Merge branch 'master' into 608

This commit is contained in:
RongHong 2011-08-05 10:59:40 +08:00
commit 5f08bb24fe
112 changed files with 3675 additions and 1122 deletions

View File

@ -24,8 +24,8 @@ function btnTouchMove(e)
local v = e[1]
local pointMove = v:locationInView(v:view())
pointMove = cocos2d.CCDirector:sharedDirector():convertToGL(pointMove)
local positionCurrent = layerFarm.__CCNode__:getPosition()
layerFarm.__CCNode__:setPosition(cocos2d.CCPoint(positionCurrent.x + pointMove.x - pointBegin.x, positionCurrent.y + pointMove.y - pointBegin.y))
local positionCurrent = layerFarm:getPosition()
layerFarm:setPosition(cocos2d.CCPoint(positionCurrent.x + pointMove.x - pointBegin.x, positionCurrent.y + pointMove.y - pointBegin.y))
pointBegin = pointMove
end
end

View File

@ -8,8 +8,6 @@
using namespace cocos2d;
#define IMG_PATH "assets"
extern "C"
{
@ -23,8 +21,6 @@ void Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeInit(JNIEnv* env, jobject thi
view->create(480, 320);
cocos2d::CCDirector::sharedDirector()->setOpenGLView(view);
CCFileUtils::setRelativePath(IMG_PATH);
AppDelegate *pAppDelegate = new AppDelegate();
cocos2d::CCApplication::sharedApplication().run();
}

View File

@ -83,6 +83,9 @@ public class Cocos2dxActivity extends Activity{
backgroundMusicPlayer = new Cocos2dxMusic(this);
soundPlayer = new Cocos2dxSound(this);
// init bitmap context
Cocos2dxBitmap.setContext(this);
handler = new Handler(){
public void handleMessage(Message msg){
switch(msg.what){

View File

@ -4,6 +4,7 @@ import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.LinkedList;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
@ -11,6 +12,7 @@ import android.graphics.Paint;
import android.graphics.Typeface;
import android.graphics.Paint.Align;
import android.graphics.Paint.FontMetricsInt;
import android.util.Log;
public class Cocos2dxBitmap{
/*
@ -21,6 +23,12 @@ public class Cocos2dxBitmap{
private static final int ALIGNLEFT = 0x31;
private static final int ALIGNRIGHT = 0x32;
private static Context context;
public static void setContext(Context context){
Cocos2dxBitmap.context = context;
}
/*
* @width: the width to draw, it can be 0
* @height: the height to draw, it can be 0
@ -31,7 +39,7 @@ public class Cocos2dxBitmap{
content = refactorString(content);
Paint paint = newPaint(fontName, fontSize, alignment);
TextProperty textProperty = getTextWidthAndHeight(content, paint, width, height);
TextProperty textProperty = computeTextProperty(content, paint, width, height);
// Draw text to bitmap
Bitmap bitmap = Bitmap.createBitmap(textProperty.maxWidth,
@ -95,7 +103,7 @@ public class Cocos2dxBitmap{
}
}
private static TextProperty getTextWidthAndHeight(String content, Paint paint,
private static TextProperty computeTextProperty(String content, Paint paint,
int maxWidth, int maxHeight){
FontMetricsInt fm = paint.getFontMetricsInt();
int h = (int)Math.ceil(fm.descent - fm.ascent);
@ -117,8 +125,7 @@ public class Cocos2dxBitmap{
maxContentWidth = temp;
}
}
}
}
return new TextProperty(maxContentWidth, h, lines);
}
@ -231,10 +238,10 @@ public class Cocos2dxBitmap{
}
/*
* Add the last char
* Add the last chars
*/
if (start == charLength - 1){
strList.add(content.substring(charLength-1));
if (start < charLength){
strList.add(content.substring(start));
}
return strList;
@ -243,9 +250,29 @@ public class Cocos2dxBitmap{
private static Paint newPaint(String fontName, int fontSize, int alignment){
Paint paint = new Paint();
paint.setColor(Color.WHITE);
paint.setTextSize(fontSize);
paint.setTypeface(Typeface.create(fontName, Typeface.NORMAL));
paint.setAntiAlias(true);
paint.setTextSize(fontSize);
paint.setAntiAlias(true);
/*
* Set type face for paint, now it support .ttf file.
*/
if (fontName.endsWith(".ttf")){
try {
Typeface typeFace = Typeface.createFromAsset(context.getAssets(), fontName);
paint.setTypeface(typeFace);
} catch (Exception e){
Log.e("Cocos2dxBitmap",
"error to create ttf type face: " + fontName);
/*
* The file may not find, use system font
*/
paint.setTypeface(Typeface.create(fontName, Typeface.NORMAL));
}
}
else {
paint.setTypeface(Typeface.create(fontName, Typeface.NORMAL));
}
switch (alignment){
case ALIGNCENTER:

View File

@ -40,6 +40,9 @@ bool AppDelegate::initInstance()
// OpenGLView initialized in HelloWorld/android/jni/helloworld/main.cpp
// the default setting is to create a fullscreen view
// if you want to use auto-scale, please enable view->create(320,480) in main.cpp
// if the resources under '/sdcard" or other writeable path, set it.
// warning: the audio source should in assets/
// cocos2d::CCFileUtils::setResourcePath("/sdcard");
#endif // CC_PLATFORM_ANDROID

View File

@ -8,8 +8,6 @@
using namespace cocos2d;
#define IMG_PATH "assets"
extern "C"
{
@ -23,8 +21,6 @@ void Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeInit(JNIEnv* env, jobject thi
// view->create(480, 320);
cocos2d::CCDirector::sharedDirector()->setOpenGLView(view);
CCFileUtils::setRelativePath(IMG_PATH);
AppDelegate *pAppDelegate = new AppDelegate();
cocos2d::CCApplication::sharedApplication().run();
}

View File

@ -83,6 +83,9 @@ public class Cocos2dxActivity extends Activity{
backgroundMusicPlayer = new Cocos2dxMusic(this);
soundPlayer = new Cocos2dxSound(this);
// init bitmap context
Cocos2dxBitmap.setContext(this);
handler = new Handler(){
public void handleMessage(Message msg){
switch(msg.what){

View File

@ -4,6 +4,7 @@ import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.LinkedList;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
@ -11,6 +12,7 @@ import android.graphics.Paint;
import android.graphics.Typeface;
import android.graphics.Paint.Align;
import android.graphics.Paint.FontMetricsInt;
import android.util.Log;
public class Cocos2dxBitmap{
/*
@ -21,6 +23,12 @@ public class Cocos2dxBitmap{
private static final int ALIGNLEFT = 0x31;
private static final int ALIGNRIGHT = 0x32;
private static Context context;
public static void setContext(Context context){
Cocos2dxBitmap.context = context;
}
/*
* @width: the width to draw, it can be 0
* @height: the height to draw, it can be 0
@ -31,7 +39,7 @@ public class Cocos2dxBitmap{
content = refactorString(content);
Paint paint = newPaint(fontName, fontSize, alignment);
TextProperty textProperty = getTextWidthAndHeight(content, paint, width, height);
TextProperty textProperty = computeTextProperty(content, paint, width, height);
// Draw text to bitmap
Bitmap bitmap = Bitmap.createBitmap(textProperty.maxWidth,
@ -95,7 +103,7 @@ public class Cocos2dxBitmap{
}
}
private static TextProperty getTextWidthAndHeight(String content, Paint paint,
private static TextProperty computeTextProperty(String content, Paint paint,
int maxWidth, int maxHeight){
FontMetricsInt fm = paint.getFontMetricsInt();
int h = (int)Math.ceil(fm.descent - fm.ascent);
@ -117,8 +125,7 @@ public class Cocos2dxBitmap{
maxContentWidth = temp;
}
}
}
}
return new TextProperty(maxContentWidth, h, lines);
}
@ -231,10 +238,10 @@ public class Cocos2dxBitmap{
}
/*
* Add the last char
* Add the last chars
*/
if (start == charLength - 1){
strList.add(content.substring(charLength-1));
if (start < charLength){
strList.add(content.substring(start));
}
return strList;
@ -243,9 +250,29 @@ public class Cocos2dxBitmap{
private static Paint newPaint(String fontName, int fontSize, int alignment){
Paint paint = new Paint();
paint.setColor(Color.WHITE);
paint.setTextSize(fontSize);
paint.setTypeface(Typeface.create(fontName, Typeface.NORMAL));
paint.setAntiAlias(true);
paint.setTextSize(fontSize);
paint.setAntiAlias(true);
/*
* Set type face for paint, now it support .ttf file.
*/
if (fontName.endsWith(".ttf")){
try {
Typeface typeFace = Typeface.createFromAsset(context.getAssets(), fontName);
paint.setTypeface(typeFace);
} catch (Exception e){
Log.e("Cocos2dxBitmap",
"error to create ttf type face: " + fontName);
/*
* The file may not find, use system font
*/
paint.setTypeface(Typeface.create(fontName, Typeface.NORMAL));
}
}
else {
paint.setTypeface(Typeface.create(fontName, Typeface.NORMAL));
}
switch (alignment){
case ALIGNCENTER:

View File

@ -1 +1 @@
9fb28c61f00c78e9def984ba0b22cf9fae814b94
a94593d95f2fff9766c611a35a6593a87d490698

View File

@ -25,7 +25,7 @@ echo.
call %VSVARS%
if %VC_VER%==90 (
vcbuild cocos2d-win32.vc2008.sln $ALL
vcbuild /MP /M10 cocos2d-win32.vc2008.sln $ALL
) else if %VC_VER%==100 (
msbuild cocos2d-win32.vc2010.sln /p:Configuration="Debug"
msbuild cocos2d-win32.vc2010.sln /p:Configuration="Release"

View File

@ -102,7 +102,7 @@ bool CCDirector::init(void)
// FPS
m_bDisplayFPS = false;
m_nFrames = 0;
m_uTotalFrames = m_uFrames = 0;
m_pszFPS = new char[10];
m_pLastUpdate = new struct cc_timeval();
@ -227,6 +227,8 @@ void CCDirector::drawScene(void)
glPopMatrix();
m_uTotalFrames++;
// swap buffers
if (m_pobOpenGLView)
{
@ -669,13 +671,13 @@ void CCDirector::resume(void)
// updates the FPS every frame
void CCDirector::showFPS(void)
{
m_nFrames++;
m_uFrames++;
m_fAccumDt += m_fDeltaTime;
if (m_fAccumDt > CC_DIRECTOR_FPS_INTERVAL)
{
m_fFrameRate = m_nFrames / m_fAccumDt;
m_nFrames = 0;
m_fFrameRate = m_uFrames / m_fAccumDt;
m_uFrames = 0;
m_fAccumDt = 0;
sprintf(m_pszFPS, "%.1f", m_fFrameRate);

View File

@ -75,7 +75,7 @@ typedef struct _hashScriptFuncEntry
{
CCTimer *timer;
bool paused;
string *funcName;
const char *funcName;
UT_hash_handle hh;
} tHashScriptFuncEntry;
@ -306,7 +306,7 @@ void CCScheduler::scheduleScriptFunc(const char *pszFuncName, ccTime fInterval,
if (! pElement)
{
pElement = (tHashScriptFuncEntry *)calloc(sizeof(*pElement), 1);
pElement->funcName = new string(pszFuncName);
pElement->funcName = pszFuncName;
pElement->timer = new CCTimer();
pElement->timer->initWithScriptFuncName(pszFuncName, fInterval);
pElement->paused = bPaused;
@ -373,23 +373,22 @@ void CCScheduler::unscheduleSelector(SEL_SCHEDULE pfnSelector, SelectorProtocol
}
}
void CCScheduler::unscheduleScriptFunc(const char *pfzFuncName)
void CCScheduler::unscheduleScriptFunc(const char *pszFuncName)
{
// explicity handle nil arguments when removing an object
if (pfzFuncName == 0)
if (pszFuncName == 0)
{
return;
}
tHashScriptFuncEntry *pElement = NULL;
HASH_FIND_INT(m_pHashForScriptFunctions, &pfzFuncName, pElement);
HASH_FIND_INT(m_pHashForScriptFunctions, &pszFuncName, pElement);
if (pElement)
{
pElement->timer->release();
delete pElement->funcName;
HASH_DEL(m_pHashForSelectors, pElement);
HASH_DEL(m_pHashForScriptFunctions, pElement);
free(pElement);
}
}

View File

@ -2180,8 +2180,7 @@ CCActionInterval* CCAnimate::reverse(void)
}
}
CCAnimation *pNewAnim = CCAnimation::animationWithName(m_pAnimation->getName(),
m_pAnimation->getDelay(), pNewArray);
CCAnimation *pNewAnim = CCAnimation::animationWithFrames(pNewArray, m_pAnimation->getDelay());
pNewArray->release();

View File

@ -166,7 +166,7 @@ void CCNode::setZOrder(int z)
/// ertexZ getter
float CCNode::getVertexZ()
{
return m_fVertexZ;
return m_fVertexZ / CC_CONTENT_SCALE_FACTOR();
}
@ -852,13 +852,13 @@ void CCNode::transform()
if (m_fRotation != 0.0f )
glRotatef( -m_fRotation, 0.0f, 0.0f, 1.0f );
// skew
if ( (skewX_ != 0.0f) || (skewY_ != 0.0f) )
{
CCAffineTransform skewMatrix = CCAffineTransformMake( 1.0f, tanf(CC_DEGREES_TO_RADIANS(skewY_)), tanf(CC_DEGREES_TO_RADIANS(skewX_)), 1.0f, 0.0f, 0.0f );
GLfloat glMatrix[16];
CCAffineToGL(&skewMatrix, glMatrix);
glMultMatrixf(glMatrix);
// skew
if ( (skewX_ != 0.0f) || (skewY_ != 0.0f) )
{
CCAffineTransform skewMatrix = CCAffineTransformMake( 1.0f, tanf(CC_DEGREES_TO_RADIANS(skewY_)), tanf(CC_DEGREES_TO_RADIANS(skewX_)), 1.0f, 0.0f, 0.0f );
GLfloat glMatrix[16];
CCAffineToGL(&skewMatrix, glMatrix);
glMultMatrixf(glMatrix);
}
// scale
@ -1022,12 +1022,12 @@ CCAffineTransform CCNode::nodeToParentTransform(void)
m_tTransform = CCAffineTransformRotate(m_tTransform, -CC_DEGREES_TO_RADIANS(m_fRotation));
}
if(m_fSkewX != 0 || m_fSkewY != 0)
{
// create a skewed coordinate system
CCAffineTransform skew = CCAffineTransformMake(1.0f, tanf(CC_DEGREES_TO_RADIANS(m_fSkewY)), tanf(CC_DEGREES_TO_RADIANS(m_fSkewX)), 1.0f, 0.0f, 0.0f);
// apply the skew to the transform
m_tTransform = CCAffineTransformConcat(skew, m_tTransform);
if(m_fSkewX != 0 || m_fSkewY != 0)
{
// create a skewed coordinate system
CCAffineTransform skew = CCAffineTransformMake(1.0f, tanf(CC_DEGREES_TO_RADIANS(m_fSkewY)), tanf(CC_DEGREES_TO_RADIANS(m_fSkewX)), 1.0f, 0.0f, 0.0f);
// apply the skew to the transform
m_tTransform = CCAffineTransformConcat(skew, m_tTransform);
}
if(! (m_fScaleX == 1 && m_fScaleY == 1))

View File

@ -29,7 +29,7 @@ namespace cocos2d {
const char* cocos2dVersion()
{
return "cocos2d v1.0.0";
return "cocos2d v1.0.1";
}
}//namespace cocos2d

View File

@ -86,28 +86,6 @@ namespace cocos2d {
*/
bool initWithFrames(CCMutableArray<CCSpriteFrame*> *pFrames, float delay);
/** Initializes a CCAnimation with a name
@since v0.99.3
@deprecated Will be removed in 1.0.1. Use "init" instead.
*/
bool initWithName(const char *pszName);
/** Initializes a CCAnimation with a name and frames
@since v0.99.3
@deprecated Will be removed in 1.0.1. Use "initWithFrames" instead.
*/
bool initWithName(const char *pszName, CCMutableArray<CCSpriteFrame*> *pFrames);
/** Initializes a CCAnimation with a name and delay between frames.
@deprecated Will be removed in 1.0.1. Use "initWithFrames:nil delay:delay" instead.
*/
bool initWithName(const char *pszName, float fDelay);
/** Initializes a CCAnimation with a name, delay and an array of CCSpriteFrames.
@deprecated Will be removed in 1.0.1. Use "initWithFrames:frames delay:delay" instead.
*/
bool initWithName(const char *pszName, float fDelay, CCMutableArray<CCSpriteFrame*> *pFrames);
/** adds a frame to a CCAnimation */
void addFrame(CCSpriteFrame *pFrame);
@ -138,24 +116,6 @@ namespace cocos2d {
@since v0.99.5
*/
static CCAnimation* animationWithFrames(CCMutableArray<CCSpriteFrame*> *frames, float delay);
/** Creates a CCAnimation with a name
@since v0.99.3
@deprecated Will be removed in 1.0.1. Use "animation" instead.
*/
static CCAnimation* animationWithName(const char *pszName);
/** Creates a CCAnimation with a name and frames
@since v0.99.3
@deprecated Will be removed in 1.0.1. Use "animationWithFrames" instead.
*/
static CCAnimation* animationWithName(const char *pszName, CCMutableArray<CCSpriteFrame*> *pFrames);
/** Creates a CCAnimation with a name and delay between frames. */
static CCAnimation* animationWithName(const char *pszName, float fDelay);
/** Creates a CCAnimation with a name, delay and an array of CCSpriteFrames. */
static CCAnimation* animationWithName(const char *pszName, float fDelay, CCMutableArray<CCSpriteFrame*> *pFrames);
};
} // end of name sapce cocos2d

View File

@ -404,7 +404,6 @@ protected:
bool m_bLandscape;
bool m_bDisplayFPS;
int m_nFrames;
ccTime m_fAccumDt;
ccTime m_fFrameRate;
#if CC_DIRECTOR_FAST_FPS
@ -415,6 +414,7 @@ protected:
bool m_bPaused;
/* How many frames were called since the director started */
unsigned int m_uTotalFrames;
unsigned int m_uFrames;
/* The running scene */

View File

@ -52,12 +52,6 @@ namespace cocos2d{
/** creates the CCLabelAtlas with a string, a char map file(the atlas), the width and height of each element and the starting char of the atlas */
static CCLabelAtlas * labelWithString(const char *label, const char *charMapFile, unsigned int itemWidth, unsigned int itemHeight, unsigned char startCharMap);
/** creates the CCLabelAtlas with a string, a char map file(the atlas), the width and height of each element in points and the starting char of the atlas.
@deprecated Will be removed in 1.0.1. Use "labelWithString:" instead
*/
static CCLabelAtlas * labelAtlasWithString(const char *label, const char *charMapFile, unsigned int itemWidth, unsigned int itemHeight, unsigned char startCharMap);
/** initializes the CCLabelAtlas with a string, a char map file(the atlas), the width and height of each element and the starting char of the atlas */
bool initWithString(const char *label, const char *charMapFile, unsigned int itemWidth, unsigned int itemHeight, unsigned char startCharMap);
// super methods

View File

@ -171,12 +171,6 @@ namespace cocos2d{
/** creates a bitmap font altas with an initial string and the FNT file */
static CCLabelBMFont * labelWithString(const char *str, const char *fntFile);
/** creates a BMFont label with an initial string and the FNT file
@deprecated Will be removed in 1.0.1. Use "labelWithString" instead.
@since v0.99.5
*/
static CCLabelBMFont * bitmapFontAtlasWithString(const char *str, const char *fntFile);
/** init a bitmap font altas with an initial string and the FNT file */
bool initWithString(const char *str, const char *fntFile);
/** updates the font chars based on the string to render */
@ -203,14 +197,6 @@ namespace cocos2d{
/** Purges the FNT config cache
*/
CC_DLL void FNTConfigRemoveCache( void );
/** CCBitmapFontAtlas
@deprecated Use CCLabelBMFont instead. Will be removed 1.0.1
*/
class CCBitmapFontAtlas : public CCLabelBMFont
{
};
}// namespace cocos2d
#endif //__CCBITMAP_FONT_ATLAS_H__

View File

@ -121,6 +121,25 @@ return NULL; \
} \
};
#define LAYER_NODE_FUNC_PARAM(layer,__PARAMTYPE__,__PARAM__) \
static layer* node(__PARAMTYPE__ __PARAM__) \
{ \
layer *pRet = new layer(); \
if (pRet && pRet->init(__PARAM__)) \
{ \
pRet->autorelease(); \
return pRet; \
} \
else \
{ \
delete pRet; \
pRet = NULL; \
return NULL; \
} \
};
//
// CCLayerColor
//
@ -177,18 +196,6 @@ protected:
virtual void updateColor();
};
/** CCColorLayer
It is the same as CCLayerColor.
@deprecated Use CCLayerColor instead. This class will be removed in v1.0.1
*/
class CC_DLL CCColorLayer : public CCLayerColor
{
public:
static CCColorLayer * layerWithColorWidthHeight(ccColor4B color, GLfloat width, GLfloat height);
static CCColorLayer * layerWithColor(ccColor4B color);
};
//
// CCLayerGradient
//
@ -283,14 +290,6 @@ public:
LAYER_NODE_FUNC(CCLayerMultiplex);
};
/** CCMultiplexLayer
It is the same as CCLayerMultiplex.
@deprecated Use CCLayerMultiplex instead. This class will be removed in v1.0.1
*/
class CCMultiplexLayer : public CCLayerMultiplex
{
};
}//namespace cocos2d
#endif // __CCLAYER_H__

View File

@ -55,8 +55,12 @@ namespace cocos2d{
, m_pSelectedItem(NULL)
{}
virtual ~CCMenu(){}
/** creates a CCMenu with it's items */
static CCMenu* menuWithItems(CCMenuItem* item, ...);
/** creates an empty CCMenu */
static CCMenu* node();
/** creates a CCMenu with it's items */
static CCMenu* menuWithItems(CCMenuItem* item, ...);
/** creates a CCMenu with it's item, then use addChild() to add
* other items. It is used for script, it can't init with undetermined
@ -64,6 +68,8 @@ namespace cocos2d{
*/
static CCMenu*menuWithItem(CCMenuItem* item);
/** initializes an empty CCMenu */
bool init();
/** initializes a CCMenu with it's items */
bool initWithItems(CCMenuItem* item, va_list args);
@ -118,10 +124,8 @@ namespace cocos2d{
virtual CCRGBAProtocol* convertToRGBAProtocol() { return (CCRGBAProtocol*)this; }
private:
CCMenuItem* itemForTouch(CCTouch * touch);
protected:
CCMenuItem* itemForTouch(CCTouch * touch);
tCCMenuState m_eState;
GLubyte m_cOpacity;
CCMenuItem *m_pSelectedItem;
@ -129,4 +133,4 @@ namespace cocos2d{
};
}
#endif//__CCMENU_H_
#endif//__CCMENU_H_

View File

@ -90,14 +90,29 @@ public:
void clear(float r, float g, float b, float a);
/** saves the texture into a file */
bool saveBuffer(const char *name);
/** saves the texture into a file. The format can be JPG or PNG */
bool saveBuffer(const char *name, int format);
// para szFilePath the absolute path to save
// para x,y the lower left corner coordinates of the buffer to save
// pare nWidth,nHeight the size of the buffer to save
// when nWidth = 0 and nHeight = 0, the image size to save equals to buffer texture size
bool saveBuffer(const char *szFilePath, int x = 0, int y = 0, int nWidth = 0, int nHeight = 0);
/** saves the texture into a file.
// para name the file name to save
// para format the image format to save, here it supports kCCImageFormatPNG and kCCImageFormatJPG */
// para x,y the lower left corner coordinates of the buffer to save
// pare nWidth,nHeight the size of the buffer to save
// when nWidth = 0 and nHeight = 0, the image size to save equals to buffer texture size
bool saveBuffer(int format, const char *name, int x = 0, int y = 0, int nWidth = 0, int nHeight = 0);
/* get buffer as UIImage, can only save a render buffer which has a RGBA8888 pixel format */
CCData *getUIImageAsDataFromBuffer(int format);
bool getUIImageFromBuffer(CCImage *pImage);
/** save the buffer data to a CCImage */
// para pImage the CCImage to save
// para x,y the lower left corner coordinates of the buffer to save
// pare nWidth,nHeight the size of the buffer to save
// when nWidth = 0 and nHeight = 0, the image size to save equals to buffer texture size
bool getUIImageFromBuffer(CCImage *pImage, int x = 0, int y = 0, int nWidth = 0, int nHeight = 0);
protected:
GLuint m_uFBO;

View File

@ -1,82 +1,99 @@
/****************************************************************************
Copyright (c) 2010-2011 cocos2d-x.org
Copyright (c) 2008-2010 Ricardo Quesada
Copyright (c) 2011 Zynga 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.
****************************************************************************/
#ifndef __CCSCENE_H__
#define __CCSCENE_H__
#include "CCNode.h"
namespace cocos2d {
typedef enum
{
ccNormalScene = 1 << 0,
ccTransitionScene = 1 << 1,
} ccSceneFlag;
/** @brief CCScene is a subclass of CCNode that is used only as an abstract concept.
CCScene an CCNode are almost identical with the difference that CCScene has it's
anchor point (by default) at the center of the screen.
For the moment CCScene has no other logic than that, but in future releases it might have
additional logic.
It is a good practice to use and CCScene as the parent of all your nodes.
*/
class CC_DLL CCScene : public CCNode
{
public:
CCScene();
virtual ~CCScene();
bool init();
static CCScene *node(void);
inline ccSceneFlag getSceneType(void) { return m_eSceneType; }
protected:
ccSceneFlag m_eSceneType;
};
}//namespace cocos2d
// for the subclass of CCScene, each has to implement the static "node" method
#define SCENE_NODE_FUNC(scene) \
static scene* node() \
{ \
scene *pRet = new scene(); \
if (pRet && pRet->init()) \
{ \
pRet->autorelease(); \
return pRet; \
} \
else \
{ \
delete pRet; \
pRet = NULL; \
return NULL; \
} \
};
#endif // __CCSCENE_H__
/****************************************************************************
Copyright (c) 2010-2011 cocos2d-x.org
Copyright (c) 2008-2010 Ricardo Quesada
Copyright (c) 2011 Zynga 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.
****************************************************************************/
#ifndef __CCSCENE_H__
#define __CCSCENE_H__
#include "CCNode.h"
namespace cocos2d {
typedef enum
{
ccNormalScene = 1 << 0,
ccTransitionScene = 1 << 1,
} ccSceneFlag;
/** @brief CCScene is a subclass of CCNode that is used only as an abstract concept.
CCScene an CCNode are almost identical with the difference that CCScene has it's
anchor point (by default) at the center of the screen.
For the moment CCScene has no other logic than that, but in future releases it might have
additional logic.
It is a good practice to use and CCScene as the parent of all your nodes.
*/
class CC_DLL CCScene : public CCNode
{
public:
CCScene();
virtual ~CCScene();
bool init();
static CCScene *node(void);
inline ccSceneFlag getSceneType(void) { return m_eSceneType; }
protected:
ccSceneFlag m_eSceneType;
};
}//namespace cocos2d
// for the subclass of CCScene, each has to implement the static "node" method
#define SCENE_NODE_FUNC(scene) \
static scene* node() \
{ \
scene *pRet = new scene(); \
if (pRet && pRet->init()) \
{ \
pRet->autorelease(); \
return pRet; \
} \
else \
{ \
delete pRet; \
pRet = NULL; \
return NULL; \
} \
};
#define SCENE_FUNC_PARAM(__TYPE__,__PARAMTYPE__,__PARAM__) \
static cocos2d::CCScene* node(__PARAMTYPE__ __PARAM__) \
{ \
cocos2d::CCScene * scene = NULL; \
do \
{ \
scene = cocos2d::CCScene::node(); \
CC_BREAK_IF(! scene); \
__TYPE__ *layer = __TYPE__::node(__PARAM__); \
CC_BREAK_IF(! layer); \
scene->addChild(layer); \
} while (0); \
return scene; \
};
#endif // __CCSCENE_H__

View File

@ -143,7 +143,7 @@ public:
void unscheduleSelector(SEL_SCHEDULE pfnSelector, SelectorProtocol *pTarget);
/** Unschedule the script function
*/
void unscheduleScriptFunc(const char *pfzFuncName);
void unscheduleScriptFunc(const char *pszFuncName);
/** Unschedules the update selector for a given target
@since v0.99.3

View File

@ -327,25 +327,8 @@ public:
/** returns the current displayed frame. */
CCSpriteFrame* displayedFrame(void);
/** adds an Animation to the Sprite.
@deprecated Use CCAnimationCache instead. Will be removed in 1.0.1
*/
void addAnimation(CCAnimation *pAnimation);
/** returns an Animation given it's name.
@deprecated Use CCAnimationCache instead. Will be removed in 1.0.1
*/
CCAnimation* animationByName(const char *pszAnimationName);
// Animation
/** changes the display frame based on an animation and an index.
@deprecated Will be removed in 1.0.1. Use setDisplayFrameWithAnimationName:index instead
*/
void setDisplayFrame(const char *pszAnimationName, int nFrameIndex);
/** changes the display frame with animation name and index.
The animation name will be get from the CCAnimationCache
@since v0.99.5
@ -355,7 +338,6 @@ public:
protected:
void updateTextureCoords(CCRect rect);
void updateBlendFunc(void);
void initAnimationDictionary(void);
void getTransformValues(struct transformValues_ *tv); // optimization
protected:
@ -404,9 +386,6 @@ protected:
// image is flipped
bool m_bFlipX;
bool m_bFlipY;
// Animations that belong to the sprite
CCMutableDictionary<std::string, CCAnimation*> *m_pAnimations;
};
}//namespace cocos2d

View File

@ -78,27 +78,23 @@ namespace cocos2d
The capacity will be increased in 33% in runtime if it run out of space.
*/
static CCSpriteBatchNode* batchNodeWithTexture(CCTexture2D *tex);
static CCSpriteBatchNode* spriteSheetWithTexture(CCTexture2D *tex); // deprecated
/** creates a CCSpriteBatchNode with a texture2d and capacity of children.
The capacity will be increased in 33% in runtime if it run out of space.
*/
static CCSpriteBatchNode* batchNodeWithTexture(CCTexture2D* tex, unsigned int capacity);
static CCSpriteBatchNode* spriteSheetWithTexture(CCTexture2D *tex, unsigned int capacity); // deprecated
/** creates a CCSpriteBatchNode with a file image (.png, .jpeg, .pvr, etc) with a default capacity of 29 children.
The capacity will be increased in 33% in runtime if it run out of space.
The file will be loaded using the TextureMgr.
*/
static CCSpriteBatchNode* batchNodeWithFile(const char* fileImage);
static CCSpriteBatchNode* spriteSheetWithFile(const char* fileImage); // deprecated
/** creates a CCSpriteBatchNode with a file image (.png, .jpeg, .pvr, etc) and capacity of children.
The capacity will be increased in 33% in runtime if it run out of space.
The file will be loaded using the TextureMgr.
*/
static CCSpriteBatchNode* batchNodeWithFile(const char* fileImage, unsigned int capacity);
static CCSpriteBatchNode* spriteSheetWithFile(const char* fileImage, unsigned int capacity); // deprecated
/** initializes a CCSpriteBatchNode with a texture2d and capacity of children.
The capacity will be increased in 33% in runtime if it run out of space.
@ -112,25 +108,6 @@ namespace cocos2d
void increaseAtlasCapacity();
/** creates an sprite with a rect in the CCSpriteBatchNode.
It's the same as:
- create an standard CCSsprite
- set the usingSpriteSheet = YES
- set the textureAtlas to the same texture Atlas as the CCSpriteBatchNode
@deprecated Use [CCSprite spriteWithBatchNode:rect:] instead;
*/
CCSprite* createSpriteWithRect(CCRect rect);
/** initializes a previously created sprite with a rect. This sprite will have the same texture as the CCSpriteBatchNode.
It's the same as:
- initialize an standard CCSsprite
- set the usingBatchNode = YES
- set the textureAtlas to the same texture Atlas as the CCSpriteBatchNode
@since v0.99.0
@deprecated Use [CCSprite initWithBatchNode:rect:] instead;
*/
void initSprite(CCSprite *sprite, CCRect rect);
/** removes a child given a certain index. It will also cleanup the running actions depending on the cleanup parameter.
@warning Removing a child from a CCSpriteBatchNode is very slow
*/

View File

@ -117,13 +117,6 @@ public:
*/
CCSpriteFrame* spriteFrameByName(const char *pszName);
/** Creates an sprite with the name of an sprite frame.
The created sprite will contain the texture, rect and offset of the sprite frame.
It returns an autorelease object.
@deprecated use CCSprite::spriteWithSpriteFrameName(name). This method will be removed on final v0.9
*/
CCSprite* createSpriteWithFrameName(const char *pszName);
public:
/** Returns the shared instance of the Sprite Frame cache */
static CCSpriteFrameCache* sharedSpriteFrameCache(void);

View File

@ -128,11 +128,6 @@ namespace cocos2d {
/** return the TMXObjectGroup for the secific group */
CCTMXObjectGroup* objectGroupNamed(const char *groupName);
/** return the TMXObjectGroup for the secific group
@deprecated Use map#objectGroupNamed instead
*/
CCTMXObjectGroup* groupNamed(const char *groupName);
/** return the value for the specific property name */
CCString *propertyNamed(const char *propertyName);

View File

@ -142,13 +142,13 @@ public:
public:
/** singleton of the CCTouchDispatcher */
static CCTouchDispatcher* sharedDispatcher();
CCTouchHandler* findHandler(CCTouchDelegate *pDelegate);
protected:
void forceRemoveDelegate(CCTouchDelegate *pDelegate);
void forceAddHandler(CCTouchHandler *pHandler, CCMutableArray<CCTouchHandler*> *pArray);
void forceRemoveAllDelegates(void);
void rearrangeHandlers(CCMutableArray<CCTouchHandler*> *pArray);
CCTouchHandler* findHandler(CCTouchDelegate *pDelegate);
protected:
CCMutableArray<CCTouchHandler*> *m_pTargetedHandlers;

View File

@ -36,7 +36,7 @@ namespace cocos2d {
CCTouchHandler
Object than contains the delegate and priority of the event handler.
*/
class CCTouchHandler : public CCObject
class CC_DLL CCTouchHandler : public CCObject
{
public:
virtual ~CCTouchHandler(void);
@ -69,7 +69,7 @@ protected:
/** CCStandardTouchHandler
It forwardes each event to the delegate.
*/
class CCStandardTouchHandler : public CCTouchHandler
class CC_DLL CCStandardTouchHandler : public CCTouchHandler
{
public:
/** initializes a TouchHandler with a delegate and a priority */
@ -85,7 +85,7 @@ public:
Object than contains the claimed touches and if it swallos touches.
Used internally by TouchDispatcher
*/
class CCTargetedTouchHandler : public CCTouchHandler
class CC_DLL CCTargetedTouchHandler : public CCTouchHandler
{
public:
~CCTargetedTouchHandler(void);

View File

@ -38,18 +38,18 @@ public:
~CCUserDefault();
// get value methods
bool getBoolForKey(const char* pKey);
int getIntegerForKey(const char* pKey);
float getFloatForKey(const char* pKey);
double getDoubleForKey(const char* pKey);
std::string getStringForKey(const char* pKey);
bool getBoolForKey(const char* pKey, bool defaultValue = false);
int getIntegerForKey(const char* pKey, int defaultValue = 0);
float getFloatForKey(const char* pKey, float defaultValue=0.0f);
double getDoubleForKey(const char* pKey, double defaultValue=0.0);
std::string getStringForKey(const char* pKey, const std::string & defaultValue = "");
// set value methods
void setBoolForKey(const char* pKey, bool value);
void setIntegerForKey(const char* pKey, int value);
void setFloatForKey(const char* pKey, float value);
void setDoubleForKey(const char* pKey, double value);
void setStringForKey(const char* pKey, std::string value);
void setStringForKey(const char* pKey, const std::string & value);
static CCUserDefault* sharedUserDefault();
static void purgeSharedUserDefault();

View File

@ -28,6 +28,10 @@ THE SOFTWARE.
#ifndef __COCOS2D_H__
#define __COCOS2D_H__
// 0x00 HI ME LO
// 00 01 00 01
#define COCOS2D_VERSION 0x00010001
//
// all cocos2d include files
//
@ -80,6 +84,7 @@ THE SOFTWARE.
#include "CCTexturePVR.h"
#include "CCTransitionRadial.h"
#include "CCActionProgressTimer.h"
#include "CCTouchHandler.h"
#include "CCTouchDispatcher.h"
#include "CCDrawingPrimitives.h"
#include "CCScheduler.h"

View File

@ -44,11 +44,6 @@ namespace cocos2d{
return NULL;
}
CCLabelAtlas * CCLabelAtlas::labelAtlasWithString(const char *label, const char *charMapFile, unsigned int itemWidth, unsigned int itemHeight, unsigned char startCharMap)
{
return labelWithString(label, charMapFile, itemWidth, itemHeight, startCharMap);
}
bool CCLabelAtlas::initWithString(const char *label, const char *charMapFile, unsigned int itemWidth, unsigned int itemHeight, unsigned char startCharMap)
{
assert(label != NULL);

View File

@ -392,11 +392,6 @@ namespace cocos2d{
return NULL;
}
CCLabelBMFont * CCLabelBMFont::bitmapFontAtlasWithString(const char *str, const char *fntFile)
{
return labelWithString(str, fntFile);
}
bool CCLabelBMFont::initWithString(const char *theString, const char *fntFile)
{
assert(theString != NULL);
@ -411,7 +406,7 @@ namespace cocos2d{
m_tColor = ccWHITE;
m_tContentSize = CCSizeZero;
m_bIsOpacityModifyRGB = m_pobTextureAtlas->getTexture()->getHasPremultipliedAlpha();
m_tAnchorPoint = ccp(0.5f, 0.5f);
setAnchorPoint(ccp(0.5f, 0.5f));
this->setString(theString);
return true;
}

View File

@ -40,7 +40,7 @@ CCLayer::CCLayer()
,m_bIsKeypadEnabled(false)
{
m_eTouchDelegateType = ccTouchDelegateAllBit;
m_tAnchorPoint = ccp(0.5f, 0.5f);
setAnchorPoint(ccp(0.5f, 0.5f));
m_bIsRelativeAnchorPoint = false;
}
@ -469,33 +469,6 @@ void CCLayerColor::draw()
glEnable(GL_TEXTURE_2D);
}
//
// CCColorLayer
//
CCColorLayer* CCColorLayer::layerWithColorWidthHeight(ccColor4B color, GLfloat width, GLfloat height)
{
CCColorLayer * pLayer = new CCColorLayer();
if( pLayer && pLayer->initWithColorWidthHeight(color,width,height))
{
pLayer->autorelease();
return pLayer;
}
CC_SAFE_DELETE(pLayer);
return NULL;
}
CCColorLayer* CCColorLayer::layerWithColor(ccColor4B color)
{
CCColorLayer * pLayer = new CCColorLayer();
if(pLayer && pLayer->initWithColor(color))
{
pLayer->autorelease();
return pLayer;
}
CC_SAFE_DELETE(pLayer);
return NULL;
}
//
// CCLayerGradient
//

View File

@ -33,7 +33,7 @@ namespace cocos2d {
CCScene::CCScene()
{
m_bIsRelativeAnchorPoint = false;
m_tAnchorPoint = ccp(0.5f, 0.5f);
setAnchorPoint(ccp(0.5f, 0.5f));
m_eSceneType = ccNormalScene;
}

View File

@ -1,40 +1,41 @@
/****************************************************************************
Copyright (c) 2010-2011 cocos2d-x.org
Copyright (c) 2008-2010 Ricardo Quesada
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 "CCMenu.h"
#include "CCDirector.h"
#include "CCApplication.h"
#include "CCPointExtension.h"
#include "CCTouchDispatcher.h"
#include "CCTouch.h"
#include "CCStdC.h"
#include <vector>
using namespace std;
namespace cocos2d{
/****************************************************************************
Copyright (c) 2010-2011 cocos2d-x.org
Copyright (c) 2008-2010 Ricardo Quesada
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 "CCMenu.h"
#include "CCDirector.h"
#include "CCApplication.h"
#include "CCPointExtension.h"
#include "CCTouchDispatcher.h"
#include "CCTouch.h"
#include "CCStdC.h"
#include <vector>
#include <stdarg.h>
using namespace std;
namespace cocos2d{
enum
{
@ -44,6 +45,18 @@ namespace cocos2d{
//
//CCMenu
//
CCMenu* CCMenu::node()
{
CCMenu *menu = new CCMenu();
if (menu && menu->init()) {
menu->autorelease();
return menu;
}
CC_SAFE_DELETE(menu)
return 0;
}
CCMenu * CCMenu::menuWithItems(CCMenuItem* item, ...)
{
va_list args;
@ -59,23 +72,29 @@ namespace cocos2d{
CC_SAFE_DELETE(pRet)
return NULL;
}
CCMenu* CCMenu::menuWithItem(CCMenuItem* item)
{
return menuWithItems(item, NULL);
}
CCMenu* CCMenu::menuWithItem(CCMenuItem* item)
{
return menuWithItems(item, NULL);
}
bool CCMenu::init()
{
va_list args;
return initWithItems(0, args);
}
bool CCMenu::initWithItems(CCMenuItem* item, va_list args)
{
if (CCLayer::init())
{
this->m_bIsTouchEnabled = true;
if (CCLayer::init())
{
this->m_bIsTouchEnabled = true;
// menu in the center of the screen
CCSize s = CCDirector::sharedDirector()->getWinSize();
this->m_bIsRelativeAnchorPoint = false;
m_tAnchorPoint = ccp(0.5f, 0.5f);
setAnchorPoint(ccp(0.5f, 0.5f));
this->setContentSize(s);
// XXX: in v0.7, winSize should return the visible size
@ -133,14 +152,14 @@ namespace cocos2d{
void CCMenu::onExit()
{
if (m_eState == kCCMenuStateTrackingTouch)
{
m_pSelectedItem->unselected();
m_eState = kCCMenuStateWaiting;
m_pSelectedItem = NULL;
}
CCLayer::onExit();
if (m_eState == kCCMenuStateTrackingTouch)
{
m_pSelectedItem->unselected();
m_eState = kCCMenuStateWaiting;
m_pSelectedItem = NULL;
}
CCLayer::onExit();
}
//Menu - Events
@ -156,6 +175,15 @@ namespace cocos2d{
{
return false;
}
for (CCNode *c = this->m_pParent; c != NULL; c = c->getParent())
{
if (c->getIsVisible() == false)
{
return false;
}
}
m_pSelectedItem = this->itemForTouch(touch);
if (m_pSelectedItem)
{
@ -171,11 +199,11 @@ namespace cocos2d{
CC_UNUSED_PARAM(touch);
CC_UNUSED_PARAM(event);
CCAssert(m_eState == kCCMenuStateTrackingTouch, "[Menu ccTouchEnded] -- invalid state");
if (m_pSelectedItem)
{
if (m_pSelectedItem)
{
m_pSelectedItem->unselected();
m_pSelectedItem->activate();
}
}
m_eState = kCCMenuStateWaiting;
}
@ -184,10 +212,10 @@ namespace cocos2d{
CC_UNUSED_PARAM(touch);
CC_UNUSED_PARAM(event);
CCAssert(m_eState == kCCMenuStateTrackingTouch, "[Menu ccTouchCancelled] -- invalid state");
if (m_pSelectedItem)
{
if (m_pSelectedItem)
{
m_pSelectedItem->unselected();
}
}
m_eState = kCCMenuStateWaiting;
}
@ -198,15 +226,15 @@ namespace cocos2d{
CCMenuItem *currentItem = this->itemForTouch(touch);
if (currentItem != m_pSelectedItem)
{
if (m_pSelectedItem)
{
if (m_pSelectedItem)
{
m_pSelectedItem->unselected();
}
}
m_pSelectedItem = currentItem;
if (m_pSelectedItem)
{
if (m_pSelectedItem)
{
m_pSelectedItem->selected();
}
}
}
}
@ -235,11 +263,11 @@ namespace cocos2d{
CCARRAY_FOREACH(m_pChildren, pObject)
{
CCNode* pChild = (CCNode*) pObject;
if (pChild)
{
height += pChild->getContentSize().height * pChild->getScaleY() + padding;
}
}
if (pChild)
{
height += pChild->getContentSize().height * pChild->getScaleY() + padding;
}
}
}
float y = height / 2.0f;
@ -249,7 +277,7 @@ namespace cocos2d{
CCARRAY_FOREACH(m_pChildren, pObject)
{
CCNode* pChild = (CCNode*) pObject;
if (pChild)
if (pChild)
{
pChild->setPosition(ccp(0, y - pChild->getContentSize().height * pChild->getScaleY() / 2.0f));
y -= pChild->getContentSize().height * pChild->getScaleY() + padding;
@ -273,7 +301,7 @@ namespace cocos2d{
CCARRAY_FOREACH(m_pChildren, pObject)
{
CCNode* pChild = (CCNode*) pObject;
if (pChild)
if (pChild)
{
width += pChild->getContentSize().width * pChild->getScaleX() + padding;
}
@ -287,9 +315,9 @@ namespace cocos2d{
CCARRAY_FOREACH(m_pChildren, pObject)
{
CCNode* pChild = (CCNode*) pObject;
if (pChild)
if (pChild)
{
pChild->setPosition(ccp(x + pChild->getContentSize().width * pChild->getScaleX() / 2.0f, 0));
pChild->setPosition(ccp(x + pChild->getContentSize().width * pChild->getScaleX() / 2.0f, 0));
x += pChild->getContentSize().width * pChild->getScaleX() + padding;
}
}
@ -327,28 +355,28 @@ namespace cocos2d{
CCARRAY_FOREACH(m_pChildren, pObject)
{
CCNode* pChild = (CCNode*) pObject;
if (pChild)
if (pChild)
{
assert(row < rows.size());
rowColumns = rows[row];
// can not have zero columns on a row
assert(rowColumns);
float tmp = pChild->getContentSize().height;
rowHeight = (unsigned int)((rowHeight >= tmp || isnan(tmp)) ? rowHeight : tmp);
++columnsOccupied;
if (columnsOccupied >= rowColumns)
{
height += rowHeight + 5;
columnsOccupied = 0;
rowHeight = 0;
++row;
assert(row < rows.size());
rowColumns = rows[row];
// can not have zero columns on a row
assert(rowColumns);
float tmp = pChild->getContentSize().height;
rowHeight = (unsigned int)((rowHeight >= tmp || isnan(tmp)) ? rowHeight : tmp);
++columnsOccupied;
if (columnsOccupied >= rowColumns)
{
height += rowHeight + 5;
columnsOccupied = 0;
rowHeight = 0;
++row;
}
}
}
}
}
// check if too many rows/columns for available menu items
@ -369,35 +397,35 @@ namespace cocos2d{
CCARRAY_FOREACH(m_pChildren, pObject)
{
CCNode* pChild = (CCNode*) pObject;
if (pChild)
if (pChild)
{
if (rowColumns == 0)
{
rowColumns = rows[row];
w = winSize.width / (1 + rowColumns);
x = w;
}
float tmp = pChild->getContentSize().height;
rowHeight = (unsigned int)((rowHeight >= tmp || isnan(tmp)) ? rowHeight : tmp);
pChild->setPosition(ccp(x - winSize.width / 2,
y - pChild->getContentSize().height / 2));
x += w;
++columnsOccupied;
if (columnsOccupied >= rowColumns)
{
y -= rowHeight + 5;
columnsOccupied = 0;
rowColumns = 0;
rowHeight = 0;
++row;
if (rowColumns == 0)
{
rowColumns = rows[row];
w = winSize.width / (1 + rowColumns);
x = w;
}
float tmp = pChild->getContentSize().height;
rowHeight = (unsigned int)((rowHeight >= tmp || isnan(tmp)) ? rowHeight : tmp);
pChild->setPosition(ccp(x - winSize.width / 2,
y - pChild->getContentSize().height / 2));
x += w;
++columnsOccupied;
if (columnsOccupied >= rowColumns)
{
y -= rowHeight + 5;
columnsOccupied = 0;
rowColumns = 0;
rowHeight = 0;
++row;
}
}
}
}
}
}
@ -436,35 +464,35 @@ namespace cocos2d{
CCARRAY_FOREACH(m_pChildren, pObject)
{
CCNode* pChild = (CCNode*) pObject;
if (pChild)
if (pChild)
{
// check if too many menu items for the amount of rows/columns
assert(column < columns.size());
columnRows = columns[column];
// can't have zero rows on a column
assert(columnRows);
// columnWidth = fmaxf(columnWidth, [item contentSize].width);
float tmp = pChild->getContentSize().width;
columnWidth = (unsigned int)((columnWidth >= tmp || isnan(tmp)) ? columnWidth : tmp);
columnHeight += (int)(pChild->getContentSize().height + 5);
++rowsOccupied;
if (rowsOccupied >= columnRows)
{
columnWidths.push_back(columnWidth);
columnHeights.push_back(columnHeight);
width += columnWidth + 10;
rowsOccupied = 0;
columnWidth = 0;
columnHeight = -5;
++column;
// check if too many menu items for the amount of rows/columns
assert(column < columns.size());
columnRows = columns[column];
// can't have zero rows on a column
assert(columnRows);
// columnWidth = fmaxf(columnWidth, [item contentSize].width);
float tmp = pChild->getContentSize().width;
columnWidth = (unsigned int)((columnWidth >= tmp || isnan(tmp)) ? columnWidth : tmp);
columnHeight += (int)(pChild->getContentSize().height + 5);
++rowsOccupied;
if (rowsOccupied >= columnRows)
{
columnWidths.push_back(columnWidth);
columnHeights.push_back(columnHeight);
width += columnWidth + 10;
rowsOccupied = 0;
columnWidth = 0;
columnHeight = -5;
++column;
}
}
}
}
}
// check if too many rows/columns for available menu items.
@ -484,34 +512,34 @@ namespace cocos2d{
CCARRAY_FOREACH(m_pChildren, pObject)
{
CCNode* pChild = (CCNode*) pObject;
if (pChild)
if (pChild)
{
if (columnRows == 0)
{
columnRows = columns[column];
y = (float) columnHeights[column];
}
// columnWidth = fmaxf(columnWidth, [item contentSize].width);
float tmp = pChild->getContentSize().width;
columnWidth = (unsigned int)((columnWidth >= tmp || isnan(tmp)) ? columnWidth : tmp);
pChild->setPosition(ccp(x + columnWidths[column] / 2,
y - winSize.height / 2));
y -= pChild->getContentSize().height + 10;
++rowsOccupied;
if (rowsOccupied >= columnRows)
{
x += columnWidth + 5;
rowsOccupied = 0;
columnRows = 0;
columnWidth = 0;
++column;
if (columnRows == 0)
{
columnRows = columns[column];
y = (float) columnHeights[column];
}
// columnWidth = fmaxf(columnWidth, [item contentSize].width);
float tmp = pChild->getContentSize().width;
columnWidth = (unsigned int)((columnWidth >= tmp || isnan(tmp)) ? columnWidth : tmp);
pChild->setPosition(ccp(x + columnWidths[column] / 2,
y - winSize.height / 2));
y -= pChild->getContentSize().height + 10;
++rowsOccupied;
if (rowsOccupied >= columnRows)
{
x += columnWidth + 5;
rowsOccupied = 0;
columnRows = 0;
columnWidth = 0;
++column;
}
}
}
}
}
}
@ -528,15 +556,15 @@ namespace cocos2d{
CCARRAY_FOREACH(m_pChildren, pObject)
{
CCNode* pChild = (CCNode*) pObject;
if (pChild)
if (pChild)
{
CCRGBAProtocol *pRGBAProtocol = pChild->convertToRGBAProtocol();
if (pRGBAProtocol)
{
pRGBAProtocol->setOpacity(m_cOpacity);
CCRGBAProtocol *pRGBAProtocol = pChild->convertToRGBAProtocol();
if (pRGBAProtocol)
{
pRGBAProtocol->setOpacity(m_cOpacity);
}
}
}
}
}
}
@ -555,15 +583,15 @@ namespace cocos2d{
CCARRAY_FOREACH(m_pChildren, pObject)
{
CCNode* pChild = (CCNode*) pObject;
if (pChild)
if (pChild)
{
CCRGBAProtocol *pRGBAProtocol = pChild->convertToRGBAProtocol();
if (pRGBAProtocol)
{
pRGBAProtocol->setColor(m_tColor);
CCRGBAProtocol *pRGBAProtocol = pChild->convertToRGBAProtocol();
if (pRGBAProtocol)
{
pRGBAProtocol->setColor(m_tColor);
}
}
}
}
}
}
@ -583,22 +611,22 @@ namespace cocos2d{
CCARRAY_FOREACH(m_pChildren, pObject)
{
CCNode* pChild = (CCNode*) pObject;
if (pChild && pChild->getIsVisible() && ((CCMenuItem*)pChild)->getIsEnabled())
if (pChild && pChild->getIsVisible() && ((CCMenuItem*)pChild)->getIsEnabled())
{
CCPoint local = pChild->convertToNodeSpace(touchLocation);
CCRect r = ((CCMenuItem*)pChild)->rect();
r.origin = CCPointZero;
if (CCRect::CCRectContainsPoint(r, local))
{
return (CCMenuItem*)pChild;
CCPoint local = pChild->convertToNodeSpace(touchLocation);
CCRect r = ((CCMenuItem*)pChild)->rect();
r.origin = CCPointZero;
if (CCRect::CCRectContainsPoint(r, local))
{
return (CCMenuItem*)pChild;
}
}
}
}
}
return NULL;
}
}
}

View File

@ -55,7 +55,7 @@ namespace cocos2d{
}
bool CCMenuItem::initWithTarget(SelectorProtocol *rec, SEL_MenuHandler selector)
{
m_tAnchorPoint = ccp(0.5f, 0.5f);
setAnchorPoint(ccp(0.5f, 0.5f));
m_pListener = rec;
m_pfnSelector = selector;
m_bIsEnabled = true;
@ -567,7 +567,7 @@ namespace cocos2d{
m_pNormalImage->setIsVisible(true);
}
}
}
}
CCMenuItemImage * CCMenuItemImage::itemFromNormalImage(const char *normalImage, const char *selectedImage)
{

View File

@ -79,7 +79,7 @@ bool CCProgressTimer::initWithTexture(cocos2d::CCTexture2D *pTexture)
m_fPercentage = 0.f;
m_pVertexData = NULL;
m_nVertexDataCount = 0;
m_tAnchorPoint = ccp(0.5f, 0.5f);
setAnchorPoint(ccp(0.5f, 0.5f));
setContentSize(m_pSprite->getContentSize());
m_eType = kCCProgressTimerTypeRadialCCW;
@ -108,6 +108,7 @@ void CCProgressTimer::setSprite(cocos2d::CCSprite *pSprite)
CC_SAFE_RETAIN(pSprite);
CC_SAFE_RELEASE(m_pSprite);
m_pSprite = pSprite;
setContentSize(m_pSprite->getContentSize());
// Everytime we set a new sprite, we free the current vertex data
if (m_pVertexData)
@ -148,9 +149,17 @@ ccVertex2F CCProgressTimer::vertexFromTexCoord(cocos2d::CCPoint texCoord)
CCTexture2D *pTexture = m_pSprite->getTexture();
if (pTexture)
{
CCSize texSize = pTexture->getContentSizeInPixels();
tmp = ccp(texSize.width * texCoord.x / pTexture->getMaxS(),
texSize.height * (1 - (texCoord.y / pTexture->getMaxT())));
float fXMax = MAX(m_pSprite->getQuad().br.texCoords.u, m_pSprite->getQuad().bl.texCoords.u);
float fXMin = MIN(m_pSprite->getQuad().br.texCoords.u, m_pSprite->getQuad().bl.texCoords.u);
float fYMax = MAX(m_pSprite->getQuad().tl.texCoords.v, m_pSprite->getQuad().bl.texCoords.v);
float fYMin = MIN(m_pSprite->getQuad().tl.texCoords.v, m_pSprite->getQuad().bl.texCoords.v);
CCPoint tMax = ccp(fXMax, fYMax);
CCPoint tMin = ccp(fXMin, fYMin);
CCSize texSize = CCSizeMake(m_pSprite->getQuad().br.vertices.x - m_pSprite->getQuad().bl.vertices.x,
m_pSprite->getQuad().tl.vertices.y - m_pSprite->getQuad().bl.vertices.y);
tmp = ccp(texSize.width * (texCoord.x - tMin.x) / (tMax.x - tMin.x),
texSize.height * (1 - (texCoord.y - tMin.y) / (tMax.y - tMin.y)));
}
else
{
@ -215,11 +224,15 @@ void CCProgressTimer::updateProgress(void)
void CCProgressTimer::updateRadial(void)
{
// Texture Max is the actual max coordinates to deal with non-power of 2 textures
CCPoint tMax = ccp(m_pSprite->getTexture()->getMaxS(),
m_pSprite->getTexture()->getMaxT());
float fXMax = MAX(m_pSprite->getQuad().br.texCoords.u, m_pSprite->getQuad().bl.texCoords.u);
float fXMin = MIN(m_pSprite->getQuad().br.texCoords.u, m_pSprite->getQuad().bl.texCoords.u);
float fYMax = MAX(m_pSprite->getQuad().tl.texCoords.v, m_pSprite->getQuad().bl.texCoords.v);
float fYMin = MIN(m_pSprite->getQuad().tl.texCoords.v, m_pSprite->getQuad().bl.texCoords.v);
CCPoint tMax = ccp(fXMax, fYMax);
CCPoint tMin = ccp(fXMin, fYMin);
// Grab the midpoint
CCPoint midpoint = ccpCompMult(m_tAnchorPoint, tMax);
CCPoint midpoint = ccpAdd(tMin, ccpCompMult(m_tAnchorPoint, ccpSub(tMax, tMin)));
float alpha = m_fPercentage / 100.f;
@ -229,7 +242,7 @@ void CCProgressTimer::updateRadial(void)
// We find the vector to do a hit detection based on the percentage
// We know the first vector is the one @ 12 o'clock (top,mid) so we rotate
// from that by the progress angle around the midpoint pivot
CCPoint topMid = ccp(midpoint.x, 0.f);
CCPoint topMid = ccp(midpoint.x, tMin.y);
CCPoint percentagePt = ccpRotateByAngle(topMid, midpoint, angle);
int index = 0;
@ -261,8 +274,8 @@ void CCProgressTimer::updateRadial(void)
{
int pIndex = (i + (kProgressTextureCoordsCount - 1)) % kProgressTextureCoordsCount;
CCPoint edgePtA = ccpCompMult(boundaryTexCoord(i % kProgressTextureCoordsCount), tMax);
CCPoint edgePtB = ccpCompMult(boundaryTexCoord(pIndex), tMax);
CCPoint edgePtA = ccpAdd(tMin, ccpCompMult(boundaryTexCoord(i % kProgressTextureCoordsCount), ccpSub(tMax, tMin)));
CCPoint edgePtB = ccpAdd(tMin, ccpCompMult(boundaryTexCoord(pIndex), ccpSub(tMax, tMin)));
// Remember that the top edge is split in half for the 12 o'clock position
// Let's deal with that here by finding the correct endpoints
@ -342,12 +355,12 @@ void CCProgressTimer::updateRadial(void)
m_pVertexData[0].texCoords = tex2(midpoint.x, midpoint.y);
m_pVertexData[0].vertices = vertexFromTexCoord(midpoint);
m_pVertexData[1].texCoords = tex2(midpoint.x, 0.f);
m_pVertexData[1].vertices = vertexFromTexCoord(ccp(midpoint.x, 0.f));
m_pVertexData[1].texCoords = tex2(midpoint.x, tMin.y);
m_pVertexData[1].vertices = vertexFromTexCoord(ccp(midpoint.x, tMin.y));
for (int i = 0; i < index; ++i)
{
CCPoint texCoords = ccpCompMult(boundaryTexCoord(i), tMax);
CCPoint texCoords = ccpAdd(tMin, ccpCompMult(boundaryTexCoord(i), ccpSub(tMax, tMin)));
m_pVertexData[i+2].texCoords = tex2(texCoords.x, texCoords.y);
m_pVertexData[i+2].vertices = vertexFromTexCoord(texCoords);
@ -360,12 +373,12 @@ void CCProgressTimer::updateRadial(void)
{
if (m_pSprite->isFlipX())
{
m_pVertexData[i].texCoords.u = tMax.x - m_pVertexData[i].texCoords.u;
m_pVertexData[i].texCoords.u = tMin.x + tMax.x - m_pVertexData[i].texCoords.u;
}
if (m_pSprite->isFlipY())
{
m_pVertexData[i].texCoords.v = tMax.y - m_pVertexData[i].texCoords.v;
m_pVertexData[i].texCoords.v = tMin.y + tMax.y - m_pVertexData[i].texCoords.v;
}
}
}
@ -379,12 +392,12 @@ void CCProgressTimer::updateRadial(void)
{
if (m_pSprite->isFlipX())
{
m_pVertexData[m_nVertexDataCount - 1].texCoords.u = tMax.x - m_pVertexData[m_nVertexDataCount - 1].texCoords.u;
m_pVertexData[m_nVertexDataCount - 1].texCoords.u = tMin.x + tMax.x - m_pVertexData[m_nVertexDataCount - 1].texCoords.u;
}
if (m_pSprite->isFlipY())
{
m_pVertexData[m_nVertexDataCount - 1].texCoords.v = tMax.y - m_pVertexData[m_nVertexDataCount - 1].texCoords.v;
m_pVertexData[m_nVertexDataCount - 1].texCoords.v = tMin.y + tMax.y - m_pVertexData[m_nVertexDataCount - 1].texCoords.v;
}
}
}
@ -402,7 +415,12 @@ void CCProgressTimer::updateBar(void)
{
float alpha = m_fPercentage / 100.f;
CCPoint tMax = ccp(m_pSprite->getTexture()->getMaxS(), m_pSprite->getTexture()->getMaxT());
float fXMax = MAX(m_pSprite->getQuad().br.texCoords.u, m_pSprite->getQuad().bl.texCoords.u);
float fXMin = MIN(m_pSprite->getQuad().br.texCoords.u, m_pSprite->getQuad().bl.texCoords.u);
float fYMax = MAX(m_pSprite->getQuad().tl.texCoords.v, m_pSprite->getQuad().bl.texCoords.v);
float fYMin = MIN(m_pSprite->getQuad().tl.texCoords.v, m_pSprite->getQuad().bl.texCoords.v);
CCPoint tMax = ccp(fXMax, fYMax);
CCPoint tMin = ccp(fXMin, fYMin);
unsigned char vIndexes[2] = {0, 0};
unsigned char index = 0;
@ -418,23 +436,23 @@ void CCProgressTimer::updateBar(void)
if (m_eType == kCCProgressTimerTypeHorizontalBarLR)
{
m_pVertexData[vIndexes[0] = 0].texCoords = tex2(0, 0);
m_pVertexData[vIndexes[1] = 1].texCoords = tex2(0, tMax.y);
m_pVertexData[vIndexes[0] = 0].texCoords = tex2(tMin.x, tMin.y);
m_pVertexData[vIndexes[1] = 1].texCoords = tex2(tMin.x, tMax.y);
} else
if (m_eType == kCCProgressTimerTypeHorizontalBarRL)
{
m_pVertexData[vIndexes[0] = 2].texCoords = tex2(tMax.x, tMax.y);
m_pVertexData[vIndexes[1] = 3].texCoords = tex2(tMax.x, 0.f);
m_pVertexData[vIndexes[1] = 3].texCoords = tex2(tMax.x, tMin.y);
} else
if (m_eType == kCCProgressTimerTypeVerticalBarBT)
{
m_pVertexData[vIndexes[0] = 1].texCoords = tex2(0, tMax.y);
m_pVertexData[vIndexes[0] = 1].texCoords = tex2(tMin.x, tMax.y);
m_pVertexData[vIndexes[1] = 3].texCoords = tex2(tMax.x, tMax.y);
} else
if (m_eType == kCCProgressTimerTypeVerticalBarTB)
{
m_pVertexData[vIndexes[0] = 0].texCoords = tex2(0, 0);
m_pVertexData[vIndexes[1] = 2].texCoords = tex2(tMax.x, 0);
m_pVertexData[vIndexes[0] = 0].texCoords = tex2(tMin.x, tMin.y);
m_pVertexData[vIndexes[1] = 2].texCoords = tex2(tMax.x, tMin.y);
}
index = vIndexes[0];
@ -450,17 +468,17 @@ void CCProgressTimer::updateBar(void)
if (m_pSprite->isFlipX())
{
index = vIndexes[0];
m_pVertexData[index].texCoords.u = tMax.x - m_pVertexData[index].texCoords.u;
m_pVertexData[index].texCoords.u = tMin.x + tMax.x - m_pVertexData[index].texCoords.u;
index = vIndexes[1];
m_pVertexData[index].texCoords.u = tMax.x - m_pVertexData[index].texCoords.u;
m_pVertexData[index].texCoords.u = tMin.x + tMax.x - m_pVertexData[index].texCoords.u;
}
if (m_pSprite->isFlipY())
{
index = vIndexes[0];
m_pVertexData[index].texCoords.v = tMax.y - m_pVertexData[index].texCoords.v;
m_pVertexData[index].texCoords.v = tMin.y + tMax.y - m_pVertexData[index].texCoords.v;
index = vIndexes[1];
m_pVertexData[index].texCoords.v = tMax.y - m_pVertexData[index].texCoords.v;
m_pVertexData[index].texCoords.v = tMin.y + tMax.y - m_pVertexData[index].texCoords.v;
}
}
@ -469,23 +487,23 @@ void CCProgressTimer::updateBar(void)
if(m_eType == kCCProgressTimerTypeHorizontalBarLR)
{
m_pVertexData[vIndexes[0] = 3].texCoords = tex2(tMax.x*alpha, tMax.y);
m_pVertexData[vIndexes[1] = 2].texCoords = tex2(tMax.x*alpha, 0);
m_pVertexData[vIndexes[0] = 3].texCoords = tex2(tMin.x + (tMax.x - tMin.x) *alpha, tMax.y);
m_pVertexData[vIndexes[1] = 2].texCoords = tex2(tMin.x + (tMax.x - tMin.x) *alpha, tMin.y);
} else
if (m_eType == kCCProgressTimerTypeHorizontalBarRL)
{
m_pVertexData[vIndexes[0] = 1].texCoords = tex2(tMax.x*(1.f - alpha), 0);
m_pVertexData[vIndexes[1] = 0].texCoords = tex2(tMax.x*(1.f - alpha), tMax.y);
m_pVertexData[vIndexes[0] = 1].texCoords = tex2(tMin.x + (tMax.x - tMin.x) * (1.f - alpha), tMin.y);
m_pVertexData[vIndexes[1] = 0].texCoords = tex2(tMin.x + (tMax.x - tMin.x) * (1.f - alpha), tMax.y);
} else
if (m_eType == kCCProgressTimerTypeVerticalBarBT)
{
m_pVertexData[vIndexes[0] = 0].texCoords = tex2(0, tMax.y*(1.f - alpha));
m_pVertexData[vIndexes[1] = 2].texCoords = tex2(tMax.x, tMax.y*(1.f - alpha));
m_pVertexData[vIndexes[0] = 0].texCoords = tex2(tMin.x, tMin.y + (tMax.y - tMin.y) * (1.f - alpha));
m_pVertexData[vIndexes[1] = 2].texCoords = tex2(tMax.x, tMin.y + (tMax.y - tMin.y) * (1.f - alpha));
} else
if (m_eType == kCCProgressTimerTypeVerticalBarTB)
{
m_pVertexData[vIndexes[0] = 1].texCoords = tex2(0, tMax.y*alpha);
m_pVertexData[vIndexes[1] = 3].texCoords = tex2(tMax.x, tMax.y*alpha);
m_pVertexData[vIndexes[0] = 1].texCoords = tex2(tMin.x, tMin.y + (tMax.y - tMin.y) * alpha);
m_pVertexData[vIndexes[1] = 3].texCoords = tex2(tMax.x, tMin.y + (tMax.y - tMin.y) * alpha);
}
index = vIndexes[0];
@ -500,17 +518,17 @@ void CCProgressTimer::updateBar(void)
if (m_pSprite->isFlipX())
{
index = vIndexes[0];
m_pVertexData[index].texCoords.u = tMax.x - m_pVertexData[index].texCoords.u;
m_pVertexData[index].texCoords.u = tMin.x + tMax.x - m_pVertexData[index].texCoords.u;
index = vIndexes[1];
m_pVertexData[index].texCoords.u = tMax.x - m_pVertexData[index].texCoords.u;
m_pVertexData[index].texCoords.u = tMin.x + tMax.x - m_pVertexData[index].texCoords.u;
}
if (m_pSprite->isFlipY())
{
index = vIndexes[0];
m_pVertexData[index].texCoords.v = tMax.y - m_pVertexData[index].texCoords.v;
m_pVertexData[index].texCoords.v = tMin.y + tMax.y - m_pVertexData[index].texCoords.v;
index = vIndexes[1];
m_pVertexData[index].texCoords.v = tMax.y - m_pVertexData[index].texCoords.v;
m_pVertexData[index].texCoords.v = tMin.y + tMax.y - m_pVertexData[index].texCoords.v;
}
}
}

View File

@ -254,19 +254,27 @@ void CCRenderTexture::clear(float r, float g, float b, float a)
this->end();
}
bool CCRenderTexture::saveBuffer(const char *name)
{
return this->saveBuffer(name, kCCImageFormatJPG);
}
bool CCRenderTexture::saveBuffer(const char *fileName, int format)
bool CCRenderTexture::saveBuffer(const char *szFilePath, int x, int y, int nWidth, int nHeight)
{
bool bRet = false;
CCImage *pImage = new CCImage();
if (pImage != NULL && getUIImageFromBuffer(pImage, x, y, nWidth, nHeight))
{
bRet = pImage->saveToFile(szFilePath);
}
CC_SAFE_DELETE(pImage);
return bRet;
}
bool CCRenderTexture::saveBuffer(int format, const char *fileName, int x, int y, int nWidth, int nHeight)
{
bool bRet = false;
CCAssert(format == kCCImageFormatJPG || format == kCCImageFormatPNG,
"the image can only be saved as JPG or PNG format");
CCImage *pImage = new CCImage();
if (pImage != NULL && getUIImageFromBuffer(pImage))
if (pImage != NULL && getUIImageFromBuffer(pImage, x, y, nWidth, nHeight))
{
std::string fullpath = CCFileUtils::getWriteablePath() + fileName;
if (kCCImageFormatPNG == format)
@ -286,38 +294,93 @@ bool CCRenderTexture::saveBuffer(const char *fileName, int format)
return bRet;
}
/* get buffer as UIImage */
bool CCRenderTexture::getUIImageFromBuffer(CCImage *pImage)
{
if (NULL == pImage)
/* get buffer as UIImage */
bool CCRenderTexture::getUIImageFromBuffer(CCImage *pImage, int x, int y, int nWidth, int nHeight)
{
if (NULL == pImage || NULL == m_pTexture)
{
return false;
}
CCSize s = m_pTexture->getContentSizeInPixels();
int tx = (int)s.width;
int ty = (int)s.height;
if (x < 0 || x >= tx || y < 0 || y >= ty)
{
return false;
}
GLubyte * pBuffer = NULL;
}
if (nWidth < 0
|| nHeight < 0
|| (0 == nWidth && 0 != nHeight)
|| (0 == nHeight && 0 != nWidth))
{
return false;
}
// to get the image size to save
// if the saving image domain exeeds the buffer texture domain,
// it should be cut
int nSavedBufferWidth = nWidth;
int nSavedBufferHeight = nHeight;
if (0 == nWidth)
{
nSavedBufferWidth = tx;
}
if (0 == nHeight)
{
nSavedBufferHeight = ty;
}
nSavedBufferWidth = x + nSavedBufferWidth > tx ? (tx - x): nSavedBufferWidth;
nSavedBufferHeight = y + nSavedBufferHeight > ty ? (ty - y): nSavedBufferHeight;
GLubyte *pBuffer = NULL;
GLubyte *pTempData = NULL;
bool bRet = false;
do
{
CCAssert(m_ePixelFormat == kCCTexture2DPixelFormat_RGBA8888, "only RGBA8888 can be saved as image");
CCSize s = m_pTexture->getContentSizeInPixels();
int tx = (int)s.width;
int ty = (int)s.height;
CC_BREAK_IF(! (pBuffer = new GLubyte[nSavedBufferWidth * nSavedBufferHeight * 4]));
// On some machines, like Samsung i9000, Motorola Defy,
// the dimension need to be a power of 2
int nReadBufferWidth = 0;
int nReadBufferHeight = 0;
int nMaxTextureSize = 0;
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &nMaxTextureSize);
nReadBufferWidth = ccNextPOT(tx);
nReadBufferHeight = ccNextPOT(ty);
CC_BREAK_IF(0 == nReadBufferWidth || 0 == nReadBufferHeight);
CC_BREAK_IF(nReadBufferWidth > nMaxTextureSize || nReadBufferHeight > nMaxTextureSize);
CC_BREAK_IF(! (pTempData = new GLubyte[nReadBufferWidth * nReadBufferHeight * 4]));
this->begin();
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glReadPixels(0,0,nReadBufferWidth,nReadBufferHeight,GL_RGBA,GL_UNSIGNED_BYTE, pTempData);
this->end();
CC_BREAK_IF(! (pBuffer = new GLubyte[tx * ty * 4]));
// to get the actual texture data
// #640 the image read from rendertexture is upseted
for (int i = 0; i < nSavedBufferHeight; ++i)
{
memcpy(&pBuffer[i * nSavedBufferWidth * 4],
&pTempData[(y + nSavedBufferHeight - i - 1) * nReadBufferWidth * 4 + x * 4],
nSavedBufferWidth * 4);
}
this->begin();
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glReadPixels(0,0,tx,ty,GL_RGBA,GL_UNSIGNED_BYTE, pBuffer);
this->end();
bRet = pImage->initWithImageData(pBuffer, tx * ty * 4, CCImage::kFmtRawData, tx, ty, 8);
} while (0);
CC_SAFE_DELETE_ARRAY(pBuffer);
return bRet;
bRet = pImage->initWithImageData(pBuffer, nSavedBufferWidth * nSavedBufferHeight * 4, CCImage::kFmtRawData, nSavedBufferWidth, nSavedBufferHeight, 8);
} while (0);
CC_SAFE_DELETE_ARRAY(pBuffer);
CC_SAFE_DELETE_ARRAY(pTempData);
return bRet;
}

View File

@ -58,7 +58,7 @@ bool CCParticleFire::initWithTotalParticles(unsigned int numberOfParticles)
// emitter position
CCSize winSize = CCDirector::sharedDirector()->getWinSize();
this->m_tPosition = ccp(winSize.width/2, 60);
this->setPosition(ccp(winSize.width/2, 60));
this->m_tPosVar = ccp(40, 20);
// life of particles
@ -124,7 +124,7 @@ bool CCParticleFireworks::initWithTotalParticles(unsigned int numberOfParticles)
// emitter position
CCSize winSize = CCDirector::sharedDirector()->getWinSize();
m_tPosition = ccp(winSize.width/2, winSize.height/2);
this->setPosition(ccp(winSize.width/2, winSize.height/2));
// angle
this->m_fAngle= 90;
@ -200,7 +200,7 @@ bool CCParticleSun::initWithTotalParticles(unsigned int numberOfParticles)
// emitter position
CCSize winSize = CCDirector::sharedDirector()->getWinSize();
m_tPosition = ccp(winSize.width/2, winSize.height/2);
this->setPosition(ccp(winSize.width/2, winSize.height/2));
m_tPosVar = CCPointZero;
// life of particles
@ -272,7 +272,7 @@ bool CCParticleGalaxy::initWithTotalParticles(unsigned int numberOfParticles)
// emitter position
CCSize winSize = CCDirector::sharedDirector()->getWinSize();
m_tPosition = ccp(winSize.width/2, winSize.height/2);
this->setPosition(ccp(winSize.width/2, winSize.height/2));
m_tPosVar = CCPointZero;
// life of particles
@ -346,7 +346,7 @@ bool CCParticleFlower::initWithTotalParticles(unsigned int numberOfParticles)
// emitter position
CCSize winSize = CCDirector::sharedDirector()->getWinSize();
m_tPosition = ccp(winSize.width/2, winSize.height/2);
this->setPosition(ccp(winSize.width/2, winSize.height/2));
m_tPosVar = CCPointZero;
// life of particles
@ -419,7 +419,7 @@ bool CCParticleMeteor::initWithTotalParticles(unsigned int numberOfParticles)
// emitter position
CCSize winSize = CCDirector::sharedDirector()->getWinSize();
m_tPosition = ccp(winSize.width/2, winSize.height/2);
this->setPosition(ccp(winSize.width/2, winSize.height/2));
m_tPosVar = CCPointZero;
// life of particles
@ -493,7 +493,7 @@ bool CCParticleSpiral::initWithTotalParticles(unsigned int numberOfParticles)
// emitter position
CCSize winSize = CCDirector::sharedDirector()->getWinSize();
m_tPosition = ccp(winSize.width/2, winSize.height/2);
this->setPosition(ccp(winSize.width/2, winSize.height/2));
m_tPosVar = CCPointZero;
// life of particles
@ -566,7 +566,7 @@ bool CCParticleExplosion::initWithTotalParticles(unsigned int numberOfParticles)
// emitter position
CCSize winSize = CCDirector::sharedDirector()->getWinSize();
m_tPosition = ccp(winSize.width/2, winSize.height/2);
this->setPosition(ccp(winSize.width/2, winSize.height/2));
m_tPosVar = CCPointZero;
// life of particles
@ -636,7 +636,7 @@ bool CCParticleSmoke::initWithTotalParticles(unsigned int numberOfParticles)
// emitter position
CCSize winSize = CCDirector::sharedDirector()->getWinSize();
m_tPosition = ccp(winSize.width/2, 0);
this->setPosition(ccp(winSize.width/2, 0));
m_tPosVar = ccp(20, 0);
// life of particles
@ -705,7 +705,7 @@ bool CCParticleSnow::initWithTotalParticles(unsigned int numberOfParticles)
// emitter position
CCSize winSize = CCDirector::sharedDirector()->getWinSize();
m_tPosition = ccp(winSize.width/2, winSize.height + 10);
this->setPosition(ccp(winSize.width/2, winSize.height + 10));
m_tPosVar = ccp( winSize.width/2, 0 );
// angle
@ -782,7 +782,7 @@ bool CCParticleRain::initWithTotalParticles(unsigned int numberOfParticles)
// emitter position
CCSize winSize = CCDirector::sharedDirector()->getWinSize();
m_tPosition = ccp(winSize.width/2, winSize.height);
this->setPosition(ccp(winSize.width/2, winSize.height));
m_tPosVar = ccp( winSize.width/2, 0 );
// life of particles

View File

@ -199,14 +199,15 @@ bool CCParticleSystem::initWithDictionary(CCDictionary<std::string, CCObject*> *
m_fEndSizeVar = (float)atof(valueForKey("finishParticleSizeVariance", dictionary));
// position
m_tPosition.x = (float)atof(valueForKey("sourcePositionx", dictionary));
m_tPosition.y = (float)atof(valueForKey("sourcePositiony", dictionary));
m_tPosVar.x = (float)atof(valueForKey("sourcePositionVariancex", dictionary));
float x = (float)atof(valueForKey("sourcePositionx", dictionary));
float y = (float)atof(valueForKey("sourcePositiony", dictionary));
this->setPosition( ccp(x,y) );
m_tPosVar.x = (float)atof(valueForKey("sourcePositionVariancex", dictionary));
m_tPosVar.y = (float)atof(valueForKey("sourcePositionVariancey", dictionary));
// Spinning
m_fStartSpin = (float)atof(valueForKey("rotationStart", dictionary));
m_fStartSpinVar = (float)atof(valueForKey("rotationStartVariance", dictionary));
// Spinning
m_fStartSpin = (float)atof(valueForKey("rotationStart", dictionary));
m_fStartSpinVar = (float)atof(valueForKey("rotationStartVariance", dictionary));
m_fEndSpin= (float)atof(valueForKey("rotationEnd", dictionary));
m_fEndSpinVar= (float)atof(valueForKey("rotationEndVariance", dictionary));
@ -406,15 +407,15 @@ void CCParticleSystem::initParticle(tCCParticle* particle)
// Color
ccColor4F start;
start.r = clampf(m_tStartColor.r + m_tStartColorVar.r * CCRANDOM_MINUS1_1(), 0, 1);
start.g = clampf(m_tStartColor.g + m_tStartColorVar.g * CCRANDOM_MINUS1_1(), 0, 1);
start.b = clampf(m_tStartColor.b + m_tStartColorVar.b * CCRANDOM_MINUS1_1(), 0, 1);
start.r = clampf(m_tStartColor.r + m_tStartColorVar.r * CCRANDOM_MINUS1_1(), 0, 1);
start.g = clampf(m_tStartColor.g + m_tStartColorVar.g * CCRANDOM_MINUS1_1(), 0, 1);
start.b = clampf(m_tStartColor.b + m_tStartColorVar.b * CCRANDOM_MINUS1_1(), 0, 1);
start.a = clampf(m_tStartColor.a + m_tStartColorVar.a * CCRANDOM_MINUS1_1(), 0, 1);
ccColor4F end;
end.r = clampf(m_tEndColor.r + m_tEndColorVar.r * CCRANDOM_MINUS1_1(), 0, 1);
end.g = clampf(m_tEndColor.g + m_tEndColorVar.g * CCRANDOM_MINUS1_1(), 0, 1);
end.b = clampf(m_tEndColor.b + m_tEndColorVar.b * CCRANDOM_MINUS1_1(), 0, 1);
end.r = clampf(m_tEndColor.r + m_tEndColorVar.r * CCRANDOM_MINUS1_1(), 0, 1);
end.g = clampf(m_tEndColor.g + m_tEndColorVar.g * CCRANDOM_MINUS1_1(), 0, 1);
end.b = clampf(m_tEndColor.b + m_tEndColorVar.b * CCRANDOM_MINUS1_1(), 0, 1);
end.a = clampf(m_tEndColor.a + m_tEndColorVar.a * CCRANDOM_MINUS1_1(), 0, 1);
particle->color = start;
@ -424,7 +425,7 @@ void CCParticleSystem::initParticle(tCCParticle* particle)
particle->deltaColor.a = (end.a - start.a) / particle->timeToLive;
// size
float startS = m_fStartSize + m_fStartSizeVar * CCRANDOM_MINUS1_1();
float startS = m_fStartSize + m_fStartSizeVar * CCRANDOM_MINUS1_1();
startS = MAX(0, startS); // No negative value
startS *= CC_CONTENT_SCALE_FACTOR();

View File

@ -107,12 +107,6 @@ public:
*/
static void setResource(const char* pszZipFileName);
///////////////////////////////////////////////////
// interfaces on android
///////////////////////////////////////////////////
static const char* getResourcePath(void);
static void setRelativePath(const char* pszRelativePath);
///////////////////////////////////////////////////
// interfaces on ios
///////////////////////////////////////////////////

View File

@ -29,6 +29,7 @@ THE SOFTWARE.
#include "CCFileUtils.h"
#include "png.h"
#include <string>
#include <ctype.h>
#if (CC_TARGET_PLATFORM != CC_PLATFORM_IOS)
// on ios, we should use platform/ios/CCImage_ios.mm instead

View File

@ -65,7 +65,12 @@ bool CCImage::initWithImageFile(const char * strPath, EImageFormat eImgFmt/* = e
return initWithImageData(data.getBuffer(), data.getSize(), eImgFmt);
}
bool CCImage::initWithImageData(void * pData, int nDataLen, EImageFormat eFmt/* = eSrcFmtPng*/)
bool CCImage::initWithImageData(void * pData,
int nDataLen,
EImageFormat eFmt,
int nWidth,
int nHeight,
int nBitsPerComponent)
{
bool bRet = false;
do
@ -239,4 +244,29 @@ bool CCImage::initWithString(
bool bRet = false;
return bRet;
}
bool CCImage::saveToFile(const char *pszFilePath, bool bIsToRGB)
{
// todo
return false;
}
bool CCImage::_initWithRawData(void * pData, int nDatalen, int nWidth, int nHeight, int nBitsPerComponent)
{
// todo
return false;
}
bool CCImage::_saveImageToPNG(const char * pszFilePath, bool bIsToRGB)
{
// todo
return false;
}
bool CCImage::_saveImageToJPG(const char * pszFilePath)
{
// todo
return false;
}
NS_CC_END;

View File

@ -29,49 +29,49 @@ NS_CC_BEGIN;
#define MAX_PATH 256
using namespace std;
// record the resource path
static std::string s_strRelativePath = "";
static std::string s_strResourcePath = "";
static string s_strResourcePath = "";
void CCFileUtils::setRelativePath(const char* pszRelativePath)
void CCFileUtils::setResourcePath(const char* pszResourcePath)
{
CCAssert(pszRelativePath != NULL, "[FileUtils setRelativePath] -- wrong relative path");
CCAssert(pszResourcePath != NULL, "[FileUtils setRelativePath] -- wrong relative path");
if (! pszRelativePath)
if (! pszResourcePath)
{
return;
}
s_strRelativePath = pszRelativePath;
// if the path is not ended with '/', append it
if (s_strRelativePath.find("/") != (strlen(s_strRelativePath.c_str()) - 1))
s_strResourcePath = pszResourcePath;
/*
* If the path is set by user, and not end with "/", append it
*/
if (s_strResourcePath.find(".apk") == string::npos
&& s_strResourcePath.find_last_of("/") != s_strResourcePath.length() - 1)
{
s_strRelativePath += "/";
s_strResourcePath += "/";
}
}
void CCFileUtils::setResourcePath(const char *pszResourcePath)
{
CCAssert(pszResourcePath != NULL, "[FileUtils setResourcePath] -- wrong resource path");
CCAssert(strlen(pszResourcePath) <= MAX_PATH, "[FileUtils setResourcePath] -- resource path too long");
s_strResourcePath = pszResourcePath;
}
const char* CCFileUtils::getResourcePath()
{
return s_strResourcePath.c_str();
}
const char* CCFileUtils::fullPathFromRelativePath(const char *pszRelativePath)
{
return pszRelativePath;
if (s_strResourcePath.find(".apk") != string::npos)
{
return pszRelativePath;
}
else
{
CCString *pRet = new CCString();
pRet->autorelease();
pRet->m_sString = s_strResourcePath + pszRelativePath;
return pRet->m_sString.c_str();
}
}
const char *CCFileUtils::fullPathFromRelativeFile(const char *pszFilename, const char *pszRelativeFile)
{
//std::string relativeFile = fullPathFromRelativePath(pszRelativeFile);
std::string relativeFile = pszRelativeFile;
CCString *pRet = new CCString();
pRet->autorelease();
@ -81,14 +81,38 @@ const char *CCFileUtils::fullPathFromRelativeFile(const char *pszFilename, const
}
unsigned char* CCFileUtils::getFileData(const char* pszFileName, const char* pszMode, unsigned long * pSize)
{
string fullPath = s_strRelativePath + pszFileName;
unsigned char * pData = CCFileUtils::getFileDataFromZip(s_strResourcePath.c_str(), fullPath.c_str(), pSize);
{
string fullPath = pszFileName;
unsigned char * pData = 0;
if (s_strResourcePath.find(".apk") != string::npos)
{
// read from apk
fullPath.insert(0, "assets/");
pData = CCFileUtils::getFileDataFromZip(s_strResourcePath.c_str(), fullPath.c_str(), pSize);
}
else
{
do
{
// read rrom other path than user set it
FILE *fp = fopen(pszFileName, pszMode);
CC_BREAK_IF(!fp);
fseek(fp,0,SEEK_END);
*pSize = ftell(fp);
fseek(fp,0,SEEK_SET);
pData = new unsigned char[*pSize];
*pSize = fread(pData,sizeof(unsigned char), *pSize,fp);
fclose(fp);
} while (0);
}
if (! pData && getIsPopupNotify())
{
std::string title = "Notification";
std::string msg = "Get data from file(";
msg.append(pszFileName).append(") failed!");
msg.append(fullPath.c_str()).append(") failed!");
CCMessageBox(msg.c_str(), title.c_str());
}
return pData;

View File

@ -34,6 +34,8 @@ THE SOFTWARE.
#define JAVAVM cocos2d::JniHelper::getJavaVM()
using namespace std;
extern "C"
{
@ -161,34 +163,24 @@ extern "C"
return bRet;
}
static char* jstringToChar_(jstring jstr)
static string jstring2string_(jstring jstr)
{
char* rtn = 0;
JNIEnv *env = 0;
jboolean isCopy;
if (! getEnv(&env))
{
return 0;
}
// convert jstring to byte array
jclass clsstring = env->FindClass("java/lang/String");
jstring strencode = env->NewStringUTF("utf-8");
jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B");
jbyteArray barr= (jbyteArray)env->CallObjectMethod(jstr, mid, strencode);
jsize alen = env->GetArrayLength(barr);
jbyte* ba = env->GetByteArrayElements(barr, JNI_FALSE);
// copy byte array into char[]
if (alen > 0)
const char* chars = env->GetStringUTFChars(jstr, &isCopy);
string ret(chars);
if (isCopy)
{
rtn = new char[alen + 1];
memcpy(rtn, ba, alen);
rtn[alen] = 0;
env->ReleaseStringUTFChars(jstr, chars);
}
env->ReleaseByteArrayElements(barr, ba, 0);
return rtn;
return ret;
}
}
@ -221,8 +213,8 @@ namespace cocos2d {
return getMethodInfo_(methodinfo, className, methodName, paramCode);
}
char* JniHelper::jstringToChar(jstring str)
string JniHelper::jstring2string(jstring str)
{
return jstringToChar_(str);
return jstring2string_(str);
}
}

View File

@ -25,6 +25,7 @@ THE SOFTWARE.
#define __ANDROID_JNI_HELPER_H__
#include <jni.h>
#include <string>
#include "CCPlatformMacros.h"
namespace cocos2d {
@ -44,7 +45,7 @@ namespace cocos2d {
static jclass getClassID(const char *className, JNIEnv *env=0);
static bool getStaticMethodInfo(JniMethodInfo &methodinfo, const char *className, const char *methodName, const char *paramCode);
static bool getMethodInfo(JniMethodInfo &methodinfo, const char *className, const char *methodName, const char *paramCode);
static char* jstringToChar(jstring str);
static std::string jstring2string(jstring str);
private:
static JavaVM *m_psJavaVM;

View File

@ -25,6 +25,7 @@ THE SOFTWARE.
#include "CCDirector.h"
#include "JniHelper.h"
#include "CCApplication.h"
#include "CCFileUtils.h"
#include <android/log.h>
#include <jni.h>
@ -111,4 +112,18 @@ extern "C"
t.env->CallStaticObjectMethod(t.classID, t.methodID);
}
}
//////////////////////////////////////////////////////////////////////////
// set apk path
//////////////////////////////////////////////////////////////////////////
void Java_org_cocos2dx_lib_Cocos2dxActivity_nativeSetPaths(JNIEnv* env, jobject thiz, jstring apkPath)
{
const char* str;
jboolean isCopy;
str = env->GetStringUTFChars(apkPath, &isCopy);
if (isCopy) {
cocos2d::CCFileUtils::setResourcePath(str);
env->ReleaseStringUTFChars(apkPath, str);
}
}
}

View File

@ -26,7 +26,6 @@ THE SOFTWARE.
#include "CCAccelerometer.h"
#include "platform/android/CCAccelerometer_android.h"
#include "CCEGLView.h"
#include "CCFileUtils.h"
#include "JniHelper.h"
#include <android/log.h>
#include <jni.h>
@ -57,19 +56,7 @@ extern "C"
(y - rcRect.origin.y) / fScreenScaleFactor,
z,
timeStamp);
}
void Java_org_cocos2dx_lib_Cocos2dxActivity_nativeSetPaths(JNIEnv* env, jobject thiz, jstring apkPath)
{
const char* str;
jboolean isCopy;
str = env->GetStringUTFChars(apkPath, &isCopy);
if (isCopy) {
cocos2d::CCFileUtils::setResourcePath(str);
env->ReleaseStringUTFChars(apkPath, str);
}
}
}
void enableAccelerometerJNI()
{

View File

@ -50,7 +50,7 @@ extern "C"
"()Ljava/lang/String;"))
{
jstring str = (jstring)t.env->CallStaticObjectMethod(t.classID, t.methodID);
ret = JniHelper::jstringToChar(str);
ret = (char*)JniHelper::jstring2string(str).c_str();
LOGD("package name %s", ret);
}
@ -72,7 +72,7 @@ extern "C"
, "()Ljava/lang/String;"))
{
jstring str = (jstring)t.env->CallStaticObjectMethod(t.classID, t.methodID);
ret = JniHelper::jstringToChar(str);
ret = (char*)JniHelper::jstring2string(str).c_str();
LOGD("language name %s", ret);
}

View File

@ -247,12 +247,7 @@ namespace cocos2d {
strcpy(s_pszResourcePath, pszResourcePath);
}
const char* CCFileUtils::getResourcePath()
{
return s_pszResourcePath;
}
int CCFileUtils::ccLoadFileIntoMemory(const char *filename, unsigned char **out)
{
CCAssert( out, "ccLoadFileIntoMemory: invalid 'out' parameter");
@ -347,10 +342,6 @@ namespace cocos2d {
{
CCAssert(0, "Have not implement!");
}
void CCFileUtils::setRelativePath(const char* pszRelativePath)
{
CCAssert(0, "Have not implement!");
}
// notification support when getFileData from a invalid file
static bool s_bPopupNotify = true;

View File

@ -21,11 +21,18 @@ 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 <Foundation/Foundation.h>
#include <UIKit/UIKit.h>
#include "CCImage.h"
#include "CCFileUtils.h"
#include <string>
#import "CCImage.h"
#import "CCFileUtils.h"
#import <string>
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#if CC_FONT_LABEL_SUPPORT
// FontLabel support
#import "FontLabel/FontManager.h"
#import "FontLabel/FontLabelStringDrawing.h"
#endif// CC_FONT_LABEL_SUPPORT
typedef struct
{
@ -335,104 +342,97 @@ static bool _initWithString(const char * pText, cocos2d::CCImage::ETextAlign eAl
{
CC_BREAK_IF(! pText || ! pInfo);
NSString * string = [NSString stringWithUTF8String:pText];
NSString * str = [NSString stringWithUTF8String:pText];
NSString * fntName = [NSString stringWithUTF8String:pFontName];
CGSize dim;
// create the font
NSString * fntName = _isValidFontName(pFontName) ? [NSString stringWithUTF8String:pFontName] : @"MarkerFelt-Wide";
UIFont * font = [UIFont fontWithName:fntName size:nSize];
if (! font)
// create the font
id font;
font = [UIFont fontWithName:fntName size:nSize];
if (font)
{
font = [UIFont systemFontOfSize:nSize];
dim = [str sizeWithFont:font];
}
#if CC_FONT_LABEL_SUPPORT
if (! font)
{
font = [[FontManager sharedManager] zFontWithName:fntName pointSize:nSize];
if (font)
{
//dim = [str sizeWithZFont:font];
dim = [FontLabelStringDrawingHelper sizeWithZFont:str zfont:font];
}
}
#endif // CC_FONT_LABEL_SUPPORT
if (! font)
{
fntName = _isValidFontName(pFontName) ? fntName : @"MarkerFelt-Wide";
font = [UIFont fontWithName:fntName size:nSize];
if (! font)
{
font = [UIFont systemFontOfSize:nSize];
}
if (font)
{
dim = [str sizeWithFont:font];
}
}
CC_BREAK_IF(! font);
// measure text size with specified font and determine the rectangle to draw text in
unsigned uHoriFlag = eAlign & 0x0f;
unsigned uVertFlag = (eAlign & 0xf0) >> 4;
CGSize textSize; // the size which total text layout need
CGSize canvasSize; // the size which malloc for drawtext
CGRect textRect; // the rectangle which draw text in
if (0 >= pInfo->width)
if (pInfo->width != 0 || pInfo->height != 0)
{
// the content width no limit, use 0x7fffffff as a big enough bounds
CGSize contentSize = CGSizeMake(0x7fffffff, 0x7fffffff);
textSize = [string sizeWithFont:font constrainedToSize:contentSize];
canvasSize = textSize;
pInfo->width = (size_t) textSize.width;
pInfo->height = (size_t) textSize.height;
textRect = CGRectMake(0, 0, textSize.width, textSize.height);
dim.width = pInfo->width;
dim.height = pInfo->height;
}
else
{
// the content height no limit, use 0x7fffffff as a big enough height
CGSize contentSize = CGSizeMake(pInfo->width, 0x7fffffff);
textSize = [string sizeWithFont:font constrainedToSize:contentSize];
if (0 >= pInfo->height)
{
canvasSize = textSize;
pInfo->height = (size_t) textSize.height;
pInfo->width = (size_t) textSize.width;
textRect = CGRectMake(0, 0, textSize.width, textSize.height);
}
else
{
canvasSize.width = pInfo->width;
if (textSize.height <= pInfo->height)
{
canvasSize.height = pInfo->height;
}
else
{
// the height of text larger than the specified
// let canvas's height larger a little,
// make sure the last line of text in specified rectangle draw in canvas
size_t lineHeight = (size_t)font.lineHeight;
canvasSize.height = ((pInfo->height + lineHeight - 1) / lineHeight) * lineHeight;
}
canvasSize = CGSizeMake(pInfo->width, MAX(pInfo->height, (size_t)textSize.height));
textRect.size = textSize;
textRect.origin.x = (1 == uHoriFlag) ? 0 // align to left
: (2 == uHoriFlag) ? pInfo->width - textSize.width // align to right
: (pInfo->width - textSize.width) / 2; // align to center
textRect.origin.y = (1 == uVertFlag || textSize.height >= pInfo->height) ? 0 // align to top
: (2 == uVertFlag) ? pInfo->height - textSize.height // align to bottom
: (pInfo->height - textSize.height) / 2; // align to center
}
pInfo->width = dim.width;
pInfo->height = dim.height;
}
// malloc space to store pixels data
size_t width = (size_t)canvasSize.width;
size_t height = (size_t)canvasSize.height;
unsigned char* data = new unsigned char[width * height * 4];
CC_BREAK_IF(! data);
memset(data, 0, height * width * 4);
CC_BREAK_IF(! font);
unsigned char* data = new unsigned char[pInfo->width * pInfo->height * 4];
memset(data, 0, pInfo->width * pInfo->height * 4);
// draw text
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(data, width, height, 8, width * 4, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(data, dim.width, dim.height, 8, dim.width * 4, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
CGColorSpaceRelease(colorSpace);
CC_BREAK_IF(!context);
if (! context)
{
delete[] data;
break;
}
CGContextSetRGBFillColor(context, 1, 1, 1, 1);
CGContextTranslateCTM(context, 0.0f, height);
CGContextTranslateCTM(context, 0.0f, dim.height);
CGContextScaleCTM(context, 1.0f, -1.0f); //NOTE: NSString draws in UIKit referential i.e. renders upside-down compared to CGBitmapContext referential
UIGraphicsPushContext(context);
// measure text size with specified font and determine the rectangle to draw text in
unsigned uHoriFlag = eAlign & 0x0f;
UITextAlignment align = (2 == uHoriFlag) ? UITextAlignmentRight
: (3 == uHoriFlag) ? UITextAlignmentCenter
: UITextAlignmentLeft;
[string drawInRect:textRect withFont:font lineBreakMode:UILineBreakModeWordWrap alignment:align];
// normal fonts
if( [font isKindOfClass:[UIFont class] ] )
{
[str drawInRect:CGRectMake(0, 0, dim.width, dim.height) withFont:font lineBreakMode:UILineBreakModeWordWrap alignment:align];
}
#if CC_FONT_LABEL_SUPPORT
else // ZFont class
{
//[str drawInRect:CGRectMake(0, 0, dim.width, dim.height) withZFont:font lineBreakMode:UILineBreakModeWordWrap alignment:align];
[FontLabelStringDrawingHelper drawInRect:str rect:CGRectMake(0, 0, dim.width, dim.height) withZFont:font lineBreakMode:UILineBreakModeWordWrap alignment:align];
}
#endif
UIGraphicsPopContext();
@ -473,7 +473,12 @@ bool CCImage::initWithImageFile(const char * strPath, EImageFormat eImgFmt/* = e
return initWithImageData(data.getBuffer(), data.getSize(), eImgFmt);
}
bool CCImage::initWithImageData(void * pData, int nDataLen, EImageFormat eFmt/* = eSrcFmtPng*/)
bool CCImage::initWithImageData(void * pData,
int nDataLen,
EImageFormat eFmt,
int nWidth,
int nHeight,
int nBitsPerComponent)
{
bool bRet = false;
tImageInfo info = {0};
@ -520,5 +525,10 @@ bool CCImage::initWithString(
return true;
}
bool CCImage::saveToFile(const char *pszFilePath, bool bIsToRGB)
{
return false;
}
NS_CC_END;

View File

@ -0,0 +1,44 @@
//
// FontLabel.h
// FontLabel
//
// Created by Kevin Ballard on 5/8/09.
// Copyright © 2009 Zynga Game Networks
//
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@class ZFont;
@class ZAttributedString;
@interface FontLabel : UILabel {
void *reserved; // works around a bug in UILabel
ZFont *zFont;
ZAttributedString *zAttributedText;
}
@property (nonatomic, setter=setCGFont:) CGFontRef cgFont __AVAILABILITY_INTERNAL_DEPRECATED;
@property (nonatomic, assign) CGFloat pointSize __AVAILABILITY_INTERNAL_DEPRECATED;
@property (nonatomic, retain, setter=setZFont:) ZFont *zFont;
// if attributedText is nil, fall back on using the inherited UILabel properties
// if attributedText is non-nil, the font/text/textColor
// in addition, adjustsFontSizeToFitWidth does not work with attributed text
@property (nonatomic, copy) ZAttributedString *zAttributedText;
// -initWithFrame:fontName:pointSize: uses FontManager to look up the font name
- (id)initWithFrame:(CGRect)frame fontName:(NSString *)fontName pointSize:(CGFloat)pointSize;
- (id)initWithFrame:(CGRect)frame zFont:(ZFont *)font;
- (id)initWithFrame:(CGRect)frame font:(CGFontRef)font pointSize:(CGFloat)pointSize __AVAILABILITY_INTERNAL_DEPRECATED;
@end

View File

@ -0,0 +1,195 @@
//
// FontLabel.m
// FontLabel
//
// Created by Kevin Ballard on 5/8/09.
// Copyright © 2009 Zynga Game Networks
//
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#import "FontLabel.h"
#import "FontManager.h"
#import "FontLabelStringDrawing.h"
#import "ZFont.h"
@interface ZFont (ZFontPrivate)
@property (nonatomic, readonly) CGFloat ratio;
@end
@implementation FontLabel
@synthesize zFont;
@synthesize zAttributedText;
- (id)initWithFrame:(CGRect)frame fontName:(NSString *)fontName pointSize:(CGFloat)pointSize {
return [self initWithFrame:frame zFont:[[FontManager sharedManager] zFontWithName:fontName pointSize:pointSize]];
}
- (id)initWithFrame:(CGRect)frame zFont:(ZFont *)font {
if ((self = [super initWithFrame:frame])) {
zFont = [font retain];
}
return self;
}
- (id)initWithFrame:(CGRect)frame font:(CGFontRef)font pointSize:(CGFloat)pointSize {
return [self initWithFrame:frame zFont:[ZFont fontWithCGFont:font size:pointSize]];
}
- (CGFontRef)cgFont {
return self.zFont.cgFont;
}
- (void)setCGFont:(CGFontRef)font {
if (self.zFont.cgFont != font) {
self.zFont = [ZFont fontWithCGFont:font size:self.zFont.pointSize];
}
}
- (CGFloat)pointSize {
return self.zFont.pointSize;
}
- (void)setPointSize:(CGFloat)pointSize {
if (self.zFont.pointSize != pointSize) {
self.zFont = [ZFont fontWithCGFont:self.zFont.cgFont size:pointSize];
}
}
- (void)setZAttributedText:(ZAttributedString *)attStr {
if (zAttributedText != attStr) {
[zAttributedText release];
zAttributedText = [attStr copy];
[self setNeedsDisplay];
}
}
- (void)drawTextInRect:(CGRect)rect {
if (self.zFont == NULL && self.zAttributedText == nil) {
[super drawTextInRect:rect];
return;
}
if (self.zAttributedText == nil) {
// this method is documented as setting the text color for us, but that doesn't appear to be the case
if (self.highlighted) {
[(self.highlightedTextColor ?: [UIColor whiteColor]) setFill];
} else {
[(self.textColor ?: [UIColor blackColor]) setFill];
}
ZFont *actualFont = self.zFont;
CGSize origSize = rect.size;
if (self.numberOfLines == 1) {
origSize.height = actualFont.leading;
CGPoint point = CGPointMake(rect.origin.x,
rect.origin.y + roundf(((rect.size.height - actualFont.leading) / 2.0f)));
CGSize size = [self.text sizeWithZFont:actualFont];
if (self.adjustsFontSizeToFitWidth && self.minimumFontSize < actualFont.pointSize) {
if (size.width > origSize.width) {
CGFloat desiredRatio = (origSize.width * actualFont.ratio) / size.width;
CGFloat desiredPointSize = desiredRatio * actualFont.pointSize / actualFont.ratio;
actualFont = [actualFont fontWithSize:MAX(MAX(desiredPointSize, self.minimumFontSize), 1.0f)];
size = [self.text sizeWithZFont:actualFont];
}
if (!CGSizeEqualToSize(origSize, size)) {
switch (self.baselineAdjustment) {
case UIBaselineAdjustmentAlignCenters:
point.y += roundf((origSize.height - size.height) / 2.0f);
break;
case UIBaselineAdjustmentAlignBaselines:
point.y += (self.zFont.ascender - actualFont.ascender);
break;
case UIBaselineAdjustmentNone:
break;
}
}
}
size.width = MIN(size.width, origSize.width);
// adjust the point for alignment
switch (self.textAlignment) {
case UITextAlignmentLeft:
break;
case UITextAlignmentCenter:
point.x += (origSize.width - size.width) / 2.0f;
break;
case UITextAlignmentRight:
point.x += origSize.width - size.width;
break;
}
[self.text drawAtPoint:point forWidth:size.width withZFont:actualFont lineBreakMode:self.lineBreakMode];
} else {
CGSize size = [self.text sizeWithZFont:actualFont constrainedToSize:origSize lineBreakMode:self.lineBreakMode numberOfLines:self.numberOfLines];
CGPoint point = rect.origin;
point.y += roundf((rect.size.height - size.height) / 2.0f);
rect = (CGRect){point, CGSizeMake(rect.size.width, size.height)};
[self.text drawInRect:rect withZFont:actualFont lineBreakMode:self.lineBreakMode alignment:self.textAlignment numberOfLines:self.numberOfLines];
}
} else {
ZAttributedString *attStr = self.zAttributedText;
if (self.highlighted) {
// modify the string to change the base color
ZMutableAttributedString *mutStr = [[attStr mutableCopy] autorelease];
NSRange activeRange = NSMakeRange(0, attStr.length);
while (activeRange.length > 0) {
NSRange effective;
UIColor *color = [attStr attribute:ZForegroundColorAttributeName atIndex:activeRange.location
longestEffectiveRange:&effective inRange:activeRange];
if (color == nil) {
[mutStr addAttribute:ZForegroundColorAttributeName value:[UIColor whiteColor] range:effective];
}
activeRange.location += effective.length, activeRange.length -= effective.length;
}
attStr = mutStr;
}
CGSize size = [attStr sizeConstrainedToSize:rect.size lineBreakMode:self.lineBreakMode numberOfLines:self.numberOfLines];
CGPoint point = rect.origin;
point.y += roundf((rect.size.height - size.height) / 2.0f);
rect = (CGRect){point, CGSizeMake(rect.size.width, size.height)};
[attStr drawInRect:rect withLineBreakMode:self.lineBreakMode alignment:self.textAlignment numberOfLines:self.numberOfLines];
}
}
- (CGRect)textRectForBounds:(CGRect)bounds limitedToNumberOfLines:(NSInteger)numberOfLines {
if (self.zFont == NULL && self.zAttributedText == nil) {
return [super textRectForBounds:bounds limitedToNumberOfLines:numberOfLines];
}
if (numberOfLines == 1) {
// if numberOfLines == 1 we need to use the version that converts spaces
CGSize size;
if (self.zAttributedText == nil) {
size = [self.text sizeWithZFont:self.zFont];
} else {
size = [self.zAttributedText size];
}
bounds.size.width = MIN(bounds.size.width, size.width);
bounds.size.height = MIN(bounds.size.height, size.height);
} else {
if (numberOfLines > 0) bounds.size.height = MIN(bounds.size.height, self.zFont.leading * numberOfLines);
if (self.zAttributedText == nil) {
bounds.size = [self.text sizeWithZFont:self.zFont constrainedToSize:bounds.size lineBreakMode:self.lineBreakMode];
} else {
bounds.size = [self.zAttributedText sizeConstrainedToSize:bounds.size lineBreakMode:self.lineBreakMode];
}
}
return bounds;
}
- (void)dealloc {
[zFont release];
[zAttributedText release];
[super dealloc];
}
@end

View File

@ -0,0 +1,81 @@
//
// FontLabelStringDrawing.h
// FontLabel
//
// Created by Kevin Ballard on 5/5/09.
// Copyright © 2009 Zynga Game Networks
// Copyright (c) 2011 cocos2d-x.org
//
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#import <UIKit/UIKit.h>
#import "ZAttributedString.h"
@class ZFont;
@interface NSString (FontLabelStringDrawing)
// CGFontRef-based methods
- (CGSize)sizeWithCGFont:(CGFontRef)font pointSize:(CGFloat)pointSize __AVAILABILITY_INTERNAL_DEPRECATED;
- (CGSize)sizeWithCGFont:(CGFontRef)font pointSize:(CGFloat)pointSize constrainedToSize:(CGSize)size __AVAILABILITY_INTERNAL_DEPRECATED;
- (CGSize)sizeWithCGFont:(CGFontRef)font pointSize:(CGFloat)pointSize constrainedToSize:(CGSize)size
lineBreakMode:(UILineBreakMode)lineBreakMode __AVAILABILITY_INTERNAL_DEPRECATED;
- (CGSize)drawAtPoint:(CGPoint)point withCGFont:(CGFontRef)font pointSize:(CGFloat)pointSize __AVAILABILITY_INTERNAL_DEPRECATED;
- (CGSize)drawInRect:(CGRect)rect withCGFont:(CGFontRef)font pointSize:(CGFloat)pointSize __AVAILABILITY_INTERNAL_DEPRECATED;
- (CGSize)drawInRect:(CGRect)rect withCGFont:(CGFontRef)font pointSize:(CGFloat)pointSize
lineBreakMode:(UILineBreakMode)lineBreakMode __AVAILABILITY_INTERNAL_DEPRECATED;
- (CGSize)drawInRect:(CGRect)rect withCGFont:(CGFontRef)font pointSize:(CGFloat)pointSize
lineBreakMode:(UILineBreakMode)lineBreakMode alignment:(UITextAlignment)alignment __AVAILABILITY_INTERNAL_DEPRECATED;
// ZFont-based methods
- (CGSize)sizeWithZFont:(ZFont *)font;
- (CGSize)sizeWithZFont:(ZFont *)font constrainedToSize:(CGSize)size;
- (CGSize)sizeWithZFont:(ZFont *)font constrainedToSize:(CGSize)size lineBreakMode:(UILineBreakMode)lineBreakMode;
- (CGSize)sizeWithZFont:(ZFont *)font constrainedToSize:(CGSize)size lineBreakMode:(UILineBreakMode)lineBreakMode
numberOfLines:(NSUInteger)numberOfLines;
- (CGSize)drawAtPoint:(CGPoint)point withZFont:(ZFont *)font;
- (CGSize)drawAtPoint:(CGPoint)point forWidth:(CGFloat)width withZFont:(ZFont *)font lineBreakMode:(UILineBreakMode)lineBreakMode;
- (CGSize)drawInRect:(CGRect)rect withZFont:(ZFont *)font;
- (CGSize)drawInRect:(CGRect)rect withZFont:(ZFont *)font lineBreakMode:(UILineBreakMode)lineBreakMode;
- (CGSize)drawInRect:(CGRect)rect withZFont:(ZFont *)font lineBreakMode:(UILineBreakMode)lineBreakMode
alignment:(UITextAlignment)alignment;
- (CGSize)drawInRect:(CGRect)rect withZFont:(ZFont *)font lineBreakMode:(UILineBreakMode)lineBreakMode
alignment:(UITextAlignment)alignment numberOfLines:(NSUInteger)numberOfLines;
@end
@interface ZAttributedString (ZAttributedStringDrawing)
- (CGSize)size;
- (CGSize)sizeConstrainedToSize:(CGSize)size;
- (CGSize)sizeConstrainedToSize:(CGSize)size lineBreakMode:(UILineBreakMode)lineBreakMode;
- (CGSize)sizeConstrainedToSize:(CGSize)size lineBreakMode:(UILineBreakMode)lineBreakMode
numberOfLines:(NSUInteger)numberOfLines;
- (CGSize)drawAtPoint:(CGPoint)point;
- (CGSize)drawAtPoint:(CGPoint)point forWidth:(CGFloat)width lineBreakMode:(UILineBreakMode)lineBreakMode;
- (CGSize)drawInRect:(CGRect)rect;
- (CGSize)drawInRect:(CGRect)rect withLineBreakMode:(UILineBreakMode)lineBreakMode;
- (CGSize)drawInRect:(CGRect)rect withLineBreakMode:(UILineBreakMode)lineBreakMode alignment:(UITextAlignment)alignment;
- (CGSize)drawInRect:(CGRect)rect withLineBreakMode:(UILineBreakMode)lineBreakMode alignment:(UITextAlignment)alignment
numberOfLines:(NSUInteger)numberOfLines;
@end
// This class is used to invoke in .mm file.
// Can not invoke FontLabelStringDrawing directly in .mm.
// It seems that, in .mm it can not support category.
@interface FontLabelStringDrawingHelper : NSObject {
}
+ (CGSize)sizeWithZFont:(NSString*)string zfont:(ZFont *)font;
+ (CGSize)drawInRect:(NSString*)string rect:(CGRect)rect withZFont:(ZFont *)font
lineBreakMode:(UILineBreakMode)lineBreakMode
alignment:(UITextAlignment)alignment;
@end

View File

@ -0,0 +1,907 @@
//
// FontLabelStringDrawing.m
// FontLabel
//
// Created by Kevin Ballard on 5/5/09.
// Copyright © 2009 Zynga Game Networks
// Copyright (c) 2011 cocos2d-x.org
//
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#import "FontLabelStringDrawing.h"
#import "ZFont.h"
#import "ZAttributedStringPrivate.h"
@interface ZFont (ZFontPrivate)
@property (nonatomic, readonly) CGFloat ratio;
@end
#define kUnicodeHighSurrogateStart 0xD800
#define kUnicodeHighSurrogateEnd 0xDBFF
#define kUnicodeHighSurrogateMask kUnicodeHighSurrogateStart
#define kUnicodeLowSurrogateStart 0xDC00
#define kUnicodeLowSurrogateEnd 0xDFFF
#define kUnicodeLowSurrogateMask kUnicodeLowSurrogateStart
#define kUnicodeSurrogateTypeMask 0xFC00
#define UnicharIsHighSurrogate(c) ((c & kUnicodeSurrogateTypeMask) == kUnicodeHighSurrogateMask)
#define UnicharIsLowSurrogate(c) ((c & kUnicodeSurrogateTypeMask) == kUnicodeLowSurrogateMask)
#define ConvertSurrogatePairToUTF32(high, low) ((UInt32)((high - 0xD800) * 0x400 + (low - 0xDC00) + 0x10000))
typedef enum {
kFontTableFormat4 = 4,
kFontTableFormat12 = 12,
} FontTableFormat;
typedef struct fontTable {
NSUInteger retainCount;
CFDataRef cmapTable;
FontTableFormat format;
union {
struct {
UInt16 segCountX2;
UInt16 *endCodes;
UInt16 *startCodes;
UInt16 *idDeltas;
UInt16 *idRangeOffsets;
} format4;
struct {
UInt32 nGroups;
struct {
UInt32 startCharCode;
UInt32 endCharCode;
UInt32 startGlyphCode;
} *groups;
} format12;
} cmap;
} fontTable;
static FontTableFormat supportedFormats[] = { kFontTableFormat4, kFontTableFormat12 };
static size_t supportedFormatsCount = sizeof(supportedFormats) / sizeof(FontTableFormat);
static fontTable *newFontTable(CFDataRef cmapTable, FontTableFormat format) {
fontTable *table = (struct fontTable *)malloc(sizeof(struct fontTable));
table->retainCount = 1;
table->cmapTable = CFRetain(cmapTable);
table->format = format;
return table;
}
static fontTable *retainFontTable(fontTable *table) {
if (table != NULL) {
table->retainCount++;
}
return table;
}
static void releaseFontTable(fontTable *table) {
if (table != NULL) {
if (table->retainCount <= 1) {
CFRelease(table->cmapTable);
free(table);
} else {
table->retainCount--;
}
}
}
static const void *fontTableRetainCallback(CFAllocatorRef allocator, const void *value) {
return retainFontTable((fontTable *)value);
}
static void fontTableReleaseCallback(CFAllocatorRef allocator, const void *value) {
releaseFontTable((fontTable *)value);
}
static const CFDictionaryValueCallBacks kFontTableDictionaryValueCallBacks = {
.version = 0,
.retain = &fontTableRetainCallback,
.release = &fontTableReleaseCallback,
.copyDescription = NULL,
.equal = NULL
};
// read the cmap table from the font
// we only know how to understand some of the table formats at the moment
static fontTable *readFontTableFromCGFont(CGFontRef font) {
CFDataRef cmapTable = CGFontCopyTableForTag(font, 'cmap');
NSCAssert1(cmapTable != NULL, @"CGFontCopyTableForTag returned NULL for 'cmap' tag in font %@",
(font ? [(id)CFCopyDescription(font) autorelease] : @"(null)"));
const UInt8 * const bytes = CFDataGetBytePtr(cmapTable);
NSCAssert1(OSReadBigInt16(bytes, 0) == 0, @"cmap table for font %@ has bad version number",
(font ? [(id)CFCopyDescription(font) autorelease] : @"(null)"));
UInt16 numberOfSubtables = OSReadBigInt16(bytes, 2);
const UInt8 *unicodeSubtable = NULL;
//UInt16 unicodeSubtablePlatformID;
UInt16 unicodeSubtablePlatformSpecificID;
FontTableFormat unicodeSubtableFormat;
const UInt8 * const encodingSubtables = &bytes[4];
for (UInt16 i = 0; i < numberOfSubtables; i++) {
const UInt8 * const encodingSubtable = &encodingSubtables[8 * i];
UInt16 platformID = OSReadBigInt16(encodingSubtable, 0);
UInt16 platformSpecificID = OSReadBigInt16(encodingSubtable, 2);
// find the best subtable
// best is defined by a combination of encoding and format
// At the moment we only support format 4, so ignore all other format tables
// We prefer platformID == 0, but we will also accept Microsoft's unicode format
if (platformID == 0 || (platformID == 3 && platformSpecificID == 1)) {
BOOL preferred = NO;
if (unicodeSubtable == NULL) {
preferred = YES;
} else if (platformID == 0 && platformSpecificID > unicodeSubtablePlatformSpecificID) {
preferred = YES;
}
if (preferred) {
UInt32 offset = OSReadBigInt32(encodingSubtable, 4);
const UInt8 *subtable = &bytes[offset];
UInt16 format = OSReadBigInt16(subtable, 0);
for (size_t i = 0; i < supportedFormatsCount; i++) {
if (format == supportedFormats[i]) {
if (format >= 8) {
// the version is a fixed-point
UInt16 formatFrac = OSReadBigInt16(subtable, 2);
if (formatFrac != 0) {
// all the current formats with a Fixed version are always *.0
continue;
}
}
unicodeSubtable = subtable;
//unicodeSubtablePlatformID = platformID;
unicodeSubtablePlatformSpecificID = platformSpecificID;
unicodeSubtableFormat = format;
break;
}
}
}
}
}
fontTable *table = NULL;
if (unicodeSubtable != NULL) {
table = newFontTable(cmapTable, unicodeSubtableFormat);
switch (unicodeSubtableFormat) {
case kFontTableFormat4:
// subtable format 4
//UInt16 length = OSReadBigInt16(unicodeSubtable, 2);
//UInt16 language = OSReadBigInt16(unicodeSubtable, 4);
table->cmap.format4.segCountX2 = OSReadBigInt16(unicodeSubtable, 6);
//UInt16 searchRange = OSReadBigInt16(unicodeSubtable, 8);
//UInt16 entrySelector = OSReadBigInt16(unicodeSubtable, 10);
//UInt16 rangeShift = OSReadBigInt16(unicodeSubtable, 12);
table->cmap.format4.endCodes = (UInt16*)&unicodeSubtable[14];
table->cmap.format4.startCodes = (UInt16*)&((UInt8*)table->cmap.format4.endCodes)[table->cmap.format4.segCountX2+2];
table->cmap.format4.idDeltas = (UInt16*)&((UInt8*)table->cmap.format4.startCodes)[table->cmap.format4.segCountX2];
table->cmap.format4.idRangeOffsets = (UInt16*)&((UInt8*)table->cmap.format4.idDeltas)[table->cmap.format4.segCountX2];
//UInt16 *glyphIndexArray = &idRangeOffsets[segCountX2];
break;
case kFontTableFormat12:
table->cmap.format12.nGroups = OSReadBigInt32(unicodeSubtable, 12);
table->cmap.format12.groups = (void *)&unicodeSubtable[16];
break;
default:
releaseFontTable(table);
table = NULL;
}
}
CFRelease(cmapTable);
return table;
}
// outGlyphs must be at least size n
static void mapCharactersToGlyphsInFont(const fontTable *table, unichar characters[], size_t charLen, CGGlyph outGlyphs[], size_t *outGlyphLen) {
if (table != NULL) {
NSUInteger j = 0;
switch (table->format) {
case kFontTableFormat4: {
for (NSUInteger i = 0; i < charLen; i++, j++) {
unichar c = characters[i];
UInt16 segOffset;
BOOL foundSegment = NO;
for (segOffset = 0; segOffset < table->cmap.format4.segCountX2; segOffset += 2) {
UInt16 endCode = OSReadBigInt16(table->cmap.format4.endCodes, segOffset);
if (endCode >= c) {
foundSegment = YES;
break;
}
}
if (!foundSegment) {
// no segment
// this is an invalid font
outGlyphs[j] = 0;
} else {
UInt16 startCode = OSReadBigInt16(table->cmap.format4.startCodes, segOffset);
if (!(startCode <= c)) {
// the code falls in a hole between segments
outGlyphs[j] = 0;
} else {
UInt16 idRangeOffset = OSReadBigInt16(table->cmap.format4.idRangeOffsets, segOffset);
if (idRangeOffset == 0) {
UInt16 idDelta = OSReadBigInt16(table->cmap.format4.idDeltas, segOffset);
outGlyphs[j] = (c + idDelta) % 65536;
} else {
// use the glyphIndexArray
UInt16 glyphOffset = idRangeOffset + 2 * (c - startCode);
outGlyphs[j] = OSReadBigInt16(&((UInt8*)table->cmap.format4.idRangeOffsets)[segOffset], glyphOffset);
}
}
}
}
break;
}
case kFontTableFormat12: {
UInt32 lastSegment = UINT32_MAX;
for (NSUInteger i = 0; i < charLen; i++, j++) {
unichar c = characters[i];
UInt32 c32 = c;
if (UnicharIsHighSurrogate(c)) {
if (i+1 < charLen) { // do we have another character after this one?
unichar cc = characters[i+1];
if (UnicharIsLowSurrogate(cc)) {
c32 = ConvertSurrogatePairToUTF32(c, cc);
i++;
}
}
}
// Start the heuristic search
// If this is an ASCII char, just do a linear search
// Otherwise do a hinted, modified binary search
// Start the first pivot at the last range found
// And when moving the pivot, limit the movement by increasing
// powers of two. This should help with locality
__typeof__(table->cmap.format12.groups[0]) *foundGroup = NULL;
if (c32 <= 0x7F) {
// ASCII
for (UInt32 idx = 0; idx < table->cmap.format12.nGroups; idx++) {
__typeof__(table->cmap.format12.groups[idx]) *group = &table->cmap.format12.groups[idx];
if (c32 < OSSwapBigToHostInt32(group->startCharCode)) {
// we've fallen into a hole
break;
} else if (c32 <= OSSwapBigToHostInt32(group->endCharCode)) {
// this is the range
foundGroup = group;
break;
}
}
} else {
// heuristic search
UInt32 maxJump = (lastSegment == UINT32_MAX ? UINT32_MAX / 2 : 8);
UInt32 lowIdx = 0, highIdx = table->cmap.format12.nGroups; // highIdx is the first invalid idx
UInt32 pivot = (lastSegment == UINT32_MAX ? lowIdx + (highIdx - lowIdx) / 2 : lastSegment);
while (highIdx > lowIdx) {
__typeof__(table->cmap.format12.groups[pivot]) *group = &table->cmap.format12.groups[pivot];
if (c32 < OSSwapBigToHostInt32(group->startCharCode)) {
highIdx = pivot;
} else if (c32 > OSSwapBigToHostInt32(group->endCharCode)) {
lowIdx = pivot + 1;
} else {
// we've hit the range
foundGroup = group;
break;
}
if (highIdx - lowIdx > maxJump * 2) {
if (highIdx == pivot) {
pivot -= maxJump;
} else {
pivot += maxJump;
}
maxJump *= 2;
} else {
pivot = lowIdx + (highIdx - lowIdx) / 2;
}
}
if (foundGroup != NULL) lastSegment = pivot;
}
if (foundGroup == NULL) {
outGlyphs[j] = 0;
} else {
outGlyphs[j] = (CGGlyph)(OSSwapBigToHostInt32(foundGroup->startGlyphCode) +
(c32 - OSSwapBigToHostInt32(foundGroup->startCharCode)));
}
}
break;
}
}
if (outGlyphLen != NULL) *outGlyphLen = j;
} else {
// we have no table, so just null out the glyphs
bzero(outGlyphs, charLen*sizeof(CGGlyph));
if (outGlyphLen != NULL) *outGlyphLen = 0;
}
}
static BOOL mapGlyphsToAdvancesInFont(ZFont *font, size_t n, CGGlyph glyphs[], CGFloat outAdvances[]) {
int advances[n];
if (CGFontGetGlyphAdvances(font.cgFont, glyphs, n, advances)) {
CGFloat ratio = font.ratio;
for (size_t i = 0; i < n; i++) {
outAdvances[i] = advances[i]*ratio;
}
return YES;
} else {
bzero(outAdvances, n*sizeof(CGFloat));
}
return NO;
}
static id getValueOrDefaultForRun(ZAttributeRun *run, NSString *key) {
id value = [run.attributes objectForKey:key];
if (value == nil) {
static NSDictionary *defaultValues = nil;
if (defaultValues == nil) {
defaultValues = [[NSDictionary alloc] initWithObjectsAndKeys:
[ZFont fontWithUIFont:[UIFont systemFontOfSize:12]], ZFontAttributeName,
[UIColor blackColor], ZForegroundColorAttributeName,
[UIColor clearColor], ZBackgroundColorAttributeName,
[NSNumber numberWithInt:ZUnderlineStyleNone], ZUnderlineStyleAttributeName,
nil];
}
value = [defaultValues objectForKey:key];
}
return value;
}
static void readRunInformation(NSArray *attributes, NSUInteger len, CFMutableDictionaryRef fontTableMap,
NSUInteger index, ZAttributeRun **currentRun, NSUInteger *nextRunStart,
ZFont **currentFont, fontTable **currentTable) {
*currentRun = [attributes objectAtIndex:index];
*nextRunStart = ([attributes count] > index+1 ? [[attributes objectAtIndex:index+1] index] : len);
*currentFont = getValueOrDefaultForRun(*currentRun, ZFontAttributeName);
if (!CFDictionaryGetValueIfPresent(fontTableMap, (*currentFont).cgFont, (const void **)currentTable)) {
*currentTable = readFontTableFromCGFont((*currentFont).cgFont);
CFDictionarySetValue(fontTableMap, (*currentFont).cgFont, *currentTable);
releaseFontTable(*currentTable);
}
}
static CGSize drawOrSizeTextConstrainedToSize(BOOL performDraw, NSString *string, NSArray *attributes, CGSize constrainedSize, NSUInteger maxLines,
UILineBreakMode lineBreakMode, UITextAlignment alignment, BOOL ignoreColor) {
NSUInteger len = [string length];
NSUInteger idx = 0;
CGPoint drawPoint = CGPointZero;
CGSize retValue = CGSizeZero;
CGContextRef ctx = (performDraw ? UIGraphicsGetCurrentContext() : NULL);
BOOL convertNewlines = (maxLines == 1);
// Extract the characters from the string
// Convert newlines to spaces if necessary
unichar *characters = (unichar *)malloc(sizeof(unichar) * len);
if (convertNewlines) {
NSCharacterSet *charset = [NSCharacterSet newlineCharacterSet];
NSRange range = NSMakeRange(0, len);
size_t cIdx = 0;
while (range.length > 0) {
NSRange newlineRange = [string rangeOfCharacterFromSet:charset options:0 range:range];
if (newlineRange.location == NSNotFound) {
[string getCharacters:&characters[cIdx] range:range];
cIdx += range.length;
break;
} else {
NSUInteger delta = newlineRange.location - range.location;
if (newlineRange.location > range.location) {
[string getCharacters:&characters[cIdx] range:NSMakeRange(range.location, delta)];
}
cIdx += delta;
characters[cIdx] = (unichar)' ';
cIdx++;
delta += newlineRange.length;
range.location += delta, range.length -= delta;
if (newlineRange.length == 1 && range.length >= 1 &&
[string characterAtIndex:newlineRange.location] == (unichar)'\r' &&
[string characterAtIndex:range.location] == (unichar)'\n') {
// CRLF sequence, skip the LF
range.location += 1, range.length -= 1;
}
}
}
len = cIdx;
} else {
[string getCharacters:characters range:NSMakeRange(0, len)];
}
// Create storage for glyphs and advances
CGGlyph *glyphs;
CGFloat *advances;
{
NSUInteger maxRunLength = 0;
ZAttributeRun *a = [attributes objectAtIndex:0];
for (NSUInteger i = 1; i < [attributes count]; i++) {
ZAttributeRun *b = [attributes objectAtIndex:i];
maxRunLength = MAX(maxRunLength, b.index - a.index);
a = b;
}
maxRunLength = MAX(maxRunLength, len - a.index);
maxRunLength++; // for a potential ellipsis
glyphs = (CGGlyph *)malloc(sizeof(CGGlyph) * maxRunLength);
advances = (CGFloat *)malloc(sizeof(CGFloat) * maxRunLength);
}
// Use this table to cache all fontTable objects
CFMutableDictionaryRef fontTableMap = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
&kFontTableDictionaryValueCallBacks);
// Fetch initial style values
NSUInteger currentRunIdx = 0;
ZAttributeRun *currentRun;
NSUInteger nextRunStart;
ZFont *currentFont;
fontTable *currentTable;
#define READ_RUN() readRunInformation(attributes, len, fontTableMap, \
currentRunIdx, &currentRun, &nextRunStart, \
&currentFont, &currentTable)
READ_RUN();
// fetch the glyphs for the first run
size_t glyphCount;
NSUInteger glyphIdx;
#define READ_GLYPHS() do { \
mapCharactersToGlyphsInFont(currentTable, &characters[currentRun.index], (nextRunStart - currentRun.index), glyphs, &glyphCount); \
mapGlyphsToAdvancesInFont(currentFont, (nextRunStart - currentRun.index), glyphs, advances); \
glyphIdx = 0; \
} while (0)
READ_GLYPHS();
NSMutableCharacterSet *alphaCharset = [NSMutableCharacterSet alphanumericCharacterSet];
[alphaCharset addCharactersInString:@"([{'\"\u2019\u02BC"];
// scan left-to-right looking for newlines or until we hit the width constraint
// When we hit a wrapping point, calculate truncation as follows:
// If we have room to draw at least one more character on the next line, no truncation
// Otherwise apply the truncation algorithm to the current line.
// After calculating any truncation, draw.
// Each time we hit the end of an attribute run, calculate the new font and make sure
// it fits (vertically) within the size constraint. If not, truncate this line.
// When we draw, iterate over the attribute runs for this line and draw each run separately
BOOL lastLine = NO; // used to indicate truncation and to stop the iterating
NSUInteger lineCount = 1;
while (idx < len && !lastLine) {
if (maxLines > 0 && lineCount == maxLines) {
lastLine = YES;
}
// scan left-to-right
struct {
NSUInteger index;
NSUInteger glyphIndex;
NSUInteger currentRunIdx;
} indexCache = { idx, glyphIdx, currentRunIdx };
CGSize lineSize = CGSizeMake(0, currentFont.leading);
CGFloat lineAscender = currentFont.ascender;
struct {
NSUInteger index;
NSUInteger glyphIndex;
NSUInteger currentRunIdx;
CGSize lineSize;
} lastWrapCache = {0, 0, 0, CGSizeZero};
BOOL inAlpha = NO; // used for calculating wrap points
BOOL finishLine = NO;
for (;idx <= len && !finishLine;) {
NSUInteger skipCount = 0;
if (idx == len) {
finishLine = YES;
lastLine = YES;
} else {
if (idx >= nextRunStart) {
// cycle the font and table and grab the next set of glyphs
do {
currentRunIdx++;
READ_RUN();
} while (idx >= nextRunStart);
READ_GLYPHS();
// re-scan the characters to synchronize the glyph index
for (NSUInteger j = currentRun.index; j < idx; j++) {
if (UnicharIsHighSurrogate(characters[j]) && j+1<len && UnicharIsLowSurrogate(characters[j+1])) {
j++;
}
glyphIdx++;
}
if (currentFont.leading > lineSize.height) {
lineSize.height = currentFont.leading;
if (retValue.height + currentFont.ascender > constrainedSize.height) {
lastLine = YES;
finishLine = YES;
}
}
lineAscender = MAX(lineAscender, currentFont.ascender);
}
unichar c = characters[idx];
// Mark a wrap point before spaces and after any stretch of non-alpha characters
BOOL markWrap = NO;
if (c == (unichar)' ') {
markWrap = YES;
} else if ([alphaCharset characterIsMember:c]) {
if (!inAlpha) {
markWrap = YES;
inAlpha = YES;
}
} else {
inAlpha = NO;
}
if (markWrap) {
lastWrapCache = (__typeof__(lastWrapCache)){
.index = idx,
.glyphIndex = glyphIdx,
.currentRunIdx = currentRunIdx,
.lineSize = lineSize
};
}
// process the line
if (c == (unichar)'\n' || c == 0x0085) { // U+0085 is the NEXT_LINE unicode character
finishLine = YES;
skipCount = 1;
} else if (c == (unichar)'\r') {
finishLine = YES;
// check for CRLF
if (idx+1 < len && characters[idx+1] == (unichar)'\n') {
skipCount = 2;
} else {
skipCount = 1;
}
} else if (lineSize.width + advances[glyphIdx] > constrainedSize.width) {
finishLine = YES;
if (retValue.height + lineSize.height + currentFont.ascender > constrainedSize.height) {
lastLine = YES;
}
// walk backwards if wrapping is necessary
if (lastWrapCache.index > indexCache.index && lineBreakMode != UILineBreakModeCharacterWrap &&
(!lastLine || lineBreakMode != UILineBreakModeClip)) {
// we're doing some sort of word wrapping
idx = lastWrapCache.index;
lineSize = lastWrapCache.lineSize;
if (!lastLine) {
// re-check if this is the last line
if (lastWrapCache.currentRunIdx != currentRunIdx) {
currentRunIdx = lastWrapCache.currentRunIdx;
READ_RUN();
READ_GLYPHS();
}
if (retValue.height + lineSize.height + currentFont.ascender > constrainedSize.height) {
lastLine = YES;
}
}
glyphIdx = lastWrapCache.glyphIndex;
// skip any spaces
for (NSUInteger j = idx; j < len && characters[j] == (unichar)' '; j++) {
skipCount++;
}
}
}
}
if (finishLine) {
// TODO: support head/middle truncation
if (lastLine && idx < len && lineBreakMode == UILineBreakModeTailTruncation) {
// truncate
unichar ellipsis = 0x2026; // ellipsis ()
CGGlyph ellipsisGlyph;
mapCharactersToGlyphsInFont(currentTable, &ellipsis, 1, &ellipsisGlyph, NULL);
CGFloat ellipsisWidth;
mapGlyphsToAdvancesInFont(currentFont, 1, &ellipsisGlyph, &ellipsisWidth);
while ((idx - indexCache.index) > 1 && lineSize.width + ellipsisWidth > constrainedSize.width) {
// we have more than 1 character and we're too wide, so back up
idx--;
if (UnicharIsHighSurrogate(characters[idx]) && UnicharIsLowSurrogate(characters[idx+1])) {
idx--;
}
if (idx < currentRun.index) {
ZFont *oldFont = currentFont;
do {
currentRunIdx--;
READ_RUN();
} while (idx < currentRun.index);
READ_GLYPHS();
glyphIdx = glyphCount-1;
if (oldFont != currentFont) {
mapCharactersToGlyphsInFont(currentTable, &ellipsis, 1, &ellipsisGlyph, NULL);
mapGlyphsToAdvancesInFont(currentFont, 1, &ellipsisGlyph, &ellipsisWidth);
}
} else {
glyphIdx--;
}
lineSize.width -= advances[glyphIdx];
}
// skip any spaces before truncating
while ((idx - indexCache.index) > 1 && characters[idx-1] == (unichar)' ') {
idx--;
if (idx < currentRun.index) {
currentRunIdx--;
READ_RUN();
READ_GLYPHS();
glyphIdx = glyphCount-1;
} else {
glyphIdx--;
}
lineSize.width -= advances[glyphIdx];
}
lineSize.width += ellipsisWidth;
glyphs[glyphIdx] = ellipsisGlyph;
idx++;
glyphIdx++;
}
retValue.width = MAX(retValue.width, lineSize.width);
retValue.height += lineSize.height;
// draw
if (performDraw) {
switch (alignment) {
case UITextAlignmentLeft:
drawPoint.x = 0;
break;
case UITextAlignmentCenter:
drawPoint.x = (constrainedSize.width - lineSize.width) / 2.0f;
break;
case UITextAlignmentRight:
drawPoint.x = constrainedSize.width - lineSize.width;
break;
}
NSUInteger stopGlyphIdx = glyphIdx;
NSUInteger lastRunIdx = currentRunIdx;
NSUInteger stopCharIdx = idx;
idx = indexCache.index;
if (currentRunIdx != indexCache.currentRunIdx) {
currentRunIdx = indexCache.currentRunIdx;
READ_RUN();
READ_GLYPHS();
}
glyphIdx = indexCache.glyphIndex;
for (NSUInteger drawIdx = currentRunIdx; drawIdx <= lastRunIdx; drawIdx++) {
if (drawIdx != currentRunIdx) {
currentRunIdx = drawIdx;
READ_RUN();
READ_GLYPHS();
}
NSUInteger numGlyphs;
if (drawIdx == lastRunIdx) {
numGlyphs = stopGlyphIdx - glyphIdx;
idx = stopCharIdx;
} else {
numGlyphs = glyphCount - glyphIdx;
idx = nextRunStart;
}
CGContextSetFont(ctx, currentFont.cgFont);
CGContextSetFontSize(ctx, currentFont.pointSize);
// calculate the fragment size
CGFloat fragmentWidth = 0;
for (NSUInteger g = 0; g < numGlyphs; g++) {
fragmentWidth += advances[glyphIdx + g];
}
if (!ignoreColor) {
UIColor *foregroundColor = getValueOrDefaultForRun(currentRun, ZForegroundColorAttributeName);
UIColor *backgroundColor = getValueOrDefaultForRun(currentRun, ZBackgroundColorAttributeName);
if (backgroundColor != nil && ![backgroundColor isEqual:[UIColor clearColor]]) {
[backgroundColor setFill];
UIRectFillUsingBlendMode((CGRect){ drawPoint, { fragmentWidth, lineSize.height } }, kCGBlendModeNormal);
}
[foregroundColor setFill];
}
CGContextShowGlyphsAtPoint(ctx, drawPoint.x, drawPoint.y + lineAscender, &glyphs[glyphIdx], numGlyphs);
NSNumber *underlineStyle = getValueOrDefaultForRun(currentRun, ZUnderlineStyleAttributeName);
if ([underlineStyle integerValue] & ZUnderlineStyleMask) {
// we only support single for the time being
UIRectFill(CGRectMake(drawPoint.x, drawPoint.y + lineAscender, fragmentWidth, 1));
}
drawPoint.x += fragmentWidth;
glyphIdx += numGlyphs;
}
drawPoint.y += lineSize.height;
}
idx += skipCount;
glyphIdx += skipCount;
lineCount++;
} else {
lineSize.width += advances[glyphIdx];
glyphIdx++;
idx++;
if (idx < len && UnicharIsHighSurrogate(characters[idx-1]) && UnicharIsLowSurrogate(characters[idx])) {
// skip the second half of the surrogate pair
idx++;
}
}
}
}
CFRelease(fontTableMap);
free(glyphs);
free(advances);
free(characters);
#undef READ_GLYPHS
#undef READ_RUN
return retValue;
}
static NSArray *attributeRunForFont(ZFont *font) {
return [NSArray arrayWithObject:[ZAttributeRun attributeRunWithIndex:0
attributes:[NSDictionary dictionaryWithObject:font
forKey:ZFontAttributeName]]];
}
static CGSize drawTextInRect(CGRect rect, NSString *text, NSArray *attributes, UILineBreakMode lineBreakMode,
UITextAlignment alignment, NSUInteger numberOfLines, BOOL ignoreColor) {
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSaveGState(ctx);
// flip it upside-down because our 0,0 is upper-left, whereas ttfs are for screens where 0,0 is lower-left
CGAffineTransform textTransform = CGAffineTransformMake(1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f);
CGContextSetTextMatrix(ctx, textTransform);
CGContextTranslateCTM(ctx, rect.origin.x, rect.origin.y);
CGContextSetTextDrawingMode(ctx, kCGTextFill);
CGSize size = drawOrSizeTextConstrainedToSize(YES, text, attributes, rect.size, numberOfLines, lineBreakMode, alignment, ignoreColor);
CGContextRestoreGState(ctx);
return size;
}
@implementation NSString (FontLabelStringDrawing)
// CGFontRef-based methods
- (CGSize)sizeWithCGFont:(CGFontRef)font pointSize:(CGFloat)pointSize {
return [self sizeWithZFont:[ZFont fontWithCGFont:font size:pointSize]];
}
- (CGSize)sizeWithCGFont:(CGFontRef)font pointSize:(CGFloat)pointSize constrainedToSize:(CGSize)size {
return [self sizeWithZFont:[ZFont fontWithCGFont:font size:pointSize] constrainedToSize:size];
}
- (CGSize)sizeWithCGFont:(CGFontRef)font pointSize:(CGFloat)pointSize constrainedToSize:(CGSize)size
lineBreakMode:(UILineBreakMode)lineBreakMode {
return [self sizeWithZFont:[ZFont fontWithCGFont:font size:pointSize] constrainedToSize:size lineBreakMode:lineBreakMode];
}
- (CGSize)drawAtPoint:(CGPoint)point withCGFont:(CGFontRef)font pointSize:(CGFloat)pointSize {
return [self drawAtPoint:point withZFont:[ZFont fontWithCGFont:font size:pointSize]];
}
- (CGSize)drawInRect:(CGRect)rect withCGFont:(CGFontRef)font pointSize:(CGFloat)pointSize {
return [self drawInRect:rect withZFont:[ZFont fontWithCGFont:font size:pointSize]];
}
- (CGSize)drawInRect:(CGRect)rect withCGFont:(CGFontRef)font pointSize:(CGFloat)pointSize lineBreakMode:(UILineBreakMode)lineBreakMode {
return [self drawInRect:rect withZFont:[ZFont fontWithCGFont:font size:pointSize] lineBreakMode:lineBreakMode];
}
- (CGSize)drawInRect:(CGRect)rect withCGFont:(CGFontRef)font pointSize:(CGFloat)pointSize
lineBreakMode:(UILineBreakMode)lineBreakMode alignment:(UITextAlignment)alignment {
return [self drawInRect:rect withZFont:[ZFont fontWithCGFont:font size:pointSize] lineBreakMode:lineBreakMode alignment:alignment];
}
// ZFont-based methods
- (CGSize)sizeWithZFont:(ZFont *)font {
CGSize size = drawOrSizeTextConstrainedToSize(NO, self, attributeRunForFont(font), CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX), 1,
UILineBreakModeClip, UITextAlignmentLeft, YES);
return CGSizeMake(ceilf(size.width), ceilf(size.height));
}
- (CGSize)sizeWithZFont:(ZFont *)font constrainedToSize:(CGSize)size {
return [self sizeWithZFont:font constrainedToSize:size lineBreakMode:UILineBreakModeWordWrap];
}
/*
According to experimentation with UIStringDrawing, this can actually return a CGSize whose height is greater
than the one passed in. The two cases are as follows:
1. If the given size parameter's height is smaller than a single line, the returned value will
be the height of one line.
2. If the given size parameter's height falls between multiples of a line height, and the wrapped string
actually extends past the size.height, and the difference between size.height and the previous multiple
of a line height is >= the font's ascender, then the returned size's height is extended to the next line.
To put it simply, if the baseline point of a given line falls in the given size, the entire line will
be present in the output size.
*/
- (CGSize)sizeWithZFont:(ZFont *)font constrainedToSize:(CGSize)size lineBreakMode:(UILineBreakMode)lineBreakMode {
size = drawOrSizeTextConstrainedToSize(NO, self, attributeRunForFont(font), size, 0, lineBreakMode, UITextAlignmentLeft, YES);
return CGSizeMake(ceilf(size.width), ceilf(size.height));
}
- (CGSize)sizeWithZFont:(ZFont *)font constrainedToSize:(CGSize)size lineBreakMode:(UILineBreakMode)lineBreakMode
numberOfLines:(NSUInteger)numberOfLines {
size = drawOrSizeTextConstrainedToSize(NO, self, attributeRunForFont(font), size, numberOfLines, lineBreakMode, UITextAlignmentLeft, YES);
return CGSizeMake(ceilf(size.width), ceilf(size.height));
}
- (CGSize)drawAtPoint:(CGPoint)point withZFont:(ZFont *)font {
return [self drawAtPoint:point forWidth:CGFLOAT_MAX withZFont:font lineBreakMode:UILineBreakModeClip];
}
- (CGSize)drawAtPoint:(CGPoint)point forWidth:(CGFloat)width withZFont:(ZFont *)font lineBreakMode:(UILineBreakMode)lineBreakMode {
return drawTextInRect((CGRect){ point, { width, CGFLOAT_MAX } }, self, attributeRunForFont(font), lineBreakMode, UITextAlignmentLeft, 1, YES);
}
- (CGSize)drawInRect:(CGRect)rect withZFont:(ZFont *)font {
return [self drawInRect:rect withZFont:font lineBreakMode:UILineBreakModeWordWrap];
}
- (CGSize)drawInRect:(CGRect)rect withZFont:(ZFont *)font lineBreakMode:(UILineBreakMode)lineBreakMode {
return [self drawInRect:rect withZFont:font lineBreakMode:lineBreakMode alignment:UITextAlignmentLeft];
}
- (CGSize)drawInRect:(CGRect)rect withZFont:(ZFont *)font lineBreakMode:(UILineBreakMode)lineBreakMode
alignment:(UITextAlignment)alignment {
return drawTextInRect(rect, self, attributeRunForFont(font), lineBreakMode, alignment, 0, YES);
}
- (CGSize)drawInRect:(CGRect)rect withZFont:(ZFont *)font lineBreakMode:(UILineBreakMode)lineBreakMode
alignment:(UITextAlignment)alignment numberOfLines:(NSUInteger)numberOfLines {
return drawTextInRect(rect, self, attributeRunForFont(font), lineBreakMode, alignment, numberOfLines, YES);
}
@end
@implementation ZAttributedString (ZAttributedStringDrawing)
- (CGSize)size {
CGSize size = drawOrSizeTextConstrainedToSize(NO, self.string, self.attributes, CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX), 1,
UILineBreakModeClip, UITextAlignmentLeft, NO);
return CGSizeMake(ceilf(size.width), ceilf(size.height));
}
- (CGSize)sizeConstrainedToSize:(CGSize)size {
return [self sizeConstrainedToSize:size lineBreakMode:UILineBreakModeWordWrap];
}
- (CGSize)sizeConstrainedToSize:(CGSize)size lineBreakMode:(UILineBreakMode)lineBreakMode {
size = drawOrSizeTextConstrainedToSize(NO, self.string, self.attributes, size, 0, lineBreakMode, UITextAlignmentLeft, NO);
return CGSizeMake(ceilf(size.width), ceilf(size.height));
}
- (CGSize)sizeConstrainedToSize:(CGSize)size lineBreakMode:(UILineBreakMode)lineBreakMode
numberOfLines:(NSUInteger)numberOfLines {
size = drawOrSizeTextConstrainedToSize(NO, self.string, self.attributes, size, numberOfLines, lineBreakMode, UITextAlignmentLeft, NO);
return CGSizeMake(ceilf(size.width), ceilf(size.height));
}
- (CGSize)drawAtPoint:(CGPoint)point {
return [self drawAtPoint:point forWidth:CGFLOAT_MAX lineBreakMode:UILineBreakModeClip];
}
- (CGSize)drawAtPoint:(CGPoint)point forWidth:(CGFloat)width lineBreakMode:(UILineBreakMode)lineBreakMode {
return drawTextInRect((CGRect){ point, { width, CGFLOAT_MAX } }, self.string, self.attributes, lineBreakMode, UITextAlignmentLeft, 1, NO);
}
- (CGSize)drawInRect:(CGRect)rect {
return [self drawInRect:rect withLineBreakMode:UILineBreakModeWordWrap];
}
- (CGSize)drawInRect:(CGRect)rect withLineBreakMode:(UILineBreakMode)lineBreakMode {
return [self drawInRect:rect withLineBreakMode:lineBreakMode alignment:UITextAlignmentLeft];
}
- (CGSize)drawInRect:(CGRect)rect withLineBreakMode:(UILineBreakMode)lineBreakMode alignment:(UITextAlignment)alignment {
return drawTextInRect(rect, self.string, self.attributes, lineBreakMode, alignment, 0, NO);
}
- (CGSize)drawInRect:(CGRect)rect withLineBreakMode:(UILineBreakMode)lineBreakMode alignment:(UITextAlignment)alignment
numberOfLines:(NSUInteger)numberOfLines {
return drawTextInRect(rect, self.string, self.attributes, lineBreakMode, alignment, numberOfLines, NO);
}
@end
@implementation FontLabelStringDrawingHelper
+ (CGSize)sizeWithZFont:(NSString*)string zfont:(ZFont *)font {
CGSize size = drawOrSizeTextConstrainedToSize(NO, string, attributeRunForFont(font), CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX), 1,
UILineBreakModeClip, UITextAlignmentLeft, YES);
return CGSizeMake(ceilf(size.width), ceilf(size.height));
}
+ (CGSize)drawInRect:(NSString*)string rect:(CGRect)rect withZFont:(ZFont *)font lineBreakMode:(UILineBreakMode)lineBreakMode
alignment:(UITextAlignment)alignment {
return [string drawInRect:rect withZFont:font lineBreakMode:lineBreakMode alignment:alignment];
}
@end

View File

@ -0,0 +1,85 @@
//
// FontManager.h
// FontLabel
//
// Created by Kevin Ballard on 5/5/09.
// Copyright © 2009 Zynga Game Networks
//
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#import <Foundation/Foundation.h>
#import <CoreGraphics/CoreGraphics.h>
@class ZFont;
@interface FontManager : NSObject {
CFMutableDictionaryRef fonts;
NSMutableDictionary *urls;
}
+ (FontManager *)sharedManager;
/*!
@method
@abstract Loads a TTF font from the main bundle
@param filename The name of the font file to load (with or without extension).
@return YES if the font was loaded, NO if an error occurred
@discussion If the font has already been loaded, this method does nothing and returns YES.
This method first attempts to load the font by appending .ttf to the filename.
If that file does not exist, it tries the filename exactly as given.
*/
- (BOOL)loadFont:(NSString *)filename;
/*!
@method
@abstract Loads a font from the given file URL
@param url A file URL that points to a font file
@return YES if the font was loaded, NO if an error occurred
@discussion If the font has already been loaded, this method does nothing and returns YES.
*/
- (BOOL)loadFontURL:(NSURL *)url;
/*!
@method
@abstract Returns the loaded font with the given filename
@param filename The name of the font file that was given to -loadFont:
@return A CGFontRef, or NULL if the specified font cannot be found
@discussion If the font has not been loaded yet, -loadFont: will be
called with the given name first.
*/
- (CGFontRef)fontWithName:(NSString *)filename __AVAILABILITY_INTERNAL_DEPRECATED;
/*!
@method
@abstract Returns a ZFont object corresponding to the loaded font with the given filename and point size
@param filename The name of the font file that was given to -loadFont:
@param pointSize The point size of the font
@return A ZFont, or NULL if the specified font cannot be found
@discussion If the font has not been loaded yet, -loadFont: will be
called with the given name first.
*/
- (ZFont *)zFontWithName:(NSString *)filename pointSize:(CGFloat)pointSize;
/*!
@method
@abstract Returns a ZFont object corresponding to the loaded font with the given file URL and point size
@param url A file URL that points to a font file
@param pointSize The point size of the font
@return A ZFont, or NULL if the specified font cannot be loaded
@discussion If the font has not been loaded yet, -loadFontURL: will be called with the given URL first.
*/
- (ZFont *)zFontWithURL:(NSURL *)url pointSize:(CGFloat)pointSize;
/*!
@method
@abstract Returns a CFArrayRef of all loaded CGFont objects
@return A CFArrayRef of all loaded CGFont objects
@description You are responsible for releasing the CFArrayRef
*/
- (CFArrayRef)copyAllFonts;
@end

View File

@ -0,0 +1,123 @@
//
// FontManager.m
// FontLabel
//
// Created by Kevin Ballard on 5/5/09.
// Copyright © 2009 Zynga Game Networks
//
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#import "FontManager.h"
#import "ZFont.h"
static FontManager *sharedFontManager = nil;
@implementation FontManager
+ (FontManager *)sharedManager {
@synchronized(self) {
if (sharedFontManager == nil) {
sharedFontManager = [[self alloc] init];
}
}
return sharedFontManager;
}
- (id)init {
if ((self = [super init])) {
fonts = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
urls = [[NSMutableDictionary alloc] init];
}
return self;
}
- (BOOL)loadFont:(NSString *)filename {
NSString *fontPath = [[NSBundle mainBundle] pathForResource:filename ofType:@"ttf"];
if (fontPath == nil) {
fontPath = [[NSBundle mainBundle] pathForResource:filename ofType:nil];
}
if (fontPath == nil) return NO;
NSURL *url = [NSURL fileURLWithPath:fontPath];
if ([self loadFontURL:url]) {
[urls setObject:url forKey:filename];
return YES;
}
return NO;
}
- (BOOL)loadFontURL:(NSURL *)url {
CGDataProviderRef fontDataProvider = CGDataProviderCreateWithURL((CFURLRef)url);
if (fontDataProvider == NULL) return NO;
CGFontRef newFont = CGFontCreateWithDataProvider(fontDataProvider);
CGDataProviderRelease(fontDataProvider);
if (newFont == NULL) return NO;
CFDictionarySetValue(fonts, url, newFont);
CGFontRelease(newFont);
return YES;
}
- (CGFontRef)fontWithName:(NSString *)filename {
CGFontRef font = NULL;
NSURL *url = [urls objectForKey:filename];
if (url == nil && [self loadFont:filename]) {
url = [urls objectForKey:filename];
}
if (url != nil) {
font = (CGFontRef)CFDictionaryGetValue(fonts, url);
}
return font;
}
- (ZFont *)zFontWithName:(NSString *)filename pointSize:(CGFloat)pointSize {
NSURL *url = [urls objectForKey:filename];
if (url == nil && [self loadFont:filename]) {
url = [urls objectForKey:filename];
}
if (url != nil) {
CGFontRef cgFont = (CGFontRef)CFDictionaryGetValue(fonts, url);
if (cgFont != NULL) {
return [ZFont fontWithCGFont:cgFont size:pointSize];
}
}
return nil;
}
- (ZFont *)zFontWithURL:(NSURL *)url pointSize:(CGFloat)pointSize {
CGFontRef cgFont = (CGFontRef)CFDictionaryGetValue(fonts, url);
if (cgFont == NULL && [self loadFontURL:url]) {
cgFont = (CGFontRef)CFDictionaryGetValue(fonts, url);
}
if (cgFont != NULL) {
return [ZFont fontWithCGFont:cgFont size:pointSize];
}
return nil;
}
- (CFArrayRef)copyAllFonts {
CFIndex count = CFDictionaryGetCount(fonts);
CGFontRef *values = (CGFontRef *)malloc(sizeof(CGFontRef) * count);
CFDictionaryGetKeysAndValues(fonts, NULL, (const void **)values);
CFArrayRef array = CFArrayCreate(NULL, (const void **)values, count, &kCFTypeArrayCallBacks);
free(values);
return array;
}
- (void)dealloc {
CFRelease(fonts);
[urls release];
[super dealloc];
}
@end

View File

@ -0,0 +1,77 @@
//
// ZAttributedString.h
// FontLabel
//
// Created by Kevin Ballard on 9/22/09.
// Copyright 2009 Zynga Game Networks. All rights reserved.
//
#import <Foundation/Foundation.h>
#if NS_BLOCKS_AVAILABLE
#define Z_BLOCKS 1
#else
// set this to 1 if you are using PLBlocks
#define Z_BLOCKS 0
#endif
#if Z_BLOCKS
enum {
ZAttributedStringEnumerationReverse = (1UL << 1),
ZAttributedStringEnumerationLongestEffectiveRangeNotRequired = (1UL << 20)
};
typedef NSUInteger ZAttributedStringEnumerationOptions;
#endif
@interface ZAttributedString : NSObject <NSCoding, NSCopying, NSMutableCopying> {
NSMutableString *_buffer;
NSMutableArray *_attributes;
}
@property (nonatomic, readonly) NSUInteger length;
@property (nonatomic, readonly) NSString *string;
- (id)initWithAttributedString:(ZAttributedString *)attr;
- (id)initWithString:(NSString *)str;
- (id)initWithString:(NSString *)str attributes:(NSDictionary *)attributes;
- (id)attribute:(NSString *)attributeName atIndex:(NSUInteger)index effectiveRange:(NSRangePointer)aRange;
- (id)attribute:(NSString *)attributeName atIndex:(NSUInteger)index longestEffectiveRange:(NSRangePointer)aRange inRange:(NSRange)rangeLimit;
- (ZAttributedString *)attributedSubstringFromRange:(NSRange)aRange;
- (NSDictionary *)attributesAtIndex:(NSUInteger)index effectiveRange:(NSRangePointer)aRange;
- (NSDictionary *)attributesAtIndex:(NSUInteger)index longestEffectiveRange:(NSRangePointer)aRange inRange:(NSRange)rangeLimit;
#if Z_BLOCKS
- (void)enumerateAttribute:(NSString *)attrName inRange:(NSRange)enumerationRange options:(ZAttributedStringEnumerationOptions)opts
usingBlock:(void (^)(id value, NSRange range, BOOL *stop))block;
- (void)enumerateAttributesInRange:(NSRange)enumerationRange options:(ZAttributedStringEnumerationOptions)opts
usingBlock:(void (^)(NSDictionary *attrs, NSRange range, BOOL *stop))block;
#endif
- (BOOL)isEqualToAttributedString:(ZAttributedString *)otherString;
@end
@interface ZMutableAttributedString : ZAttributedString {
}
- (void)addAttribute:(NSString *)name value:(id)value range:(NSRange)range;
- (void)addAttributes:(NSDictionary *)attributes range:(NSRange)range;
- (void)appendAttributedString:(ZAttributedString *)str;
- (void)deleteCharactersInRange:(NSRange)range;
- (void)insertAttributedString:(ZAttributedString *)str atIndex:(NSUInteger)idx;
- (void)removeAttribute:(NSString *)name range:(NSRange)range;
- (void)replaceCharactersInRange:(NSRange)range withAttributedString:(ZAttributedString *)str;
- (void)replaceCharactersInRange:(NSRange)range withString:(NSString *)str;
- (void)setAttributedString:(ZAttributedString *)str;
- (void)setAttributes:(NSDictionary *)attributes range:(NSRange)range;
@end
extern NSString * const ZFontAttributeName;
extern NSString * const ZForegroundColorAttributeName;
extern NSString * const ZBackgroundColorAttributeName;
extern NSString * const ZUnderlineStyleAttributeName;
enum {
ZUnderlineStyleNone = 0x00,
ZUnderlineStyleSingle = 0x01
};
#define ZUnderlineStyleMask 0x00FF
enum {
ZUnderlinePatternSolid = 0x0000
};
#define ZUnderlinePatternMask 0xFF00

View File

@ -0,0 +1,597 @@
//
// ZAttributedString.m
// FontLabel
//
// Created by Kevin Ballard on 9/22/09.
// Copyright 2009 Zynga Game Networks. All rights reserved.
//
#import "ZAttributedString.h"
#import "ZAttributedStringPrivate.h"
@interface ZAttributedString ()
- (NSUInteger)indexOfEffectiveAttributeRunForIndex:(NSUInteger)index;
- (NSDictionary *)attributesAtIndex:(NSUInteger)index effectiveRange:(NSRangePointer)aRange uniquingOnName:(NSString *)attributeName;
- (NSDictionary *)attributesAtIndex:(NSUInteger)index longestEffectiveRange:(NSRangePointer)aRange
inRange:(NSRange)rangeLimit uniquingOnName:(NSString *)attributeName;
@end
@interface ZAttributedString ()
@property (nonatomic, readonly) NSArray *attributes;
@end
@implementation ZAttributedString
@synthesize string = _buffer;
@synthesize attributes = _attributes;
- (id)initWithAttributedString:(ZAttributedString *)attr {
NSParameterAssert(attr != nil);
if ((self = [super init])) {
_buffer = [attr->_buffer mutableCopy];
_attributes = [[NSMutableArray alloc] initWithArray:attr->_attributes copyItems:YES];
}
return self;
}
- (id)initWithString:(NSString *)str {
return [self initWithString:str attributes:nil];
}
- (id)initWithString:(NSString *)str attributes:(NSDictionary *)attributes {
if ((self = [super init])) {
_buffer = [str mutableCopy];
_attributes = [[NSMutableArray alloc] initWithObjects:[ZAttributeRun attributeRunWithIndex:0 attributes:attributes], nil];
}
return self;
}
- (id)init {
return [self initWithString:@"" attributes:nil];
}
- (id)initWithCoder:(NSCoder *)decoder {
if ((self = [super init])) {
_buffer = [[decoder decodeObjectForKey:@"buffer"] mutableCopy];
_attributes = [[decoder decodeObjectForKey:@"attributes"] mutableCopy];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder {
[aCoder encodeObject:_buffer forKey:@"buffer"];
[aCoder encodeObject:_attributes forKey:@"attributes"];
}
- (id)copyWithZone:(NSZone *)zone {
return [self retain];
}
- (id)mutableCopyWithZone:(NSZone *)zone {
return [(ZMutableAttributedString *)[ZMutableAttributedString allocWithZone:zone] initWithAttributedString:self];
}
- (NSUInteger)length {
return [_buffer length];
}
- (NSString *)description {
NSMutableArray *components = [NSMutableArray arrayWithCapacity:[_attributes count]*2];
NSRange range = NSMakeRange(0, 0);
for (NSUInteger i = 0; i <= [_attributes count]; i++) {
range.location = NSMaxRange(range);
ZAttributeRun *run;
if (i < [_attributes count]) {
run = [_attributes objectAtIndex:i];
range.length = run.index - range.location;
} else {
run = nil;
range.length = [_buffer length] - range.location;
}
if (range.length > 0) {
[components addObject:[NSString stringWithFormat:@"\"%@\"", [_buffer substringWithRange:range]]];
}
if (run != nil) {
NSMutableArray *attrDesc = [NSMutableArray arrayWithCapacity:[run.attributes count]];
for (id key in run.attributes) {
[attrDesc addObject:[NSString stringWithFormat:@"%@: %@", key, [run.attributes objectForKey:key]]];
}
[components addObject:[NSString stringWithFormat:@"{%@}", [attrDesc componentsJoinedByString:@", "]]];
}
}
return [NSString stringWithFormat:@"%@", [components componentsJoinedByString:@" "]];
}
- (id)attribute:(NSString *)attributeName atIndex:(NSUInteger)index effectiveRange:(NSRangePointer)aRange {
NSParameterAssert(attributeName != nil);
return [[self attributesAtIndex:index effectiveRange:aRange uniquingOnName:attributeName] objectForKey:attributeName];
}
- (id)attribute:(NSString *)attributeName atIndex:(NSUInteger)index longestEffectiveRange:(NSRangePointer)aRange inRange:(NSRange)rangeLimit {
NSParameterAssert(attributeName != nil);
return [[self attributesAtIndex:index longestEffectiveRange:aRange inRange:rangeLimit uniquingOnName:attributeName] objectForKey:attributeName];
}
- (ZAttributedString *)attributedSubstringFromRange:(NSRange)aRange {
if (NSMaxRange(aRange) > [_buffer length]) {
@throw [NSException exceptionWithName:NSRangeException reason:@"range was outisde of the attributed string" userInfo:nil];
}
ZMutableAttributedString *newStr = [self mutableCopy];
if (aRange.location > 0) {
[newStr deleteCharactersInRange:NSMakeRange(0, aRange.location)];
}
if (NSMaxRange(aRange) < [_buffer length]) {
[newStr deleteCharactersInRange:NSMakeRange(aRange.length, [_buffer length] - NSMaxRange(aRange))];
}
return [newStr autorelease];
}
- (NSDictionary *)attributesAtIndex:(NSUInteger)index effectiveRange:(NSRangePointer)aRange {
return [NSDictionary dictionaryWithDictionary:[self attributesAtIndex:index effectiveRange:aRange uniquingOnName:nil]];
}
- (NSDictionary *)attributesAtIndex:(NSUInteger)index longestEffectiveRange:(NSRangePointer)aRange inRange:(NSRange)rangeLimit {
return [NSDictionary dictionaryWithDictionary:[self attributesAtIndex:index longestEffectiveRange:aRange inRange:rangeLimit uniquingOnName:nil]];
}
#if Z_BLOCKS
// Warning: this code has not been tested. The only guarantee is that it compiles.
- (void)enumerateAttribute:(NSString *)attrName inRange:(NSRange)enumerationRange options:(ZAttributedStringEnumerationOptions)opts
usingBlock:(void (^)(id, NSRange, BOOL*))block {
if (opts & ZAttributedStringEnumerationLongestEffectiveRangeNotRequired) {
[self enumerateAttributesInRange:enumerationRange options:opts usingBlock:^(NSDictionary *attrs, NSRange range, BOOL *stop) {
id value = [attrs objectForKey:attrName];
if (value != nil) {
block(value, range, stop);
}
}];
} else {
__block id oldValue = nil;
__block NSRange effectiveRange = NSMakeRange(0, 0);
[self enumerateAttributesInRange:enumerationRange options:opts usingBlock:^(NSDictionary *attrs, NSRange range, BOOL *stop) {
id value = [attrs objectForKey:attrName];
if (oldValue == nil) {
oldValue = value;
effectiveRange = range;
} else if (value != nil && [oldValue isEqual:value]) {
// combine the attributes
effectiveRange = NSUnionRange(effectiveRange, range);
} else {
BOOL innerStop = NO;
block(oldValue, effectiveRange, &innerStop);
if (innerStop) {
*stop = YES;
oldValue = nil;
} else {
oldValue = value;
}
}
}];
if (oldValue != nil) {
BOOL innerStop = NO; // necessary for the block, but unused
block(oldValue, effectiveRange, &innerStop);
}
}
}
- (void)enumerateAttributesInRange:(NSRange)enumerationRange options:(ZAttributedStringEnumerationOptions)opts
usingBlock:(void (^)(NSDictionary*, NSRange, BOOL*))block {
// copy the attributes so we can mutate the string if necessary during enumeration
// also clip the array during copy to only the subarray of attributes that cover the requested range
NSArray *attrs;
if (NSEqualRanges(enumerationRange, NSMakeRange(0, 0))) {
attrs = [NSArray arrayWithArray:_attributes];
} else {
// in this binary search, last is the first run after the range
NSUInteger first = 0, last = [_attributes count];
while (last > first+1) {
NSUInteger pivot = (last + first) / 2;
ZAttributeRun *run = [_attributes objectAtIndex:pivot];
if (run.index < enumerationRange.location) {
first = pivot;
} else if (run.index >= NSMaxRange(enumerationRange)) {
last = pivot;
}
}
attrs = [_attributes subarrayWithRange:NSMakeRange(first, last-first)];
}
if (opts & ZAttributedStringEnumerationReverse) {
NSUInteger end = [_buffer length];
for (ZAttributeRun *run in [attrs reverseObjectEnumerator]) {
BOOL stop = NO;
NSUInteger start = run.index;
// clip to enumerationRange
start = MAX(start, enumerationRange.location);
end = MIN(end, NSMaxRange(enumerationRange));
block(run.attributes, NSMakeRange(start, end - start), &stop);
if (stop) break;
end = run.index;
}
} else {
NSUInteger start = 0;
ZAttributeRun *run = [attrs objectAtIndex:0];
NSInteger offset = 0;
NSInteger oldLength = [_buffer length];
for (NSUInteger i = 1;;i++) {
NSUInteger end;
if (i >= [attrs count]) {
end = oldLength;
} else {
end = [[attrs objectAtIndex:i] index];
}
BOOL stop = NO;
NSUInteger clippedStart = MAX(start, enumerationRange.location);
NSUInteger clippedEnd = MIN(end, NSMaxRange(enumerationRange));
block(run.attributes, NSMakeRange(clippedStart + offset, clippedEnd - start), &stop);
if (stop || i >= [attrs count]) break;
start = end;
NSUInteger newLength = [_buffer length];
offset += (newLength - oldLength);
oldLength = newLength;
}
}
}
#endif
- (BOOL)isEqualToAttributedString:(ZAttributedString *)otherString {
return ([_buffer isEqualToString:otherString->_buffer] && [_attributes isEqualToArray:otherString->_attributes]);
}
- (BOOL)isEqual:(id)object {
return [object isKindOfClass:[ZAttributedString class]] && [self isEqualToAttributedString:(ZAttributedString *)object];
}
#pragma mark -
- (NSUInteger)indexOfEffectiveAttributeRunForIndex:(NSUInteger)index {
NSUInteger first = 0, last = [_attributes count];
while (last > first + 1) {
NSUInteger pivot = (last + first) / 2;
ZAttributeRun *run = [_attributes objectAtIndex:pivot];
if (run.index > index) {
last = pivot;
} else if (run.index < index) {
first = pivot;
} else {
first = pivot;
break;
}
}
return first;
}
- (NSDictionary *)attributesAtIndex:(NSUInteger)index effectiveRange:(NSRangePointer)aRange uniquingOnName:(NSString *)attributeName {
if (index >= [_buffer length]) {
@throw [NSException exceptionWithName:NSRangeException reason:@"index beyond range of attributed string" userInfo:nil];
}
NSUInteger runIndex = [self indexOfEffectiveAttributeRunForIndex:index];
ZAttributeRun *run = [_attributes objectAtIndex:runIndex];
if (aRange != NULL) {
aRange->location = run.index;
runIndex++;
if (runIndex < [_attributes count]) {
aRange->length = [[_attributes objectAtIndex:runIndex] index] - aRange->location;
} else {
aRange->length = [_buffer length] - aRange->location;
}
}
return run.attributes;
}
- (NSDictionary *)attributesAtIndex:(NSUInteger)index longestEffectiveRange:(NSRangePointer)aRange
inRange:(NSRange)rangeLimit uniquingOnName:(NSString *)attributeName {
if (index >= [_buffer length]) {
@throw [NSException exceptionWithName:NSRangeException reason:@"index beyond range of attributed string" userInfo:nil];
} else if (NSMaxRange(rangeLimit) > [_buffer length]) {
@throw [NSException exceptionWithName:NSRangeException reason:@"rangeLimit beyond range of attributed string" userInfo:nil];
}
NSUInteger runIndex = [self indexOfEffectiveAttributeRunForIndex:index];
ZAttributeRun *run = [_attributes objectAtIndex:runIndex];
if (aRange != NULL) {
if (attributeName != nil) {
id value = [run.attributes objectForKey:attributeName];
NSUInteger endRunIndex = runIndex+1;
runIndex--;
// search backwards
while (1) {
if (run.index <= rangeLimit.location) {
break;
}
ZAttributeRun *prevRun = [_attributes objectAtIndex:runIndex];
id prevValue = [prevRun.attributes objectForKey:attributeName];
if (prevValue == value || (value != nil && [prevValue isEqual:value])) {
runIndex--;
run = prevRun;
} else {
break;
}
}
// search forwards
ZAttributeRun *endRun = nil;
while (endRunIndex < [_attributes count]) {
ZAttributeRun *nextRun = [_attributes objectAtIndex:endRunIndex];
if (nextRun.index >= NSMaxRange(rangeLimit)) {
endRun = nextRun;
break;
}
id nextValue = [nextRun.attributes objectForKey:attributeName];
if (nextValue == value || (value != nil && [nextValue isEqual:value])) {
endRunIndex++;
} else {
endRun = nextRun;
break;
}
}
aRange->location = MAX(run.index, rangeLimit.location);
aRange->length = MIN((endRun ? endRun.index : [_buffer length]), NSMaxRange(rangeLimit)) - aRange->location;
} else {
// with no attribute name, we don't need to do any real searching,
// as we already guarantee each run has unique attributes.
// just make sure to clip the range to the rangeLimit
aRange->location = MAX(run.index, rangeLimit.location);
ZAttributeRun *endRun = (runIndex+1 < [_attributes count] ? [_attributes objectAtIndex:runIndex+1] : nil);
aRange->length = MIN((endRun ? endRun.index : [_buffer length]), NSMaxRange(rangeLimit)) - aRange->location;
}
}
return run.attributes;
}
- (void)dealloc {
[_buffer release];
[_attributes release];
[super dealloc];
}
@end
@interface ZMutableAttributedString ()
- (void)cleanupAttributesInRange:(NSRange)range;
- (NSRange)rangeOfAttributeRunsForRange:(NSRange)range;
- (void)offsetRunsInRange:(NSRange )range byOffset:(NSInteger)offset;
@end
@implementation ZMutableAttributedString
- (id)copyWithZone:(NSZone *)zone {
return [(ZAttributedString *)[ZAttributedString allocWithZone:zone] initWithAttributedString:self];
}
- (void)addAttribute:(NSString *)name value:(id)value range:(NSRange)range {
range = [self rangeOfAttributeRunsForRange:range];
for (ZAttributeRun *run in [_attributes subarrayWithRange:range]) {
[run.attributes setObject:value forKey:name];
}
[self cleanupAttributesInRange:range];
}
- (void)addAttributes:(NSDictionary *)attributes range:(NSRange)range {
range = [self rangeOfAttributeRunsForRange:range];
for (ZAttributeRun *run in [_attributes subarrayWithRange:range]) {
[run.attributes addEntriesFromDictionary:attributes];
}
[self cleanupAttributesInRange:range];
}
- (void)appendAttributedString:(ZAttributedString *)str {
[self insertAttributedString:str atIndex:[_buffer length]];
}
- (void)deleteCharactersInRange:(NSRange)range {
NSRange runRange = [self rangeOfAttributeRunsForRange:range];
[_buffer replaceCharactersInRange:range withString:@""];
[_attributes removeObjectsInRange:runRange];
for (NSUInteger i = runRange.location; i < [_attributes count]; i++) {
ZAttributeRun *run = [_attributes objectAtIndex:i];
ZAttributeRun *newRun = [[ZAttributeRun alloc] initWithIndex:(run.index - range.length) attributes:run.attributes];
[_attributes replaceObjectAtIndex:i withObject:newRun];
[newRun release];
}
[self cleanupAttributesInRange:NSMakeRange(runRange.location, 0)];
}
- (void)insertAttributedString:(ZAttributedString *)str atIndex:(NSUInteger)idx {
[self replaceCharactersInRange:NSMakeRange(idx, 0) withAttributedString:str];
}
- (void)removeAttribute:(NSString *)name range:(NSRange)range {
range = [self rangeOfAttributeRunsForRange:range];
for (ZAttributeRun *run in [_attributes subarrayWithRange:range]) {
[run.attributes removeObjectForKey:name];
}
[self cleanupAttributesInRange:range];
}
- (void)replaceCharactersInRange:(NSRange)range withAttributedString:(ZAttributedString *)str {
NSRange replaceRange = [self rangeOfAttributeRunsForRange:range];
NSInteger offset = [str->_buffer length] - range.length;
[_buffer replaceCharactersInRange:range withString:str->_buffer];
[_attributes replaceObjectsInRange:replaceRange withObjectsFromArray:str->_attributes];
NSRange newRange = NSMakeRange(replaceRange.location, [str->_attributes count]);
[self offsetRunsInRange:newRange byOffset:range.location];
[self offsetRunsInRange:NSMakeRange(NSMaxRange(newRange), [_attributes count] - NSMaxRange(newRange)) byOffset:offset];
[self cleanupAttributesInRange:NSMakeRange(newRange.location, 0)];
[self cleanupAttributesInRange:NSMakeRange(NSMaxRange(newRange), 0)];
}
- (void)replaceCharactersInRange:(NSRange)range withString:(NSString *)str {
[self replaceCharactersInRange:range withAttributedString:[[[ZAttributedString alloc] initWithString:str] autorelease]];
}
- (void)setAttributedString:(ZAttributedString *)str {
[_buffer release], _buffer = [str->_buffer mutableCopy];
[_attributes release], _attributes = [str->_attributes mutableCopy];
}
- (void)setAttributes:(NSDictionary *)attributes range:(NSRange)range {
range = [self rangeOfAttributeRunsForRange:range];
for (ZAttributeRun *run in [_attributes subarrayWithRange:range]) {
[run.attributes setDictionary:attributes];
}
[self cleanupAttributesInRange:range];
}
#pragma mark -
// splits the existing runs to provide one or more new runs for the given range
- (NSRange)rangeOfAttributeRunsForRange:(NSRange)range {
NSParameterAssert(NSMaxRange(range) <= [_buffer length]);
// find (or create) the first run
NSUInteger first = 0;
ZAttributeRun *lastRun = nil;
for (;;first++) {
if (first >= [_attributes count]) {
// we didn't find a run
first = [_attributes count];
ZAttributeRun *newRun = [[ZAttributeRun alloc] initWithIndex:range.location attributes:lastRun.attributes];
[_attributes addObject:newRun];
[newRun release];
break;
}
ZAttributeRun *run = [_attributes objectAtIndex:first];
if (run.index == range.location) {
break;
} else if (run.index > range.location) {
ZAttributeRun *newRun = [[ZAttributeRun alloc] initWithIndex:range.location attributes:lastRun.attributes];
[_attributes insertObject:newRun atIndex:first];
[newRun release];
break;
}
lastRun = run;
}
if (((ZAttributeRun *)[_attributes lastObject]).index < NSMaxRange(range)) {
NSRange subrange = NSMakeRange(first, [_attributes count] - first);
if (NSMaxRange(range) < [_buffer length]) {
ZAttributeRun *newRun = [[ZAttributeRun alloc] initWithIndex:NSMaxRange(range)
attributes:(NSDictionary*)[(ZAttributeRun *)[_attributes lastObject] attributes]];
[_attributes addObject:newRun];
[newRun release];
}
return subrange;
} else {
// find the last run within and the first run after the range
NSUInteger lastIn = first, firstAfter = [_attributes count]-1;
while (firstAfter > lastIn + 1) {
NSUInteger idx = (firstAfter + lastIn) / 2;
ZAttributeRun *run = [_attributes objectAtIndex:idx];
if (run.index < range.location) {
lastIn = idx;
} else if (run.index > range.location) {
firstAfter = idx;
} else {
// this is definitively the first run after the range
firstAfter = idx;
break;
}
}
if ([[_attributes objectAtIndex:firstAfter] index] > NSMaxRange(range)) {
// the first after is too far after, insert another run!
ZAttributeRun *newRun = [[ZAttributeRun alloc] initWithIndex:NSMaxRange(range)
attributes:[(ZAttributeRun *)[_attributes objectAtIndex:firstAfter-1] attributes]];
[_attributes insertObject:newRun atIndex:firstAfter];
[newRun release];
}
return NSMakeRange(lastIn, firstAfter - lastIn);
}
}
- (void)cleanupAttributesInRange:(NSRange)range {
// expand the range to include one surrounding attribute on each side
if (range.location > 0) {
range.location -= 1;
range.length += 1;
}
if (NSMaxRange(range) < [_attributes count]) {
range.length += 1;
} else {
// make sure the range is capped to the attributes count
range.length = [_attributes count] - range.location;
}
if (range.length == 0) return;
ZAttributeRun *lastRun = [_attributes objectAtIndex:range.location];
for (NSUInteger i = range.location+1; i < NSMaxRange(range);) {
ZAttributeRun *run = [_attributes objectAtIndex:i];
if ([lastRun.attributes isEqualToDictionary:run.attributes]) {
[_attributes removeObjectAtIndex:i];
range.length -= 1;
} else {
lastRun = run;
i++;
}
}
}
- (void)offsetRunsInRange:(NSRange)range byOffset:(NSInteger)offset {
for (NSUInteger i = range.location; i < NSMaxRange(range); i++) {
ZAttributeRun *run = [_attributes objectAtIndex:i];
ZAttributeRun *newRun = [[ZAttributeRun alloc] initWithIndex:run.index + offset attributes:run.attributes];
[_attributes replaceObjectAtIndex:i withObject:newRun];
[newRun release];
}
}
@end
@implementation ZAttributeRun
@synthesize index = _index;
@synthesize attributes = _attributes;
+ (id)attributeRunWithIndex:(NSUInteger)idx attributes:(NSDictionary *)attrs {
return [[[self alloc] initWithIndex:idx attributes:attrs] autorelease];
}
- (id)initWithIndex:(NSUInteger)idx attributes:(NSDictionary *)attrs {
NSParameterAssert(idx >= 0);
if ((self = [super init])) {
_index = idx;
if (attrs == nil) {
_attributes = [[NSMutableDictionary alloc] init];
} else {
_attributes = [attrs mutableCopy];
}
}
return self;
}
- (id)initWithCoder:(NSCoder *)decoder {
if ((self = [super init])) {
_index = [[decoder decodeObjectForKey:@"index"] unsignedIntegerValue];
_attributes = [[decoder decodeObjectForKey:@"attributes"] mutableCopy];
}
return self;
}
- (id)init {
return [self initWithIndex:0 attributes:[NSDictionary dictionary]];
}
- (id)copyWithZone:(NSZone *)zone {
return [[ZAttributeRun allocWithZone:zone] initWithIndex:_index attributes:_attributes];
}
- (void)encodeWithCoder:(NSCoder *)aCoder {
[aCoder encodeObject:[NSNumber numberWithUnsignedInteger:_index] forKey:@"index"];
[aCoder encodeObject:_attributes forKey:@"attributes"];
}
- (NSString *)description {
NSMutableArray *components = [NSMutableArray arrayWithCapacity:[_attributes count]];
for (id key in _attributes) {
[components addObject:[NSString stringWithFormat:@"%@=%@", key, [_attributes objectForKey:key]]];
}
return [NSString stringWithFormat:@"<%@: %p index=%lu attributes={%@}>",
NSStringFromClass([self class]), self, (unsigned long)_index, [components componentsJoinedByString:@" "]];
}
- (BOOL)isEqual:(id)object {
if (![object isKindOfClass:[ZAttributeRun class]]) return NO;
ZAttributeRun *other = (ZAttributeRun *)object;
return _index == other->_index && [_attributes isEqualToDictionary:other->_attributes];
}
- (void)dealloc {
[_attributes release];
[super dealloc];
}
@end
NSString * const ZFontAttributeName = @"ZFontAttributeName";
NSString * const ZForegroundColorAttributeName = @"ZForegroundColorAttributeName";
NSString * const ZBackgroundColorAttributeName = @"ZBackgroundColorAttributeName";
NSString * const ZUnderlineStyleAttributeName = @"ZUnderlineStyleAttributeName";

View File

@ -0,0 +1,24 @@
//
// ZAttributedStringPrivate.h
// FontLabel
//
// Created by Kevin Ballard on 9/23/09.
// Copyright 2009 Zynga Game Networks. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "ZAttributedString.h"
@interface ZAttributeRun : NSObject <NSCopying, NSCoding> {
NSUInteger _index;
NSMutableDictionary *_attributes;
}
@property (nonatomic, readonly) NSUInteger index;
@property (nonatomic, readonly) NSMutableDictionary *attributes;
+ (id)attributeRunWithIndex:(NSUInteger)idx attributes:(NSDictionary *)attrs;
- (id)initWithIndex:(NSUInteger)idx attributes:(NSDictionary *)attrs;
@end
@interface ZAttributedString (ZAttributedStringPrivate)
@property (nonatomic, readonly) NSArray *attributes;
@end

View File

@ -0,0 +1,47 @@
//
// ZFont.h
// FontLabel
//
// Created by Kevin Ballard on 7/2/09.
// Copyright © 2009 Zynga Game Networks
//
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface ZFont : NSObject {
CGFontRef _cgFont;
CGFloat _pointSize;
CGFloat _ratio;
NSString *_familyName;
NSString *_fontName;
NSString *_postScriptName;
}
@property (nonatomic, readonly) CGFontRef cgFont;
@property (nonatomic, readonly) CGFloat pointSize;
@property (nonatomic, readonly) CGFloat ascender;
@property (nonatomic, readonly) CGFloat descender;
@property (nonatomic, readonly) CGFloat leading;
@property (nonatomic, readonly) CGFloat xHeight;
@property (nonatomic, readonly) CGFloat capHeight;
@property (nonatomic, readonly) NSString *familyName;
@property (nonatomic, readonly) NSString *fontName;
@property (nonatomic, readonly) NSString *postScriptName;
+ (ZFont *)fontWithCGFont:(CGFontRef)cgFont size:(CGFloat)fontSize;
+ (ZFont *)fontWithUIFont:(UIFont *)uiFont;
- (id)initWithCGFont:(CGFontRef)cgFont size:(CGFloat)fontSize;
- (ZFont *)fontWithSize:(CGFloat)fontSize;
@end

View File

@ -0,0 +1,170 @@
//
// ZFont.m
// FontLabel
//
// Created by Kevin Ballard on 7/2/09.
// Copyright © 2009 Zynga Game Networks
//
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#import "ZFont.h"
@interface ZFont ()
@property (nonatomic, readonly) CGFloat ratio;
- (NSString *)copyNameTableEntryForID:(UInt16)nameID;
@end
@implementation ZFont
@synthesize cgFont=_cgFont, pointSize=_pointSize, ratio=_ratio;
+ (ZFont *)fontWithCGFont:(CGFontRef)cgFont size:(CGFloat)fontSize {
return [[[self alloc] initWithCGFont:cgFont size:fontSize] autorelease];
}
+ (ZFont *)fontWithUIFont:(UIFont *)uiFont {
NSParameterAssert(uiFont != nil);
CGFontRef cgFont = CGFontCreateWithFontName((CFStringRef)uiFont.fontName);
ZFont *zFont = [[self alloc] initWithCGFont:cgFont size:uiFont.pointSize];
CGFontRelease(cgFont);
return [zFont autorelease];
}
- (id)initWithCGFont:(CGFontRef)cgFont size:(CGFloat)fontSize {
if ((self = [super init])) {
_cgFont = CGFontRetain(cgFont);
_pointSize = fontSize;
_ratio = fontSize/CGFontGetUnitsPerEm(cgFont);
}
return self;
}
- (id)init {
NSAssert(NO, @"-init is not valid for ZFont");
return nil;
}
- (CGFloat)ascender {
return ceilf(self.ratio * CGFontGetAscent(self.cgFont));
}
- (CGFloat)descender {
return floorf(self.ratio * CGFontGetDescent(self.cgFont));
}
- (CGFloat)leading {
return (self.ascender - self.descender);
}
- (CGFloat)capHeight {
return ceilf(self.ratio * CGFontGetCapHeight(self.cgFont));
}
- (CGFloat)xHeight {
return ceilf(self.ratio * CGFontGetXHeight(self.cgFont));
}
- (NSString *)familyName {
if (_familyName == nil) {
_familyName = [self copyNameTableEntryForID:1];
}
return _familyName;
}
- (NSString *)fontName {
if (_fontName == nil) {
_fontName = [self copyNameTableEntryForID:4];
}
return _fontName;
}
- (NSString *)postScriptName {
if (_postScriptName == nil) {
_postScriptName = [self copyNameTableEntryForID:6];
}
return _postScriptName;
}
- (ZFont *)fontWithSize:(CGFloat)fontSize {
if (fontSize == self.pointSize) return self;
NSParameterAssert(fontSize > 0.0);
return [[[ZFont alloc] initWithCGFont:self.cgFont size:fontSize] autorelease];
}
- (BOOL)isEqual:(id)object {
if (![object isKindOfClass:[ZFont class]]) return NO;
ZFont *font = (ZFont *)object;
return (font.cgFont == self.cgFont && font.pointSize == self.pointSize);
}
- (NSString *)copyNameTableEntryForID:(UInt16)aNameID {
CFDataRef nameTable = CGFontCopyTableForTag(self.cgFont, 'name');
NSAssert1(nameTable != NULL, @"CGFontCopyTableForTag returned NULL for 'name' tag in font %@",
[(id)CFCopyDescription(self.cgFont) autorelease]);
const UInt8 * const bytes = CFDataGetBytePtr(nameTable);
NSAssert1(OSReadBigInt16(bytes, 0) == 0, @"name table for font %@ has bad version number",
[(id)CFCopyDescription(self.cgFont) autorelease]);
const UInt16 count = OSReadBigInt16(bytes, 2);
const UInt16 stringOffset = OSReadBigInt16(bytes, 4);
const UInt8 * const nameRecords = &bytes[6];
UInt16 nameLength = 0;
UInt16 nameOffset = 0;
NSStringEncoding encoding = 0;
for (UInt16 idx = 0; idx < count; idx++) {
const uintptr_t recordOffset = 12 * idx;
const UInt16 nameID = OSReadBigInt16(nameRecords, recordOffset + 6);
if (nameID != aNameID) continue;
const UInt16 platformID = OSReadBigInt16(nameRecords, recordOffset + 0);
const UInt16 platformSpecificID = OSReadBigInt16(nameRecords, recordOffset + 2);
encoding = 0;
// for now, we only support a subset of encodings
switch (platformID) {
case 0: // Unicode
encoding = NSUTF16StringEncoding;
break;
case 1: // Macintosh
switch (platformSpecificID) {
case 0:
encoding = NSMacOSRomanStringEncoding;
break;
}
case 3: // Microsoft
switch (platformSpecificID) {
case 1:
encoding = NSUTF16StringEncoding;
break;
}
}
if (encoding == 0) continue;
nameLength = OSReadBigInt16(nameRecords, recordOffset + 8);
nameOffset = OSReadBigInt16(nameRecords, recordOffset + 10);
break;
}
NSString *result = nil;
if (nameOffset > 0) {
const UInt8 *nameBytes = &bytes[stringOffset + nameOffset];
result = [[NSString alloc] initWithBytes:nameBytes length:nameLength encoding:encoding];
}
CFRelease(nameTable);
return result;
}
- (void)dealloc {
CGFontRelease(_cgFont);
[_familyName release];
[_fontName release];
[_postScriptName release];
[super dealloc];
}
@end

View File

@ -148,18 +148,6 @@ void CCFileUtils::setResource(const char* pszZipFileName)
CCAssert(0, "Have not implement!");
}
const char* CCFileUtils::getResourcePath(void)
{
CCAssert(0, "Have not implement!");
return NULL;
}
void CCFileUtils::setRelativePath(const char* pszRelativePath)
{
CC_UNUSED_PARAM(pszRelativePath);
CCAssert(0, "Have not implement!");
}
string CCFileUtils::getWriteablePath()
{
// return the path that the exe file saved in

View File

@ -34,7 +34,9 @@ public:
: m_hDC(NULL)
, m_hBmp(NULL)
, m_hFont((HFONT)GetStockObject(DEFAULT_GUI_FONT))
, m_hWnd(NULL)
{
m_hWnd = hWnd;
HDC hdc = GetDC(hWnd);
m_hDC = CreateCompatibleDC(hdc);
ReleaseDC(hWnd, hdc);
@ -53,20 +55,67 @@ public:
DeleteObject(m_hFont);
m_hFont = hDefFont;
}
// release temp font resource
if (m_curFontPath.size() > 0)
{
wchar_t * pwszBuffer = utf8ToUtf16(m_curFontPath);
if (pwszBuffer)
{
RemoveFontResource(pwszBuffer);
SendMessage( m_hWnd, 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);
} 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 (pFontName)
{
strcpy_s(tNewFont.lfFaceName, LF_FACESIZE, pFontName);
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 = CCFileUtils::fullPathFromRelativePath(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)
{
@ -86,6 +135,31 @@ public:
if (m_hFont != hDefFont)
{
DeleteObject(m_hFont);
// release old font register
if (m_curFontPath.size() > 0)
{
wchar_t * pwszBuffer = utf8ToUtf16(m_curFontPath);
if (pwszBuffer)
{
RemoveFontResource(pwszBuffer);
SendMessage( m_hWnd, WM_FONTCHANGE, 0, 0);
delete [] pwszBuffer;
pwszBuffer = NULL;
}
}
fontPath.size()>0?(m_curFontPath = fontPath):(m_curFontPath.clear());
// register temp font
if (m_curFontPath.size() > 0)
{
wchar_t * pwszBuffer = utf8ToUtf16(m_curFontPath);
if (pwszBuffer)
{
AddFontResource(pwszBuffer);
SendMessage( m_hWnd, WM_FONTCHANGE, 0, 0);
delete [] pwszBuffer;
pwszBuffer = NULL;
}
}
}
m_hFont = NULL;
@ -267,6 +341,8 @@ public:
private:
friend class CCImage;
HFONT m_hFont;
HWND m_hWnd;
std::string m_curFontPath;
};
static BitmapDC& sharedBitmapDC()

View File

@ -247,17 +247,6 @@ void CCFileUtils::setResourcePath(const char *pszResourcePath)
CCAssert(0, "Have not implement!");
}
const char* CCFileUtils::getResourcePath(void)
{
CCAssert(0, "Have not implement!");
return NULL;
}
void CCFileUtils::setRelativePath(const char* pszRelativePath)
{
CCAssert(0, "Have not implement!");
}
string CCFileUtils::getWriteablePath()
{
return string(CCApplication::sharedApplication().getAppWritablePath());

View File

@ -24,6 +24,7 @@ THE SOFTWARE.
#include "TG3.h"
#include <string>
#include "CCApplication.h"
NS_CC_BEGIN
@ -35,6 +36,7 @@ public:
BitmapDC()
: m_pBmp(NULL)
, m_pMemWnd(NULL)
, m_pFont(NULL)
{
}
@ -42,16 +44,59 @@ public:
~BitmapDC(void)
{
prepareBitmap(0, 0);
if (m_pFont)
{
delete m_pFont;
m_pFont = NULL;
}
}
bool setFont(const char * pFontName = NULL, int nSize = 0)
{
bool bRet = false;
TFont * pNewFont = new TFont;
do
{
CC_BREAK_IF(! m_hFont.Create(0, (Int32)nSize));
bRet = true;
if (NULL == pFontName)
{
break;
}
TUChar szFullPath[MAX_PATH] = {0};
std::string fullpath;
#ifdef _TRANZDA_VM_
fullpath = pFontName;
CCLog("++fullpath %s",fullpath.c_str());
fullpath = CCFileUtils::fullPathFromRelativePath(fullpath.c_str());
CCLog("--fullpath %s",fullpath.c_str());
fullpath = &fullpath.c_str()[strlen("D:/Work7")];
#else
fullpath = CCApplication::sharedApplication().getAppDataPath();
fullpath += pFontName;
#endif
TUString::StrGBToUnicode(szFullPath,(const Char*)fullpath.c_str());
CCLog("path %s,++pNewFont->Create",fullpath.c_str());
CC_BREAK_IF(! pNewFont->Create(szFullPath,0, (Int32)nSize,0,NULL));
CCLog("path %s,--pNewFont->Create",fullpath.c_str());
bRet = true;
} while (0);
// create default font
if (!bRet &&
pNewFont->Create(0, (Int32)nSize))
{
bRet = true;
}
// delete old font
if (bRet)
{
if (m_pFont)
{
delete m_pFont;
m_pFont = NULL;
}
m_pFont = pNewFont;
}
return bRet;
}
@ -96,7 +141,7 @@ public:
}
// calculate the width of current line and update the window width
int nTempWidth = m_hFont.CharsWidth(strLine.c_str(), strLine.length() + 1);
int nTempWidth = m_pFont->CharsWidth(strLine.c_str(), strLine.length() + 1);
if (nTempWidth >= nWinWidth)
{
nWinWidth = nTempWidth;
@ -115,14 +160,14 @@ public:
int nCurPos = 0;
do
{
nCurPos = m_hFont.WordWrap(strLeft.c_str(), nWinWidth);
nCurPos = m_pFont->WordWrap(strLeft.c_str(), nWinWidth);
strLeft = strLeft.substr(nCurPos);
++nLineCount;
} while (strLeft.length() > 0);
}
// calculate the window height.
tSize.SetHeight(nLineCount * m_hFont.LineHeight());
tSize.SetHeight(nLineCount * m_pFont->LineHeight());
tSize.SetWidth(nWinWidth);
bRet = true;
@ -205,7 +250,7 @@ public:
m_pMemWnd->GetMemWindowTBitmapPtr()->Fill32(RGBA(0, 0, 0, 0), 0, 0, nWidth, nHeight);
TRectangle rect(0, 0, nWidth, nHeight);
dc.DrawTextInRectangleEx(pszText, 0, RGBA(255,255,255,255), RGBA(0,0,0,255), m_hFont, &rect, style);
dc.DrawTextInRectangleEx(pszText, 0, RGBA(255,255,255,255), RGBA(0,0,0,255), *m_pFont, &rect, style);
dc.ReadBitmap(m_pBmp, 0, 0);
@ -217,7 +262,7 @@ public:
CC_SYNTHESIZE_READONLY(TBitmap*, m_pBmp, Bitmap);
private:
TFont m_hFont;
TFont * m_pFont;
TWindow * m_pMemWnd;
};

View File

@ -93,6 +93,7 @@ OBJECTS = \
$(OBJECTS_DIR)/CCAccelerometer_wophone.o \
$(OBJECTS_DIR)/CCApplication_wophone.o \
$(OBJECTS_DIR)/CCEGLView_wophone.o \
$(OBJECTS_DIR)/CCScriptSupport.o \
$(OBJECTS_DIR)/CCAnimation.o \
$(OBJECTS_DIR)/CCAnimationCache.o \
$(OBJECTS_DIR)/CCSprite.o \
@ -115,6 +116,7 @@ OBJECTS = \
$(OBJECTS_DIR)/CCTexture2D.o \
$(OBJECTS_DIR)/CCTextureAtlas.o \
$(OBJECTS_DIR)/CCTextureCache.o \
$(OBJECTS_DIR)/CCTexturePVR.o \
$(OBJECTS_DIR)/CCParallaxNode.o \
$(OBJECTS_DIR)/CCTileMapAtlas.o \
$(OBJECTS_DIR)/CCTMXLayer.o \
@ -122,8 +124,7 @@ OBJECTS = \
$(OBJECTS_DIR)/CCTMXTiledMap.o \
$(OBJECTS_DIR)/CCTMXXMLParser.o \
$(OBJECTS_DIR)/CCTouchDispatcher.o \
$(OBJECTS_DIR)/CCTouchHandler.o \
$(OBJECTS_DIR)/CCScriptSupport.o
$(OBJECTS_DIR)/CCTouchHandler.o
ADD_OBJECTS +=
@ -325,6 +326,9 @@ $(OBJECTS_DIR)/CCApplication_wophone.o : ../platform/wophone/CCApplication_wopho
$(OBJECTS_DIR)/CCEGLView_wophone.o : ../platform/wophone/CCEGLView_wophone.cpp
$(CXX) -c $(CXX_FLAGS) $(INCLUDE_PATH) $(LAST_INCLUDE_PATH) -o $(OBJECTS_DIR)/CCEGLView_wophone.o ../platform/wophone/CCEGLView_wophone.cpp
$(OBJECTS_DIR)/CCScriptSupport.o : ../script_support/CCScriptSupport.cpp
$(CXX) -c $(CXX_FLAGS) $(INCLUDE_PATH) $(LAST_INCLUDE_PATH) -o $(OBJECTS_DIR)/CCScriptSupport.o ../script_support/CCScriptSupport.cpp
$(OBJECTS_DIR)/CCAnimation.o : ../sprite_nodes/CCAnimation.cpp
$(CXX) -c $(CXX_FLAGS) $(INCLUDE_PATH) $(LAST_INCLUDE_PATH) -o $(OBJECTS_DIR)/CCAnimation.o ../sprite_nodes/CCAnimation.cpp
@ -391,6 +395,9 @@ $(OBJECTS_DIR)/CCTextureAtlas.o : ../textures/CCTextureAtlas.cpp
$(OBJECTS_DIR)/CCTextureCache.o : ../textures/CCTextureCache.cpp
$(CXX) -c $(CXX_FLAGS) $(INCLUDE_PATH) $(LAST_INCLUDE_PATH) -o $(OBJECTS_DIR)/CCTextureCache.o ../textures/CCTextureCache.cpp
$(OBJECTS_DIR)/CCTexturePVR.o : ../textures/CCTexturePVR.cpp
$(CXX) -c $(CXX_FLAGS) $(INCLUDE_PATH) $(LAST_INCLUDE_PATH) -o $(OBJECTS_DIR)/CCTexturePVR.o ../textures/CCTexturePVR.cpp
$(OBJECTS_DIR)/CCParallaxNode.o : ../tileMap_parallax_nodes/CCParallaxNode.cpp
$(CXX) -c $(CXX_FLAGS) $(INCLUDE_PATH) $(LAST_INCLUDE_PATH) -o $(OBJECTS_DIR)/CCParallaxNode.o ../tileMap_parallax_nodes/CCParallaxNode.cpp
@ -415,5 +422,3 @@ $(OBJECTS_DIR)/CCTouchDispatcher.o : ../touch_dispatcher/CCTouchDispatcher.cpp
$(OBJECTS_DIR)/CCTouchHandler.o : ../touch_dispatcher/CCTouchHandler.cpp
$(CXX) -c $(CXX_FLAGS) $(INCLUDE_PATH) $(LAST_INCLUDE_PATH) -o $(OBJECTS_DIR)/CCTouchHandler.o ../touch_dispatcher/CCTouchHandler.cpp
$(OBJECTS_DIR)/CCScriptSupport.o : ../script_support/CCScriptSupport.cpp
$(CXX) -c $(CXX_FLAGS) $(INCLUDE_PATH) $(LAST_INCLUDE_PATH) -o $(OBJECTS_DIR)/CCScriptSupport.o ../script_support/CCScriptSupport.cpp

View File

@ -65,42 +65,6 @@ namespace cocos2d
return pAnimation;
}
CCAnimation* CCAnimation::animationWithName(const char *pszName)
{
CCAnimation *pAnimation = new CCAnimation();
pAnimation->initWithName(pszName);
pAnimation->autorelease();
return pAnimation;
}
CCAnimation* CCAnimation::animationWithName(const char *pszName, CCMutableArray<CCSpriteFrame*> *pFrames)
{
CCAnimation *pAnimation = new CCAnimation();
pAnimation->initWithName(pszName, pFrames);
pAnimation->autorelease();
return pAnimation;
}
CCAnimation* CCAnimation::animationWithName(const char *pszName, float fDelay, CCMutableArray<CCSpriteFrame*> *pFrames)
{
CCAnimation *pAnimation = new CCAnimation();
pAnimation->initWithName(pszName, fDelay, pFrames);
pAnimation->autorelease();
return pAnimation;
}
CCAnimation* CCAnimation::animationWithName(const char *pszName, float fDelay)
{
CCAnimation *pAnimation = new CCAnimation();
pAnimation->initWithName(pszName, fDelay);
pAnimation->autorelease();
return pAnimation;
}
bool CCAnimation::initWithFrames(CCMutableArray<CCSpriteFrame*> *pFrames, float delay)
{
m_fDelay = delay;
@ -115,31 +79,6 @@ namespace cocos2d
return initWithFrames(pFrames, 0);
}
bool CCAnimation::initWithName(const char *pszName)
{
return initWithName(pszName, 0, NULL);
}
bool CCAnimation::initWithName(const char *pszName, float fDelay)
{
return initWithName(pszName, fDelay, NULL);
}
bool CCAnimation::initWithName(const char *pszName, CCMutableArray<CCSpriteFrame*> *pFrames)
{
return initWithName(pszName, 0, pFrames);
}
bool CCAnimation::initWithName(const char *pszName, float fDelay, CCMutableArray<CCSpriteFrame*> *pFrames)
{
m_fDelay = fDelay;
m_nameStr = pszName;
m_pobFrames = CCMutableArray<CCSpriteFrame*>::arrayWithArray(pFrames);
m_pobFrames->retain();
return true;
}
CCAnimation::~CCAnimation(void)
{
CCLOGINFO("cocos2d, deallocing %p", this);

View File

@ -195,11 +195,8 @@ bool CCSprite::init(void)
m_bFlipX = m_bFlipY = false;
// lazy alloc
m_pAnimations = NULL;
// default transform anchor: center
m_tAnchorPoint = ccp(0.5f, 0.5f);
setAnchorPoint(ccp(0.5f, 0.5f));
// zwoptex default values
m_obOffsetPositionInPixels = CCPointZero;
@ -332,7 +329,6 @@ CCSprite::CCSprite()
CCSprite::~CCSprite(void)
{
CC_SAFE_RELEASE(m_pobTexture);
CC_SAFE_RELEASE(m_pAnimations);
}
void CCSprite::useSelfRender(void)
@ -360,11 +356,6 @@ void CCSprite::useBatchNode(CCSpriteBatchNode *batchNode)
m_pobBatchNode = batchNode;
}
void CCSprite::initAnimationDictionary(void)
{
m_pAnimations = new CCMutableDictionary<string, CCAnimation*>();
}
void CCSprite::setTextureRect(CCRect rect)
{
CCRect rectInPixels = CC_RECT_POINTS_TO_PIXELS(rect);
@ -1039,22 +1030,6 @@ void CCSprite::setDisplayFrame(CCSpriteFrame *pNewFrame)
setTextureRectInPixels(pNewFrame->getRectInPixels(), pNewFrame->isRotated(), pNewFrame->getOriginalSizeInPixels());
}
// XXX deprecated
void CCSprite::setDisplayFrame(const char *pszAnimationName, int nFrameIndex)
{
if (! m_pAnimations)
{
initAnimationDictionary();
}
CCAnimation *pAnimation = m_pAnimations->objectForKey(std::string(pszAnimationName));
CCSpriteFrame *pFrame = pAnimation->getFrames()->getObjectAtIndex(nFrameIndex);
assert(pFrame);
setDisplayFrame(pFrame);
}
void CCSprite::setDisplayFrameWithAnimationName(const char *animationName, int frameIndex)
{
assert(animationName);
@ -1087,24 +1062,6 @@ CCSpriteFrame* CCSprite::displayedFrame(void)
m_tContentSizeInPixels);
}
void CCSprite::addAnimation(CCAnimation *pAnimation)
{
// lazy alloc
if (! m_pAnimations)
{
initAnimationDictionary();
}
m_pAnimations->setObject(pAnimation, pAnimation->getName());
}
CCAnimation* CCSprite::animationByName(const char *pszAnimationName)
{
assert(pszAnimationName != NULL);
return m_pAnimations->objectForKey(std::string(pszAnimationName));
}
// Texture protocol
void CCSprite::updateBlendFunc(void)

View File

@ -48,11 +48,6 @@ namespace cocos2d
return batchNode;
}
CCSpriteBatchNode* CCSpriteBatchNode::spriteSheetWithTexture(cocos2d::CCTexture2D *tex)
{
return batchNodeWithTexture(tex);
}
CCSpriteBatchNode* CCSpriteBatchNode::batchNodeWithTexture(CCTexture2D* tex, unsigned int capacity)
{
CCSpriteBatchNode *batchNode = new CCSpriteBatchNode();
@ -62,11 +57,6 @@ namespace cocos2d
return batchNode;
}
CCSpriteBatchNode* CCSpriteBatchNode::spriteSheetWithTexture(CCTexture2D *tex, unsigned int capacity)
{
return batchNodeWithTexture(tex, capacity);
}
/*
* creation with File Image
*/
@ -79,11 +69,6 @@ namespace cocos2d
return batchNode;
}
CCSpriteBatchNode* CCSpriteBatchNode::spriteSheetWithFile(const char *fileImage, unsigned int capacity)
{
return batchNodeWithFile(fileImage, capacity);
}
CCSpriteBatchNode* CCSpriteBatchNode::batchNodeWithFile(const char *fileImage)
{
CCSpriteBatchNode *batchNode = new CCSpriteBatchNode();
@ -93,11 +78,6 @@ namespace cocos2d
return batchNode;
}
CCSpriteBatchNode* CCSpriteBatchNode::spriteSheetWithFile(const char *fileImage)
{
return batchNodeWithFile(fileImage);
}
/*
* init with CCTexture2D
*/
@ -170,25 +150,6 @@ namespace cocos2d
glPopMatrix();
}
// xxx deprecated
CCSprite* CCSpriteBatchNode::createSpriteWithRect(CCRect rect)
{
CCSprite *pSprite = CCSprite::spriteWithTexture(m_pobTextureAtlas->getTexture(), rect);
pSprite->useBatchNode(this);
return pSprite;
}
// XXX deprecated
void CCSpriteBatchNode::initSprite(cocos2d::CCSprite *sprite, cocos2d::CCRect rect)
{
if (sprite)
{
sprite->initWithTexture(m_pobTextureAtlas->getTexture(), rect);
sprite->useBatchNode(this);
}
}
void CCSpriteBatchNode::addChild(CCNode *child, int zOrder, int tag)
{
assert(child != NULL);
@ -266,7 +227,7 @@ namespace cocos2d
CCSprite* pChild = (CCSprite*) pObject;
if (pChild)
{
pChild->useSelfRender();
removeSpriteFromAtlas(pChild);
}
}
}

View File

@ -388,11 +388,6 @@ CCSpriteFrame* CCSpriteFrameCache::spriteFrameByName(const char *pszName)
return frame;
}
CCSprite* CCSpriteFrameCache::createSpriteWithFrameName(const char *pszName)
{
CCSpriteFrame *frame = m_pSpriteFrames->objectForKey(std::string(pszName));
return CCSprite::spriteWithSpriteFrame(frame);
}
const char * CCSpriteFrameCache::valueForKey(const char *key, CCDictionary<std::string, CCObject*> *dict)
{
if (dict)

View File

@ -148,26 +148,24 @@ void CCUserDefault::purgeSharedUserDefault()
m_spUserDefault = NULL;
}
bool CCUserDefault::getBoolForKey(const char* pKey)
bool CCUserDefault::getBoolForKey(const char* pKey, bool defaultValue)
{
const char* value = getValueForKey(pKey);
bool ret = false;
bool ret = defaultValue;
if (value)
{
if (! strcmp(value, "true"))
{
ret = true;
}
ret = (! strcmp(value, "true"));
xmlFree((void*)value);
}
return ret;
}
int CCUserDefault::getIntegerForKey(const char* pKey)
int CCUserDefault::getIntegerForKey(const char* pKey, int defaultValue)
{
const char* value = getValueForKey(pKey);
int ret = 0;
int ret = defaultValue;
if (value)
{
@ -178,17 +176,17 @@ int CCUserDefault::getIntegerForKey(const char* pKey)
return ret;
}
float CCUserDefault::getFloatForKey(const char* pKey)
float CCUserDefault::getFloatForKey(const char* pKey, float defaultValue)
{
float ret = (float)getDoubleForKey(pKey);
float ret = (float)getDoubleForKey(pKey, (double)defaultValue);
return ret;
}
double CCUserDefault::getDoubleForKey(const char* pKey)
double CCUserDefault::getDoubleForKey(const char* pKey, double defaultValue)
{
const char* value = getValueForKey(pKey);
double ret = 0.0;
double ret = defaultValue;
if (value)
{
@ -199,10 +197,10 @@ double CCUserDefault::getDoubleForKey(const char* pKey)
return ret;
}
string CCUserDefault::getStringForKey(const char* pKey)
string CCUserDefault::getStringForKey(const char* pKey, const std::string & defaultValue)
{
const char* value = getValueForKey(pKey);
string ret("");
string ret = defaultValue;
if (value)
{
@ -264,7 +262,7 @@ void CCUserDefault::setDoubleForKey(const char* pKey, double value)
setValueForKey(pKey, tmp);
}
void CCUserDefault::setStringForKey(const char* pKey, std::string value)
void CCUserDefault::setStringForKey(const char* pKey, const std::string & value)
{
// check key
if (! pKey)

View File

@ -445,7 +445,8 @@ void CCTextureCache::removeTextureForKey(const char *textureKeyName)
CCTexture2D* CCTextureCache::textureForKey(const char* key)
{
return m_pTextures->objectForKey(string(key));
std::string strKey = CCFileUtils::fullPathFromRelativePath(key);
return m_pTextures->objectForKey(strKey);
}
void CCTextureCache::reloadAllTextures()

View File

@ -227,11 +227,6 @@ namespace cocos2d{
return NULL;
}
// XXX deprecated
CCTMXObjectGroup * CCTMXTiledMap::groupNamed(const char *groupName)
{
return objectGroupNamed(groupName);
}
CCString * CCTMXTiledMap::propertyNamed(const char *propertyName)
{
return m_pProperties->objectForKey(std::string(propertyName));

View File

@ -19,8 +19,8 @@ fi
# the bash file should not be called by cygwin
UNIX_NAME=`uname -o`
if [ $UNIX_NAME = "Cygwin" ];then
KERNEL_NAME=`uname -s | grep "CYGWIN*"`
if [ $KERNEL_NAME"hi" != "hi" ]; then
echo "Error!!!"
echo "Don't run in cygwin. You should run corresponding bat."
exit

View File

@ -65,6 +65,7 @@ copy_src_and_jni(){
copy_build_native(){
# here should use # instead of /, why??
sed "s#__cocos2dxroot__#$COCOS2DX_ROOT#;s#__ndkroot__#$NDK_ROOT#;s#__projectname__#$APP_NAME#" $COCOS2DX_ROOT/template/android/build_native.sh > $APP_DIR/android/build_native.sh
chmod u+x $APP_DIR/android/build_native.sh
}
# replace AndroidManifext.xml and change the activity name

View File

@ -6,7 +6,7 @@
// Copyright ___ORGANIZATIONNAME___ ___YEAR___. All rights reserved.
//
#include "___PROJECTNAMEASIDENTIFIER___AppDelegate.h"
#include "AppDelegate.h"
#include "cocos2d.h"
#include "HelloWorldScene.h"

View File

@ -1 +1 @@
6616770f7d0487bf12f076293d27d5ef5f11af1e
fd240a3cf678487c690dd028abcba1a5ff1a3c6c

View File

@ -6,7 +6,7 @@
// Copyright ___ORGANIZATIONNAME___ ___YEAR___. All rights reserved.
//
#include "___PROJECTNAMEASIDENTIFIER___AppDelegate.h"
#include "AppDelegate.h"
#include "cocos2d.h"
#include "HelloWorldScene.h"

View File

@ -1 +1 @@
55a23e272c4ae52bb22a27f5bd0f4309bcb4c683
e11ed677bce9b5ea1798fdbfff120ddba0182dd9

View File

@ -6,7 +6,7 @@
// Copyright ___ORGANIZATIONNAME___ ___YEAR___. All rights reserved.
//
#include "___PROJECTNAMEASIDENTIFIER___AppDelegate.h"
#include "AppDelegate.h"
#include "cocos2d.h"
#include "HelloWorldScene.h"

View File

@ -1 +1 @@
e927644074613ed3644c897bdb0912660335380e
bd9603372ffc87e1e3fc5cb80030bdc28112f961

View File

@ -1 +1 @@
99f6132989ba063c7d343a1b0b27799df3d2f280
4f2f642918e859dde3db5a24ebb9484634f1d2fc

View File

@ -52,6 +52,7 @@ LOCAL_SRC_FILES := main.cpp \
../../../tests/EaseActionsTest/EaseActionsTest.cpp \
../../../tests/EffectsAdvancedTest/EffectsAdvancedTest.cpp \
../../../tests/EffectsTest/EffectsTest.cpp \
../../../tests/FontTest/FontTest.cpp \
../../../tests/HiResTest/HiResTest.cpp \
../../../tests/IntervalTest/IntervalTest.cpp \
../../../tests/KeypadTest/KeypadTest.cpp \

View File

@ -8,8 +8,6 @@
using namespace cocos2d;
#define IMG_PATH "assets"
extern "C"
{
@ -23,8 +21,6 @@ void Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeInit(JNIEnv* env, jobject thi
// view->create(480, 320);
cocos2d::CCDirector::sharedDirector()->setOpenGLView(view);
CCFileUtils::setRelativePath(IMG_PATH);
AppDelegate *pAppDelegate = new AppDelegate();
cocos2d::CCApplication::sharedApplication().run();
}

View File

@ -83,6 +83,9 @@ public class Cocos2dxActivity extends Activity{
backgroundMusicPlayer = new Cocos2dxMusic(this);
soundPlayer = new Cocos2dxSound(this);
// init bitmap context
Cocos2dxBitmap.setContext(this);
handler = new Handler(){
public void handleMessage(Message msg){
switch(msg.what){

View File

@ -4,6 +4,7 @@ import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.LinkedList;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
@ -11,6 +12,7 @@ import android.graphics.Paint;
import android.graphics.Typeface;
import android.graphics.Paint.Align;
import android.graphics.Paint.FontMetricsInt;
import android.util.Log;
public class Cocos2dxBitmap{
/*
@ -21,6 +23,12 @@ public class Cocos2dxBitmap{
private static final int ALIGNLEFT = 0x31;
private static final int ALIGNRIGHT = 0x32;
private static Context context;
public static void setContext(Context context){
Cocos2dxBitmap.context = context;
}
/*
* @width: the width to draw, it can be 0
* @height: the height to draw, it can be 0
@ -31,7 +39,7 @@ public class Cocos2dxBitmap{
content = refactorString(content);
Paint paint = newPaint(fontName, fontSize, alignment);
TextProperty textProperty = getTextWidthAndHeight(content, paint, width, height);
TextProperty textProperty = computeTextProperty(content, paint, width, height);
// Draw text to bitmap
Bitmap bitmap = Bitmap.createBitmap(textProperty.maxWidth,
@ -95,7 +103,7 @@ public class Cocos2dxBitmap{
}
}
private static TextProperty getTextWidthAndHeight(String content, Paint paint,
private static TextProperty computeTextProperty(String content, Paint paint,
int maxWidth, int maxHeight){
FontMetricsInt fm = paint.getFontMetricsInt();
int h = (int)Math.ceil(fm.descent - fm.ascent);
@ -117,8 +125,7 @@ public class Cocos2dxBitmap{
maxContentWidth = temp;
}
}
}
}
return new TextProperty(maxContentWidth, h, lines);
}
@ -231,10 +238,10 @@ public class Cocos2dxBitmap{
}
/*
* Add the last char
* Add the last chars
*/
if (start == charLength - 1){
strList.add(content.substring(charLength-1));
if (start < charLength){
strList.add(content.substring(start));
}
return strList;
@ -243,9 +250,29 @@ public class Cocos2dxBitmap{
private static Paint newPaint(String fontName, int fontSize, int alignment){
Paint paint = new Paint();
paint.setColor(Color.WHITE);
paint.setTextSize(fontSize);
paint.setTypeface(Typeface.create(fontName, Typeface.NORMAL));
paint.setAntiAlias(true);
paint.setTextSize(fontSize);
paint.setAntiAlias(true);
/*
* Set type face for paint, now it support .ttf file.
*/
if (fontName.endsWith(".ttf")){
try {
Typeface typeFace = Typeface.createFromAsset(context.getAssets(), fontName);
paint.setTypeface(typeFace);
} catch (Exception e){
Log.e("Cocos2dxBitmap",
"error to create ttf type face: " + fontName);
/*
* The file may not find, use system font
*/
paint.setTypeface(Typeface.create(fontName, Typeface.NORMAL));
}
}
else {
paint.setTypeface(Typeface.create(fontName, Typeface.NORMAL));
}
switch (alignment){
case ALIGNCENTER:

View File

@ -1 +1 @@
898c0f4be35b091c881554d3a75aafca0788707a
089538e21098633ff475d29aa721c886c2eed848

View File

@ -1083,6 +1083,18 @@
>
</File>
</Filter>
<Filter
Name="FontTest"
>
<File
RelativePath="..\tests\FontTest\FontTest.cpp"
>
</File>
<File
RelativePath="..\tests\FontTest\FontTest.h"
>
</File>
</Filter>
</Filter>
</Filter>
</Files>

View File

@ -119,7 +119,8 @@ OBJECTS = \
$(OBJECTS_DIR)/TouchesTest.o \
$(OBJECTS_DIR)/TransitionsTest.o \
$(OBJECTS_DIR)/UserDefaultTest.o \
$(OBJECTS_DIR)/ZwoptexTest.o
$(OBJECTS_DIR)/ZwoptexTest.o \
$(OBJECTS_DIR)/FontTest.o
ADD_OBJECTS +=
@ -390,3 +391,6 @@ $(OBJECTS_DIR)/UserDefaultTest.o : ../tests/UserDefaultTest/UserDefaultTest.cpp
$(OBJECTS_DIR)/ZwoptexTest.o : ../tests/ZwoptexTest/ZwoptexTest.cpp
$(CXX) -c $(CXX_FLAGS) $(INCLUDE_PATH) $(LAST_INCLUDE_PATH) -o $(OBJECTS_DIR)/ZwoptexTest.o ../tests/ZwoptexTest/ZwoptexTest.cpp
$(OBJECTS_DIR)/FontTest.o : ../tests/FontTest/FontTest.cpp
$(CXX) -c $(CXX_FLAGS) $(INCLUDE_PATH) $(LAST_INCLUDE_PATH) -o $(OBJECTS_DIR)/FontTest.o ../tests/FontTest/FontTest.cpp

View File

@ -1090,6 +1090,18 @@
>
</File>
</Filter>
<Filter
Name="FontTest"
>
<File
RelativePath="..\tests\FontTest\FontTest.cpp"
>
</File>
<File
RelativePath="..\tests\FontTest\FontTest.h"
>
</File>
</Filter>
</Filter>
</Filter>
<Filter

View File

@ -609,7 +609,7 @@ void ActionAnimate::onEnter()
centerSprites(1);
CCAnimation* animation = CCAnimation::animationWithName("dance", 0.2f);
CCAnimation* animation = CCAnimation::animation();
char frameName[100] = {0};
for( int i=1;i<15;i++)
{
@ -617,7 +617,7 @@ void ActionAnimate::onEnter()
animation->addFrameWithFileName(frameName);
}
CCActionInterval* action = CCAnimate::actionWithAnimation( animation, false);
CCActionInterval* action = CCAnimate::actionWithDuration(3, animation, false);
CCActionInterval* action_back = action->reverse();
m_grossini->runAction( CCSequence::actions( action, action_back, NULL));

View File

@ -120,7 +120,7 @@ void Box2DTestLayer::addNewSpriteWithCoords(CCPoint p)
//just randomly picking one of the images
int idx = (CCRANDOM_0_1() > .5 ? 0:1);
int idy = (CCRANDOM_0_1() > .5 ? 0:1);
CCSprite *sprite = batch->createSpriteWithRect( CCRectMake(32 * idx,32 * idy,32,32));
CCSprite *sprite = CCSprite::spriteWithTexture(batch->getTexture(), CCRectMake(32 * idx,32 * idy,32,32));
batch->addChild(sprite);
sprite->setPosition( CCPointMake( p.x, p.y) );

View File

@ -19,15 +19,16 @@
* SOFTWARE.
*/
#include "chipmunk.h"
#include "drawSpace.h"
#include "cocos2d.h"
#include "cocos2d.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <limits.h>
#include <string.h>
#include "chipmunk.h"
#include "drawSpace.h"
using namespace cocos2d;

View File

@ -0,0 +1,133 @@
#include "FontTest.h"
#include "../testResource.h"
enum {
kTagLabel1,
kTagLabel2,
kTagLabel3,
kTagLabel4,
};
static int fontIdx = 0;
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
static std::string fontList[] =
{
"American Typewriter",
"Marker Felt",
"A Damn Mess",
"Abberancy",
"Abduction",
"Paint Boy",
"Schwarzwald Regular",
"Scissor Cuts",
};
#else
static std::string fontList[] =
{
"fonts/A Damn Mess.ttf",
"fonts/Abberancy.ttf",
"fonts/Abduction.ttf",
"fonts/Paint Boy.ttf",
"fonts/Schwarzwald Regular.ttf",
"fonts/Scissor Cuts.ttf",
};
#endif
static const char* nextAction(void)
{
fontIdx++;
fontIdx = fontIdx % (sizeof(fontList) / sizeof(fontList[0]));
return fontList[fontIdx].c_str();
}
static const char* backAction(void)
{
fontIdx--;
if (fontIdx < 0)
{
fontIdx += (sizeof(fontList) / sizeof(fontList[0]));
}
return fontList[fontIdx].c_str();
}
static const char* restartAction(void)
{
return fontList[fontIdx].c_str();
}
FontTest::FontTest()
{
CCSize size = CCDirector::sharedDirector()->getWinSize();
CCMenuItemImage *item1 = CCMenuItemImage::itemFromNormalImage(s_pPathB1, s_pPathB2, this, menu_selector(FontTest::backCallback));
CCMenuItemImage *item2 = CCMenuItemImage::itemFromNormalImage(s_pPathR1, s_pPathR2, this, menu_selector(FontTest::restartCallback));
CCMenuItemImage *item3 = CCMenuItemImage::itemFromNormalImage(s_pPathF1, s_pPathF2, this, menu_selector(FontTest::nextCallback));
CCMenu *menu = CCMenu::menuWithItems(item1, item2, item3, NULL);
menu->setPosition(CCPointZero);
item1->setPosition(ccp(size.width/2 - 100,30));
item2->setPosition(ccp(size.width/2, 30));
item3->setPosition(ccp(size.width/2 + 100,30));
addChild(menu, 1);
showFont(restartAction());
}
void FontTest::showFont(const char *pFont)
{
removeChildByTag(kTagLabel1, true);
removeChildByTag(kTagLabel2, true);
removeChildByTag(kTagLabel3, true);
removeChildByTag(kTagLabel4, true);
CCSize s = CCDirector::sharedDirector()->getWinSize();
CCLabelTTF *top = CCLabelTTF::labelWithString(pFont, pFont, 24);
CCLabelTTF *left = CCLabelTTF::labelWithString("alignment left", CCSizeMake(s.width, 50), CCTextAlignmentLeft, pFont, 32);
CCLabelTTF *center = CCLabelTTF::labelWithString("alignment center", CCSizeMake(s.width, 50), CCTextAlignmentCenter, pFont, 32);
CCLabelTTF *right = CCLabelTTF::labelWithString("alignment right", CCSizeMake(s.width, 50), CCTextAlignmentRight, pFont, 32);
top->setPosition(ccp(s.width/2, 250));
left->setPosition(ccp(s.width/2, 200));
center->setPosition(ccp(s.width/2, 150));
right->setPosition(ccp(s.width/2, 100));
addChild(left, 0, kTagLabel1);
addChild(right, 0, kTagLabel2);
addChild(center, 0, kTagLabel3);
addChild(top, 0, kTagLabel4);
}
void FontTest::backCallback(CCObject* pSender)
{
showFont(backAction());
}
void FontTest::nextCallback(CCObject* pSender)
{
showFont(nextAction());
}
std::string FontTest::title()
{
return "Font test";
}
void FontTest::restartCallback(CCObject* pSender)
{
showFont(restartAction());
}
///---------------------------------------
//
// DirectorTestScene
//
///---------------------------------------
void FontTestScene::runThisTest()
{
CCLayer* pLayer = FontTest::node();
addChild(pLayer);
CCDirector::sharedDirector()->replaceScene(this);
}

Some files were not shown because too many files have changed in this diff Show More