cocos2d-x 文本框

Jun 07, 2016 pm 03:32 PM
성취하다 텍스트

1.所有文本框必须实现CCLabelProtocol接口 2.CCLableTTF比另外两个文本框渲染慢 TTF(TrueTypeFont)是一种字库名称,是Apple公司和Microsoft公司共同推出的字体文件式,随着windows的流行,已经变成最常用的一种字体文件表示方式。 CCLabelTTF 所以, 而应该

cocos2d-x 文本框

1.所有文本框必须实现CCLabelProtocol接口

 

2.CCLableTTF比另外两个文本框渲染慢

TTF(TrueTypeFont)是一种字库名称,是Apple公司和Microsoft公司共同推出的字体文件格式,随着windows的流行,已经变成最常用的一种字体文件表示方式。

           CCLabelTTF 

           所以, 而应该使用CCLabelAtlas或者是CCLabelBMFont 

OK, 看下它的使用方法 

CCLabelTTF *label = CCLabelTTF::labelWithString("the string", "Marker Felt", 21);

this->addChild(label);

 label->setPosition(ccp(100, 100));

 label->setString("change string");//修改文字的方法

 这个类使用的是系统中的字体,不需要额外往项目文件中添加字体文件。但如果你有自定义的字体也可以加到项目中,如果无法使用,可以查看一下ccConfig.h中的CC_FONT_LABEL_SUPPORT是否enable了。  

 

 

3.CCLabelBMFont中每个文字相当于一个CCSprite,可以旋转,移动,改变尺寸等

CCLabelBMFont  相当于每次改变只改变了图片坐标,而CCLabelTTF要重新渲染.这个类使用之前,需要添加好字体文件,包括一个图片文件 (**.png) 和一个 字体坐标文件 (**.fnt)。

在 cocos2d-x的示例项目中有现成的,可以先拿过来练习一下,找的时候注意两个文件的名称是相同的,只是扩展名不同。

CCLabelIBMFont *label = CCLabelIBMFont::labelWithString("the string", "font-hd.png");

this->addChild(label);

label->setPosition(ccp(100, 100));

label->setString("change string");

 

下面是 font-hd.png文件的截图

cocos2d-x 文本框

 font-hd.fnt文件定义了 图像文件的名称,以及每个字符对应的位置信息。

 这个没办法指定字体的字号,但可以用scale属性进行缩放来调整大小。就当它是sprite,可以简单的实现很炫的文字的动画效果。

 

4.CCLabelAtlas        

如果你用cocos2d-x项目模板创建过项目,那么你已经看过它的效果了,就是左下角显示帧率的数字。

因为帧率一直在变,使用CCLabelTTF的话效率太低,因为只是数字所以也犯不上使用 CCLabelBMFont 加载那么大的文字图像,所以使用这个比较合适。

CCLabelAtlas *label = CCLabelAtlas::labelWithString("12", "fps_images.png", 12, 18, ".");

this->addChild(label);

label->setPosition(ccp(100, 100));

label->setString("34");

 在项目文件中,在resourse group里你可以找一下一个叫 fps_images.png的这个图像文件,文件如下:

        cocos2d-x 文本框

       所以,这个只能显示上面这个12个字符,abcd什么的就不行了。

       解释一下参数,

       12 就是字符,

       fps_images.png就是字符的图像文件(这个只要图像文件就可以了),

       12 是每个字符的宽度,

       18 是每个字符的高度,这个不能设错,否则显示的时候可能就不对了。

       最后一个是起始字符,它是使用这个其实字符来对应字符和图像关系的

5.下面具体分析一下画字的原理(参考一篇博客)

图字,顾名思义,利用图片做为纹理来显示的文字。当下流行的跨平台2D引擎Cocos2d-x和LibGdx也都有对于图字的应用支持,今天我就来为大家讲一讲图字。

 

首先要介绍一下,图字是怎么来的?其实这个很早很早了,记得80后在95年开始玩DOS下的仙剑奇侠传的时候,那些令人难忘的中文对话吧!DOS下做游戏,使用的是C语言,不要说写字了,很多复杂的操作甚至涉及驱动。那时候绘图就是利用将图片中的像素取出来后绘制在屏幕上,所以处理游戏中的中文,就只有把这些文字的像素预先写到BMP或二进制文件中,然后读取出来再设置屏幕像素以实现。后来进入DDRAW的时代,可以使用WINDOWS系统中的字库来写字了。把DDRAW的后台表面进行LOCK,取出其DC,然后用GDI将文字写到其DC上,这种做法后面也延续了很久,但GDI进行TextOut的效率非常慢,你要是想像梦幻西游一样满屏写了,那得卡死,解决方案是什么?还是图字。专业的游戏开发者会将所用到的字都预处理生成到一张图片中,通过一个编码与纹理UV对应文件来进行纹理UV的获取后做为顶点的UV值然后进行绘制,有也的在每一帧中实时的将需要的字使用DDRAW写字的方法绘制到相应的纹理上然后使用文字编码与纹理UV对应信息来进行绘制,这样效率就提高很多了。目前比较流行的做法是使用一张png图片来存储用到的文字。一个.fnt文件来存储文字图片说明信息。Cocos2d-x和LibGdx中都集成了相关的图字处理类。在世界范围内,也有很多游戏使用了这个方案。在游戏汉化界,了解和掌握图字的原理和修改方法也是很重要的一项工作

我们以Cocos2d-x的tests工程中的LabelTest中的最后一个Label显示“中国”为例来分析一下。

打开Cocos2d-x所在目录下的tests\Resources\fonts目录,找到bitmapFontChinese.png(文字贴图文件)和bitmapFontChinese.fnt(文字图片说明信息文件)

先打开png,我们可以看到它是512×512大小,上面由12行,14列个文字组成。包括有一些汉字,常用字符,数字和字母。它的每个字都是由青色到蓝色的向下渐变。
cocos2d-x 文本框
再用UEdit或记事本打开bitmapFontChinese.fnt,可以看到它的构成,我在这里讲一下。

第一行是对字体的介绍。

 

1

info face="华康海报体W12(P)" size=32 bold=0italic=0 charset="" unicode=0stretchH=100smooth=1 aa=1 padding=0,0,0,0 spacing=1,1

 

解释:
face=”华康海报体W12(P)”:字体为”华康海报体W12(P)”,

size=32:大小为32像素

bold=0 :不加粗

italic=0:不使用斜体

charset=”": charset是编码字符集,这里没有填写值即使用默认,

unicode=0:不使用Unicode

stretchH=100:纵向缩放百分比

smooth=1 :开启平滑

aa=1:开启抗锯齿

padding=0,0,0,0:内边距,文字与边框的空隙。

spacing=1,1 :外边距,就是相临边缘的距离。
第二行是对应所有字贴图的公共信息

 

1

common lineHeight=37 base=28 scaleW=512 scaleH=512pages=1 packed=0

 

解释:

lineHeight=37:行高,如果遇到换行符时,绘制字的位置坐标的Y值在换行后增加的像素值。

base=28 :字的基本大小

scaleW=512 :图片大小

scaleH=512:图片大小

pages=1 :此种字体共用到几张图。

packed=0:图片不压缩
第三行是对应当前字贴图的信息

//第一页,文件名称是”bitmapFontChinese.png”

page id=0 file=”bitmapFontChinese.png”

第四行是当前贴图中所容纳的文字数量

chars count=204

第五行起把当前贴图中所用到的所有文字的编码以及对应在图片上的矩形位置,偏移等列出来

第一个字符编码为32,也就是空格,位置为0,0,宽高为0,0, 绘制到屏幕的相应位置时,像素偏移(0,28),绘制完后相应位置的x往后移15像素再画下一个字符,字的图块在第1页上
char id=32 x=0 y=0 width=0 height=0 xoffset=0 yoffset=28 xadvance=15 page=0 chnl=0

第一个字符编码为汉字”象”,也就是空格,位置为0,0,宽为33,高为36, 绘制到屏幕的相应位置时,像素偏移(0,-1),绘制完后相应位置的x往后移36像素再画下一个字,字的图块在第1页上

char id=35937 x=0 y=0 width=33 height=36 xoffset=0 yoffset=-1 xadvance=36 page=0 chnl=0

char id=26696 x=33 y=0 width=35 height=36 xoffset=-1 yoffset=-1 xadvance=36 page=0 chnl=0

char id=26071 x=68 y=0 width=35 height=36 xoffset=-1 yoffset=-1 xadvance=36 page=0 chnl=0


再后面是描述两个字在进行组合绘制时字距调整的相关信息,这里没有要进行间距调整的字组合所以为设-1。对于字组合间距调整可以看此示例图:
cocos2d-x 文本框
kernings count=-1

这个数字代表参与字组合间距调整的字的数量。

如果kernings count大于零,后面会有类似这样的描述:

kerning first=102 second=41 amount=2

也就是’f’与’)’进行组合显示’f)’时,’)’向右移2像素防止粘在一起。

通过上面这些信息,引擎可以通过编码找到相应的文字并取出对应的纹理块。

//Cocos2d-x中LabelBMFontChinese

下面我们来分析一下Cocos2d-x的tests工程中的LabelTest中的最后一个Label,它的类名为CCLabelBMFont.转到其类定义文件CCLabelBMFont.h

 

1

class CC_DLL CCLabelBMFont : public CCSpriteBatchNode, public CCLabelProtocol, public CCRGBAProtocol

 

cocos2d-x 文本框
可以看到其直接派生于三个类,分别是

CCSpriteBatchNode :精灵批次管理类,用于将使用一张图的多个精灵在设置一次纹理的批次里进行绘制,提高渲染的效率。

CCLabelProtocol :文字字串类

CCRGBAProtocol:颜色调节接口类

由简入深,我们先来看一下CCRGBAProtocol,打开CCProtocols.h

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

class CC_DLL CCRGBAProtocol
{
public:
    //设置颜色
    virtual void setColor(const ccColor3B& color) = 0;

    //取得颜色
    virtual const ccColor3B& getColor(void) = 0;

    //返回透明度
    virtual GLubyte getOpacity(void) = 0;

    //设置透明度
    virtual void setOpacity(GLubyte opacity) = 0;

    //设置是否使用Alpha值设置RGB,如果
    virtual void setIsOpacityModifyRGB(bool bValue) = 0;

    //取得是否使用Alpha值设置RGB
    virtual bool getIsOpacityModifyRGB(void) = 0;
};

 

可以看到CCRGBAProtocol类是个纯虚类,只是定义了一些设置获取颜色信息的接口函数。

继续看CCLabelProtocal,明显的,它也是纯虚类,做为存储字符串的接口使用:

 

1
2
3
4
5
6
7
8
9

class CC_DLL CCLabelProtocol
{
public:
   
    virtual void setString(const char *label) = 0;

   
    virtual const char* getString(void) = 0;
};

 

最后来分析CCSpriteBatchNode类。它由CCNodet 和 CCTextureProtocal两个类派生而来,CCNode是基础结点类,用于将引擎中所有具有逻辑顺序和父子关系的类组织起来,基于CCNode派生的类均可以互相挂接。CCNode不是本章要详细介绍的内容,就不再详细分析了,看一下CCTextureProtocol,这是一个纹理使用接口类:

 

1
2
3
4
5
6
7
8
9

class CC_DLL CCTextureProtocol : public CCBlendProtocol
{
public:
    // 返回所使用的2D纹理
    virtual CCTexture2D* getTexture(void) = 0;

    // 设置使用的2D纹理,并为纹理的使用计数器加1操作
    virtual void setTexture(CCTexture2D *texture) = 0;
};

 

很简单,只有两个函数对纹理进行设置和获取,它派生于CCBlendProtocal,这是一个Alpha混合系数设置接口类,用于在开启Alpha混合状态后对Alpha混合的系数进行设置。再来看一下CCBlendProtocal,这是一个混合状态设置接口类:

 

1
2
3
4
5
6
7
8
9

class CC_DLL CCBlendProtocol
{
public:
    // 为纹理设置使用的混合状态
    virtual void setBlendFunc(ccBlendFunc blendFunc) = 0;

    // 返回为纹理设置的混合状态
    virtual ccBlendFunc getBlendFunc(void) = 0;
};

 

返回到类CCSpriteBatchNode的定义。我们再来分析CCSpriteBatchNode。之前说了CCSpriteBatchNode是精灵批次管理类,用于将使用一张图的多个精灵在设置一次纹理的批次里进行绘制,提高渲染的效率。既然多个精灵使用一张图,则需要将多个小图块合并在一张图上,这样只要设置使用大图做为纹理,将使用各小图块做为纹理贴图的精灵设置好顶点与UV等数据,就可以绘制出这些精灵了。Cocos2d-x提供了一个类CCTextureAtlas对使用图块的这些精灵所使用的顶点缓冲区进行管理。为了更好的理解CCSpriteBatchNode,我们看一下它的定义和实现:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86

#ifndef __CCTEXTURE_ATLAS_H__
#define __CCTEXTURE_ATLAS_H__
//用到的头文件
#include
#include "ccTypes.h"
#include "CCObject.h"
#include "ccConfig.h"
//使用Cocos2d命名空间
namespace   cocos2d {
class CCTexture2D;
//CCTextureAtlas由CCObject派生而来
class CC_DLL CCTextureAtlas : public CCObject
{
protected:
    //使用此大图中的图块的精灵对应的三角形索引数组的指针
    GLushort            *m_pIndices;
#if CC_USES_VBO
    //如果使用Vertex Buffer Object(VBO:使用显存而非内存存储顶点缓冲数据,大大提高效率),建立VBO句柄数组,第一个元素存顶点数组的句柄,第二个元素存索引数组句柄
    GLuint              m_pBuffersVBO[2];
    //标记是否更新需要更新的图块信息。当你新加入了图块或者修改了图块,需要设置为true。
    bool                m_bDirty;
#endif // CC_USES_VBO

// CC_PROPERTY_READONLY宏为类定义变量及增加相应的get函数。
    //当前使用图块的数量
    CC_PROPERTY_READONLY(unsigned int, m_uTotalQuads, TotalQuads)
    //存储图块信息的数组容量
    CC_PROPERTY_READONLY(unsigned int, m_uCapacity, Capacity)
    //设置所使用的大图纹理
    CC_PROPERTY(CCTexture2D *, m_pTexture, Texture)
    //使用此大图的图块的所有精灵的顶点缓冲信息数组
    CC_PROPERTY(ccV3F_C4B_T2F_Quad *, m_pQuads, Quads)

public:
    //构造
    CCTextureAtlas();
    //析构
    virtual ~CCTextureAtlas();
    //描述
    char * description();

    //静态函数:从文件中创建纹理,并初始化图块容量
    static CCTextureAtlas * textureAtlasWithFile(const char* file , unsigned int capacity);

    //同上,只是非静态函数。作者提示不能重复调用,否则会造成内存泄漏。
    bool initWithFile(const char* file, unsigned int capacity);

    //静态函数:从贴图中创建纹理,并初始化图块容量
    static CCTextureAtlas * textureAtlasWithTexture(CCTexture2D *texture, unsigned int capacity);

    //同上,只是非静态函数。作者提示不能重复调用,否则会造成内存泄漏。
    bool initWithTexture(CCTexture2D *texture, unsigned int capacity);

    //通过索引值找到对应的图块顶点缓冲数据并用新数据修改它,由CCSprite实例对象在变换顶点信息时调用。
    void updateQuad(ccV3F_C4B_T2F_Quad* quad, unsigned int index);

    //通过索引值找到对应的图块顶点缓冲数据,并在其之前插入一个新的图块。
    void insertQuad(ccV3F_C4B_T2F_Quad* quad, unsigned int index);

    //通过索引值找到对应的图块顶点缓冲数据,并把它插入另一个图块之前。
    void insertQuadFromIndex(unsigned int fromIndex, unsigned int newIndex);

    //移除指定位置的图块顶点缓冲数据.
    void removeQuadAtIndex(unsigned int index);

    //清空所有的图块顶点缓冲数据。
    void removeAllQuads();

    //重新设置图块顶点缓冲数组的容量
    bool resizeCapacity(unsigned int n);

    //绘制指定的图块顶点缓冲
    void drawNumberOfQuads(unsigned int n);

    //绘制从指定的图块起后面的N个图块
    void drawNumberOfQuads(unsigned int n, unsigned int start);

    //绘制所有的图块顶点缓冲
    void drawQuads();
private:
    //初始化索引缓冲数据
    void initIndices();
};
}//namespace   cocos2d

#endif //__CCTEXTURE_ATLAS_H__

 

再看CPP:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471

#include "CCTextureAtlas.h"
#include "CCTextureCache.h"
#include "ccMacros.h"

// 纹理头文件
#include "CCTexture2D.h"

#include

//使用Cocos2d命名空间
namespace   cocos2d {
//构造,初始化成员变量
CCTextureAtlas::CCTextureAtlas()
    :m_pIndices(NULL)
#if CC_USES_VBO
    , m_bDirty(false)
#endif
    ,m_pTexture(NULL)
    ,m_pQuads(NULL)
{}
//析构,释放所用的内存
CCTextureAtlas::~CCTextureAtlas()
{
//  CCLOGINFO("cocos2d: deallocing CCTextureAtlas.");

    CC_SAFE_FREE(m_pQuads)
    CC_SAFE_FREE(m_pIndices)

#if CC_USES_VBO
    //释放缓冲区对象
    glDeleteBuffers(2, m_pBuffersVBO);
#endif // CC_USES_VBO

    CC_SAFE_RELEASE(m_pTexture);
}
//实现通过宏CC_PROPERTY_READONLY声明的函数
//取得当前使用的图块的数量
unsigned int CCTextureAtlas::getTotalQuads()
{
    return m_uTotalQuads;
}
//取得图块集的容量
unsigned int CCTextureAtlas::getCapacity()
{
    return m_uCapacity;
}
//取得大纹理
CCTexture2D* CCTextureAtlas::getTexture()
{
    return m_pTexture;
}
//设置大纹理
void CCTextureAtlas::setTexture(CCTexture2D * var)
{
    CC_SAFE_RETAIN(var);
    CC_SAFE_RELEASE(m_pTexture);
    m_pTexture = var;
}
//取得使用此大图的图块的所有精灵的顶点缓冲信息数组
ccV3F_C4B_T2F_Quad* CCTextureAtlas::getQuads()
{
    return m_pQuads;
}
//设置使用此大图的图块的所有精灵的顶点缓冲信息数组
void CCTextureAtlas::setQuads(ccV3F_C4B_T2F_Quad *var)
{
    m_pQuads = var;
}

//静态函数:从文件中创建纹理,并初始化图块容量
CCTextureAtlas * CCTextureAtlas::textureAtlasWithFile(const char* file, unsigned int capacity)
{
    //使用new来实例化一个CCTextureAtlas对象
    CCTextureAtlas * pTextureAtlas = new CCTextureAtlas();
    //调用成员函数进行初始化
    if(pTextureAtlas && pTextureAtlas->initWithFile(file, capacity))
    {
        pTextureAtlas->autorelease();
        return pTextureAtlas;
    }
    //如果失败,释放后返回NULL
    CC_SAFE_DELETE(pTextureAtlas);
    return NULL;
}
//静态函数:从贴图中创建纹理,并初始化图块容量
CCTextureAtlas * CCTextureAtlas::textureAtlasWithTexture(CCTexture2D *texture, unsigned int capacity)
{
    //使用new来实例化一个CCTextureAtlas对象
    CCTextureAtlas * pTextureAtlas = new CCTextureAtlas();
    //调用成员函数进行初始化
    if (pTextureAtlas && pTextureAtlas->initWithTexture(texture, capacity))
    {
        pTextureAtlas->autorelease();
        return pTextureAtlas;
    }
    //如果失败,释放后返回NULL
    CC_SAFE_DELETE(pTextureAtlas);
    return NULL;
}
//非静态函数,从文件中创建纹理,并初始化图块容量
bool CCTextureAtlas::initWithFile(const char * file, unsigned int capacity)
{
    // 由纹理管理器加载一个图片文件,返回生成的纹理
    CCTexture2D *texture = CCTextureCache::sharedTextureCache()->addImage(file);
    //判断生成纹理是否有效
    if (texture)
    {  
        //如果成功,使用纹理进行初始化
        return initWithTexture(texture, capacity);
    }
    else
    {
        //不成功打印错误日志并返回NULL
        CCLOG("cocos2d: Could not open file: %s", file);
        delete this;

        return NULL;
    }
}
//非静态函数,设置纹理,并初始化图块容量
bool CCTextureAtlas::initWithTexture(CCTexture2D *texture, unsigned int capacity)
{
    //纹理有效性判断,防止重复调用
    CCAssert(texture != NULL, "texture should not be null");
    //设置图块容量
    m_uCapacity = capacity;
    m_uTotalQuads = 0;

    // 设置纹理
    this->m_pTexture = texture;
    CC_SAFE_RETAIN(m_pTexture);

    // 判断是否重复调用
    CCAssert(m_pQuads == NULL && m_pIndices == NULL, "");
    //申请容量大小的的顶点缓冲信息数组
    m_pQuads = (ccV3F_C4B_T2F_Quad*)calloc( sizeof(ccV3F_C4B_T2F_Quad) * m_uCapacity, 1 ); 
    //申请容量大小的索引缓冲数组
    m_pIndices = (GLushort *)calloc( sizeof(GLushort) * m_uCapacity * 6, 1 );

    //如果失败,做相应处理
    if( ! ( m_pQuads && m_pIndices) && m_uCapacity > 0) {
        //CCLOG("cocos2d: CCTextureAtlas: not enough memory");
        CC_SAFE_FREE(m_pQuads)
        CC_SAFE_FREE(m_pIndices)
        CC_SAFE_RELEASE_NULL(m_pTexture);
        return false;
    }

//初始化缓冲区对象
#if CC_USES_VBO
    glGenBuffers(2, &m_pBuffersVBO[0]);
    m_bDirty = true;
#endif // CC_USES_VBO
//初始化索引缓冲
    this->initIndices();

    return true;
}
//取得描述
char * CCTextureAtlas::description()
{
    char *ret = new char[100];
    sprintf(ret, "", m_uTotalQuads);
    return ret;
}

//初始化索引缓冲
void CCTextureAtlas::initIndices()
{
    //如果容量为0直接返回
    if (m_uCapacity == 0)
        return;
    //按照顶点的顺序和使用的三角形渲染排列方式为索引缓冲填充数据。
    for( unsigned int i=0; i m_uCapacity; i++)
    {
#if CC_TEXTURE_ATLAS_USE_TRIANGLE_STRIP
        m_pIndices[i*6+0] = i*4+0;
        m_pIndices[i*6+1] = i*4+0;
        m_pIndices[i*6+2] = i*4+2;     
        m_pIndices[i*6+3] = i*4+1;
        m_pIndices[i*6+4] = i*4+3;
        m_pIndices[i*6+5] = i*4+3;
#else
        m_pIndices[i*6+0] = (GLushort)(i*4+0);
        m_pIndices[i*6+1] = (GLushort)(i*4+1);
        m_pIndices[i*6+2] = (GLushort)(i*4+2);

        // inverted index. issue #179
        m_pIndices[i*6+3] = (GLushort)(i*4+3);
        m_pIndices[i*6+4] = (GLushort)(i*4+2);
        m_pIndices[i*6+5] = (GLushort)(i*4+1);     
        //      m_pIndices[i*6+3] = i*4+2;
        //      m_pIndices[i*6+4] = i*4+3;
        //      m_pIndices[i*6+5] = i*4+1; 
#endif 
    }
#if CC_USES_VBO
    //指定m_pBuffersVBO[0]为顶点缓冲区,并激活缓冲区
    glBindBuffer(GL_ARRAY_BUFFER, m_pBuffersVBO[0]);
    //绑定完成后为其分配内存
    glBufferData(GL_ARRAY_BUFFER, sizeof(m_pQuads[0]) * m_uCapacity, m_pQuads, GL_DYNAMIC_DRAW);
    //指定m_pBuffersVBO[1]为索引缓冲区,并激活缓冲区
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_pBuffersVBO[1]);
    //绑定完成后为其分配内存
     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(m_pIndices[0]) * m_uCapacity * 6, m_pIndices, GL_STATIC_DRAW);
    //取消绑定
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
#endif // CC_USES_VBO
}

//通过索引值找到对应图块的顶点缓冲并用新数据修改它
void CCTextureAtlas::updateQuad(ccV3F_C4B_T2F_Quad *quad, unsigned int index)
{
    //有效性判断
    CCAssert( index >= 0 && index m_uCapacity, "updateQuadWithTexture: Invalid index");
    //如果index大于现有的数量则更新数量
    m_uTotalQuads = max( index+1, m_uTotalQuads);
    //修改对应的数据值
    m_pQuads[index] = *quad;   
    //需要更新
#if CC_USES_VBO
    m_bDirty = true;
#endif
}
//通过索引值找到对应图块的顶点缓冲,并在其位置之前插入一个新的图块。
void CCTextureAtlas::insertQuad(ccV3F_C4B_T2F_Quad *quad, unsigned int index)
{
    //有效性判断
    CCAssert( index m_uCapacity, "insertQuadWithTexture: Invalid index");
    //数量增加
    m_uTotalQuads++;
    CCAssert( m_uTotalQuads m_uCapacity, "invalid totalQuads");

    //先将索引位置之后的数据整体后移一个位置,再用新数据填充索引位置的数据。实现插入操作。
    unsigned int remaining = (m_uTotalQuads-1) - index;
   
    if( remaining > 0) {
        // texture coordinates
        memmove( &m_pQuads[index+1],&m_pQuads[index], sizeof(m_pQuads[0]) * remaining );       
    }

    m_pQuads[index] = *quad;

    //设置需要更新m_pBuffersVBO中的VBO数组数据。
#if CC_USES_VBO
    m_bDirty = true;
#endif
}
//通过索引值找到对应图块的顶点缓冲,并把它插入另一个图块之前。
void CCTextureAtlas::insertQuadFromIndex(unsigned int oldIndex, unsigned int newIndex)
{
    //有效性判断
    CCAssert( newIndex >= 0 && newIndex m_uTotalQuads, "insertQuadFromIndex:atIndex: Invalid index");
    CCAssert( oldIndex >= 0 && oldIndex m_uTotalQuads, "insertQuadFromIndex:atIndex: Invalid index");
    //两个索引相同直接返回即可
    if( oldIndex == newIndex )
        return;

    //计算要移动的图块数量
    unsigned int howMany = (oldIndex - newIndex) > 0 ? (oldIndex - newIndex) :  (newIndex - oldIndex);
    unsigned int dst = oldIndex;
    unsigned int src = oldIndex + 1;
    if( oldIndex > newIndex) {
        dst = newIndex+1;
        src = newIndex;
    }

    // 开始进行移动
    ccV3F_C4B_T2F_Quad quadsBackup = m_pQuads[oldIndex];
    memmove( &m_pQuads[dst],&m_pQuads[src], sizeof(m_pQuads[0]) * howMany );
    //更新新索引位置的数据
    m_pQuads[newIndex] = quadsBackup;
    //设置需要更新m_pBuffersVBO中的VBO数组数据。
#if CC_USES_VBO
    m_bDirty = true;
#endif
}
//移除指定位置的图块顶点缓冲
void CCTextureAtlas::removeQuadAtIndex(unsigned int index)
{
    //有效性判断
    CCAssert( index m_uTotalQuads, "removeQuadAtIndex: Invalid index");

    unsigned int remaining = (m_uTotalQuads-1) - index;

    //将索引图块后的所有图块向前移1个位置即可
    // last object doesn't need to be moved
    if( remaining ) {
        // texture coordinates
        memmove( &m_pQuads[index],&m_pQuads[index+1], sizeof(m_pQuads[0]) * remaining );
    }
    //数量减1
    m_uTotalQuads--;
    //设置需要更新m_pBuffersVBO中的VBO数组数据。
#if CC_USES_VBO
    m_bDirty = true;
#endif
}

//移除所有的顶点缓冲数据
void CCTextureAtlas::removeAllQuads()
{
    //数量直接置0,这是最快的方式
    m_uTotalQuads = 0;
}

// 重新设置图块顶点缓冲数组的容量
bool CCTextureAtlas::resizeCapacity(unsigned int newCapacity)
{
    //如果等于原来的容量直接返回
    if( newCapacity == m_uCapacity )
        return true;

    //确保当前绘制的精灵数量最大不能超过容量
    m_uTotalQuads = min(m_uTotalQuads, newCapacity);
    //更新容量
    m_uCapacity = newCapacity;
   
    //定义指针存放要申请的图块信息与索引数组的内存地址
    void * tmpQuads = NULL;
    void * tmpIndices = NULL;
   
    //为图块的顶点缓冲数组申请内存,注意:如果已占有内存则直接在原内存地址上进行内存长度调整
    if (m_pQuads == NULL)
        tmpQuads = calloc(sizeof(m_pQuads[0]) * m_uCapacity, 1);
    else
        tmpQuads = realloc( m_pQuads, sizeof(m_pQuads[0]) * m_uCapacity );
    //为图块的索引缓冲数组申请内存, 如果已占有内存则直接在原内存地址上进行内存长度调整
    if (m_pIndices == NULL)
        tmpIndices = calloc(sizeof(m_pIndices[0]) * m_uCapacity * 6, 1);
    else
        tmpIndices = realloc( m_pIndices, sizeof(m_pIndices[0]) * m_uCapacity * 6 );
   
    //如果内存申请失败的处理
    if( ! ( tmpQuads && tmpIndices) ) {
        //CCLOG("cocos2d: CCTextureAtlas: not enough memory");
        if( tmpQuads )
            free(tmpQuads);
        else
            free(m_pQuads);

        if( tmpIndices )
            free(tmpIndices);
        else
            free(m_pIndices);

        m_pQuads = NULL;
        m_pIndices = NULL;
        m_uCapacity = m_uTotalQuads = 0;
        return false;
    }
    //如果成功,则将内存地址赋给相应成员指针变量
    m_pQuads = (ccV3F_C4B_T2F_Quad *)tmpQuads;
    m_pIndices = (GLushort *)tmpIndices;
   
    //释放顶点缓冲对象并重新创建和进行绑定
#if CC_USES_VBO
    glDeleteBuffers(2, m_pBuffersVBO);
    // initial binding
    glGenBuffers(2, &m_pBuffersVBO[0]);
    m_bDirty = true;
#endif // CC_USES_VBO
    //初始化索引缓冲
    this->initIndices();
    //设置需要更新m_pBuffersVBO中的VBO数组数据。上面已经设了,这里重复可以不要。
#if CC_USES_VBO
    m_bDirty = true;
#endif

    return true;
}

//绘制所有的图块顶点缓冲数据
void CCTextureAtlas::drawQuads()
{
    this->drawNumberOfQuads(m_uTotalQuads, 0);
}

//绘制指定的图块顶点缓冲数据
void CCTextureAtlas::drawNumberOfQuads(unsigned int n)
{
    this->drawNumberOfQuads(n, 0);
}
//绘制从指定的图块顶点缓冲数据起后面的N个图块顶点缓冲数据
void CCTextureAtlas::drawNumberOfQuads(unsigned int n, unsigned int start)
{  
    // Default GL states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY
    // Needed states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY
    // Unneeded states: -
    // 如果数量为零直接返回。
    if (0 == n)
        return;
    //设置使用纹理
    glBindTexture(GL_TEXTURE_2D, m_pTexture->getName());

#define kQuadSize sizeof(m_pQuads[0].bl)

    //如果使用VBO所进行的渲染设置
#if CC_USES_VBO
    //指定m_pBuffersVBO[0]为顶点缓冲区,并激活缓冲区
    glBindBuffer(GL_ARRAY_BUFFER, m_pBuffersVBO[0]);
    //绑定完成后为其分配内存
#if CC_ENABLE_CACHE_TEXTTURE_DATA
    glBufferData(GL_ARRAY_BUFFER, sizeof(m_pQuads[0

본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

AI Hentai Generator

AI Hentai Generator

AI Hentai를 무료로 생성하십시오.

인기 기사

R.E.P.O. 에너지 결정과 그들이하는 일 (노란색 크리스탈)
4 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 최고의 그래픽 설정
4 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 아무도들을 수없는 경우 오디오를 수정하는 방법
4 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25 : Myrise에서 모든 것을 잠금 해제하는 방법
1 몇 달 전 By 尊渡假赌尊渡假赌尊渡假赌

뜨거운 도구

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전

SublimeText3 중국어 버전

중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)

Huawei 휴대폰에서 이중 WeChat 로그인을 구현하는 방법은 무엇입니까? Huawei 휴대폰에서 이중 WeChat 로그인을 구현하는 방법은 무엇입니까? Mar 24, 2024 am 11:27 AM

Huawei 휴대폰에서 이중 WeChat 로그인을 구현하는 방법은 무엇입니까? 소셜 미디어의 등장으로 WeChat은 사람들의 일상 생활에 없어서는 안될 커뮤니케이션 도구 중 하나가 되었습니다. 그러나 많은 사람들이 동일한 휴대폰에서 동시에 여러 WeChat 계정에 로그인하는 문제에 직면할 수 있습니다. Huawei 휴대폰 사용자의 경우 듀얼 WeChat 로그인을 달성하는 것은 어렵지 않습니다. 이 기사에서는 Huawei 휴대폰에서 듀얼 WeChat 로그인을 달성하는 방법을 소개합니다. 우선, 화웨이 휴대폰과 함께 제공되는 EMUI 시스템은 듀얼 애플리케이션 열기라는 매우 편리한 기능을 제공합니다. 앱 듀얼 오픈 기능을 통해 사용자는 동시에

PHP 프로그래밍 가이드: 피보나치 수열을 구현하는 방법 PHP 프로그래밍 가이드: 피보나치 수열을 구현하는 방법 Mar 20, 2024 pm 04:54 PM

프로그래밍 언어 PHP는 다양한 프로그래밍 논리와 알고리즘을 지원할 수 있는 강력한 웹 개발 도구입니다. 그중 피보나치 수열을 구현하는 것은 일반적이고 고전적인 프로그래밍 문제입니다. 이 기사에서는 PHP 프로그래밍 언어를 사용하여 피보나치 수열을 구현하는 방법을 소개하고 구체적인 코드 예제를 첨부합니다. 피보나치 수열은 다음과 같이 정의되는 수학적 수열입니다. 수열의 첫 번째와 두 번째 요소는 1이고 세 번째 요소부터 시작하여 각 요소의 값은 이전 두 요소의 합과 같습니다. 시퀀스의 처음 몇 가지 요소

Chrome 및 Edge의 모든 탭에서 텍스트를 검색하는 방법 Chrome 및 Edge의 모든 탭에서 텍스트를 검색하는 방법 Feb 19, 2024 am 11:30 AM

이 튜토리얼에서는 Windows의 Chrome 또는 Edge에서 열려 있는 모든 탭에서 특정 텍스트나 문구를 찾는 방법을 보여줍니다. Chrome에 열려 있는 모든 탭에서 텍스트 검색을 수행하는 방법이 있습니까? 예, Chrome의 무료 외부 웹 확장 프로그램을 사용하면 수동으로 탭을 전환하지 않고도 열려 있는 모든 탭에서 텍스트 검색을 수행할 수 있습니다. TabSearch 및 Ctrl-FPlus와 같은 일부 확장 기능을 사용하면 이를 쉽게 달성할 수 있습니다. Chrome의 모든 탭에서 텍스트를 검색하는 방법은 무엇입니까? Ctrl-FPlus는 사용자가 브라우저 창의 모든 탭에서 특정 단어, 문구 또는 텍스트를 쉽게 검색할 수 있게 해주는 무료 확장 프로그램입니다. 이번 확장

Huawei 휴대폰에서 WeChat 복제 기능을 구현하는 방법 Huawei 휴대폰에서 WeChat 복제 기능을 구현하는 방법 Mar 24, 2024 pm 06:03 PM

Huawei 휴대폰에서 WeChat 복제 기능을 구현하는 방법 소셜 소프트웨어의 인기와 개인 정보 보호 및 보안에 대한 사람들의 강조가 높아지면서 WeChat 복제 기능이 점차 주목을 받고 있습니다. WeChat 복제 기능을 사용하면 사용자가 동일한 휴대폰에서 여러 WeChat 계정에 동시에 로그인할 수 있으므로 관리 및 사용이 더 쉬워집니다. Huawei 휴대폰에서 WeChat 복제 기능을 구현하는 것은 어렵지 않습니다. 다음 단계만 따르면 됩니다. 1단계: 휴대폰 시스템 버전과 WeChat 버전이 요구 사항을 충족하는지 확인하십시오. 먼저 Huawei 휴대폰 시스템 버전과 WeChat 앱이 최신 버전으로 업데이트되었는지 확인하세요.

PHP 게임 요구 사항 구현 가이드 PHP 게임 요구 사항 구현 가이드 Mar 11, 2024 am 08:45 AM

PHP 게임 요구사항 구현 가이드 인터넷의 대중화와 발전으로 인해 웹 게임 시장이 점점 더 대중화되고 있습니다. 많은 개발자는 PHP 언어를 사용하여 자신만의 웹 게임을 개발하기를 원하며 게임 요구 사항을 구현하는 것이 핵심 단계입니다. 이 문서에서는 PHP 언어를 사용하여 일반적인 게임 요구 사항을 구현하는 방법을 소개하고 특정 코드 예제를 제공합니다. 1. 게임 캐릭터 만들기 웹게임에서 게임 캐릭터는 매우 중요한 요소입니다. 이름, 레벨, 경험치 등 게임 캐릭터의 속성을 정의하고, 이를 운용할 수 있는 방법을 제공해야 합니다.

Golang이 어떻게 게임 개발 가능성을 가능하게 하는지 마스터하세요 Golang이 어떻게 게임 개발 가능성을 가능하게 하는지 마스터하세요 Mar 16, 2024 pm 12:57 PM

오늘날의 소프트웨어 개발 분야에서 효율적이고 간결하며 동시성이 뛰어난 프로그래밍 언어인 Golang(Go 언어)은 점점 더 개발자들의 선호를 받고 있습니다. 풍부한 표준 라이브러리와 효율적인 동시성 기능으로 인해 게임 개발 분야에서 주목받는 선택이 되었습니다. 이 기사에서는 게임 개발에 Golang을 사용하는 방법을 살펴보고 특정 코드 예제를 통해 Golang의 강력한 가능성을 보여줍니다. 1. 게임 개발에서 Golang의 장점 Golang은 정적인 유형의 언어로서 대규모 게임 시스템을 구축하는 데 사용됩니다.

Golang에서 정확한 나눗셈 연산을 구현하는 방법 Golang에서 정확한 나눗셈 연산을 구현하는 방법 Feb 20, 2024 pm 10:51 PM

Golang에서 정확한 나눗셈 작업을 구현하는 것은 특히 재무 계산과 관련된 시나리오 또는 고정밀 계산이 필요한 기타 시나리오에서 일반적인 요구 사항입니다. Golang에 내장된 나눗셈 연산자 "/"는 부동 소수점 수에 대해 계산되며 때로는 정밀도가 손실되는 문제가 있습니다. 이 문제를 해결하기 위해 타사 라이브러리나 사용자 정의 기능을 사용하여 정확한 분할 작업을 구현할 수 있습니다. 일반적인 접근 방식은 분수 표현을 제공하고 정확한 나눗셈 연산을 구현하는 데 사용할 수 있는 math/big 패키지의 Rat 유형을 사용하는 것입니다.

win11 텍스트 문서를 여는 방법 알아보기 win11 텍스트 문서를 여는 방법 알아보기 Jan 02, 2024 pm 03:54 PM

텍스트 문서는 시스템에서 매우 중요한 파일로, 많은 텍스트 콘텐츠를 볼 수 있을 뿐만 아니라 프로그래밍 기능도 제공합니다. 그러나 win11 시스템이 업데이트된 후 많은 친구들이 텍스트 문서를 열 수 없다는 사실을 발견했습니다. 이제 텍스트 문서를 실행하여 직접 열 수 있습니다. win11에서 텍스트 문서를 여는 위치 1. 먼저 키보드에서 "win+r"을 눌러 실행을 호출합니다. 2. 그런 다음 "메모장"을 입력하여 새 텍스트 문서를 직접 만듭니다. 3. 기존 텍스트 문서를 열려면 왼쪽 상단에 있는 파일을 클릭한 다음 "열기"를 클릭할 수도 있습니다.

See all articles