BYCircleTextureFactory.h
//
// BYCircleTextureFactory.h
// SuperBalance1.1
//
// Created by Bruce Yang on 8/1/11.
// Copyright 2011 Home. All rights reserved.
//
#import "cocos2d.h"
#import "GameConfig.h"
#import "CirclePointsGenerator.h"
#import "BYTextureDef.h"
#import "BYSingle.h"
@interface BYCircleTextureFactory : NSObject {
}
+ (CCTexture2D*) genCircleTexture:(BYTextureDef*)textureDef;
@end
BYCircleTextureFactory.mm
//
// BYCircleTextureFactory.mm
// SuperBalance1.1
//
// Created by Bruce Yang on 8/1/11.
// Copyright 2011 Home. All rights reserved.
//
#import "BYCircleTextureFactory.h"
@implementation BYCircleTextureFactory
/**
* 绘制出圆角多边形的轮廓,在内部填充颜色
*/
+ (void) glesDraw:(CGPoint*)vertices colors:(ccColor4F*)colors arrayLen:(int)arrayLen {
// 第一件事情就是禁用GL_TEXTURE_2D 和 GL_TEXTURE_COORD_ARRA两个opengl状态,
// 因为,我们接下来只需要绘制颜色---这与纹理无关。
glDisable(GL_TEXTURE_2D);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
// 将顶点(x, y)数组和颜色(r, g, b, a)数组传给opengl
glVertexPointer(2, GL_FLOAT, 0, vertices);
glColorPointer(4, GL_FLOAT, 0, colors);
glDrawArrays(GL_TRIANGLE_STRIP, 0, (GLsizei)arrayLen);
// 最后,我们重新激活GL_TEXTURE_COORD_ARRAY 和 GL_TEXTURE_2D两个状态,
// 这样做的话是保持和之前调用的对称,并且不会破坏opengl状态机。
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnable(GL_TEXTURE_2D);
}
/**
* 绘制1个像素的多边形圆角边框
*/
+ (void) drawOnePixelBorder:(CGPoint*)outBorderVetices verticesCount:(int)outBorderVeticesCount {
// openGL就是一个状态机,使用得时候该有的状态必须有,不需要的状态必须 disable 掉!!!
glDisable(GL_TEXTURE_2D);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glColor4f(0.0f, 0.0f, 0.0f, 1.0f);
glVertexPointer(2, GL_FLOAT, 0, outBorderVetices);
glDrawArrays(GL_LINE_LOOP, 0, outBorderVeticesCount);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnable(GL_TEXTURE_2D);
}
/**
* 去除图片文件的后缀
*/
+ (NSString*) fileNameWithoutSuffix:(NSString*)fullName {
NSMutableString *mutableString = [NSMutableString stringWithCapacity:50]; // 接收一下
[mutableString appendString:fullName];
NSString *suffix = [mutableString pathExtension]; // 获取文件后缀名
NSString *handledSuffix = [NSString stringWithFormat:@"%@%@", @".", suffix]; // 使后缀名带上前面那个点儿
NSRange suffixRange = [mutableString rangeOfString:handledSuffix];
[mutableString deleteCharactersInRange:suffixRange];
return mutableString;
}
/**
* 将纹理、噪点图片与目标形状相混合,形状内的部分保留,形状外的部分剔除
*/
+ (void) textureOrNoiseBlend:(NSString*)imgName circleSize:(CGSize)circleSize {
if(imgName != nil) {
CCSprite *textureOrNoise;
if([BYSingle getInstance].isIpad == NO) {
textureOrNoise = [CCSprite spriteWithFile:imgName];
textureOrNoise.position = ccp(circleSize.width/2, circleSize.height/2);
} else {
textureOrNoise = [CCSprite spriteWithFile:[NSString stringWithFormat:@"%@-hd.png", [self fileNameWithoutSuffix:imgName]]];
textureOrNoise.position = ccp(circleSize.width, circleSize.height);
}
[textureOrNoise setBlendFunc:(ccBlendFunc){GL_DST_COLOR, GL_ZERO}];
[textureOrNoise visit];
}
}
/**
* 将texture的尺寸扩大为原来的四倍(因为这里是静态类,因此需将+改为-)~
*/
+ (CGPoint*) convert2RetinaSize:(CGPoint*)vertices verticesCount:(int)verticesCount {
CGPoint *target = new CGPoint[verticesCount];
for(int i = 0; i < verticesCount; i ++) {
target[i] = ccpMult(vertices[i], 2.0f);
}
return target;
}
/**
* 生成带边框的圆形纹理~
*/
+ (CCTexture2D*) genCircleTexture:(BYTextureDef*)textureDef {
// 1: Create new CCRenderTexture
CGPoint sizePoint = textureDef.polygonVertexs[0];
CGSize circleSize = CGSizeMake(sizePoint.x, sizePoint.y);
CCRenderTexture *rt;
if([BYSingle getInstance].isIpad == NO) {
rt = [CCRenderTexture renderTextureWithWidth:circleSize.width height:circleSize.width];
} else {
rt = [CCRenderTexture renderTextureWithWidth:circleSize.width*2 height:circleSize.width*2];
}
// 颜色为黑色(白色等其他颜色亦可,因为不透明度为0)
ccColor4F bgColor1 = (ccColor4F){0.95f, 1.0f, 0.33f, 0.0f};
// 就因为没有加上下面这句代码,害我足足找了两天,记住曝出的错误:OpenGL error 0x0504 in -[EAGLView swapBuffers]
// 疯了,在网上查了下,说是什么 “堆栈下溢”,原来指的就是没有给 纹理打上底色??!
[rt beginWithClear:bgColor1.r g:bgColor1.g b:bgColor1.b a:bgColor1.a];
CGPoint *finalResult = [CirclePointsGenerator genCirclePoints:circleSize];
// 多边形的顶点数~
int circleVertexCount = CIRCLE_SEGEMENTS_COUNT;
// opengles绘制多边形边框总共的顶点数~
int borderTotalCount = circleVertexCount * 2 + 2;
CGPoint borderVertexs[borderTotalCount];
ccColor4F borderColors[borderTotalCount];
// 又有新的需求,不需要渐变边框,只需要圆角+1px的外框
int outBorderVeticesCount = CIRCLE_SEGEMENTS_COUNT + 1;
CGPoint outBorderVetices[outBorderVeticesCount];
// ************************* 对4代做修正~ *********************************
if([BYSingle getInstance].isRetinaSupported) {
finalResult = [self convert2RetinaSize:finalResult verticesCount:borderTotalCount];
}
if([BYSingle getInstance].isIpad == YES) {
finalResult = [self convert2RetinaSize:finalResult verticesCount:borderTotalCount];
}
// ************************* 对4代做修正~ *********************************
int k = 0;
for(int i = 0; i < borderTotalCount; i ++) {
borderVertexs[i] = finalResult[i];
borderColors[i] = (ccColor4F){1.0f, 1.0f, 1.0f, 1.0f};
if(i%2 == 0) {
outBorderVetices[k] = finalResult[i];
k += 1;
}
}
outBorderVetices[k] = outBorderVetices[0];
// --------------------------------- 蛋疼的分割线 ---------------------------------
// opengles绘制多边形内容物总共的顶点数~
int contentTotalCount;
if(circleVertexCount%2 == 1) {
// 如果是顶点数为奇数的多边形
contentTotalCount = 3 + (circleVertexCount-3)/2*3;
} else {
// 如果是顶点数为偶数的多边形
contentTotalCount = 5 + (circleVertexCount-4)/2*3;
}
CGPoint originalContentVertexs[circleVertexCount];
CGPoint contentVertexs[contentTotalCount];
ccColor4F contentColors[contentTotalCount];
for(int i = 0; i < circleVertexCount; i ++) {
originalContentVertexs[i] = finalResult[i * 2 + 1];
}
// 内部3角形的颜色,需一致设置为不透明度为1.0f的白色,便于与纹理图片 blend 获得纹理~
ccColor4F contentColor = (ccColor4F){1.0f, 1.0f, 1.0f, 1.0f};
int j = 1;
for(int i = 0; i < contentTotalCount; i ++) {
if(i%3 == 0) {
contentVertexs[i] = originalContentVertexs[0];
} else {
contentVertexs[i] = originalContentVertexs[j];
j = j + 1;
}
contentColors[i] = contentColor;
}
// 释放内存,避免野指针的存在(使用完毕之后立即回收在堆上new出来的内存)~
delete finalResult;
// 4: Draw into the texture
// 一。首先以纯白填充多边形内容物,为绘制纹理和噪点做准备
[self glesDraw:contentVertexs colors:contentColors arrayLen:contentTotalCount];
// 二。绘制多边形边框
[self glesDraw:borderVertexs colors:borderColors arrayLen:borderTotalCount];
// 三。混合木质纹理~
[self textureOrNoiseBlend:textureDef.textureImgName circleSize:circleSize];
// 四。混合噪点图片~
[self textureOrNoiseBlend:textureDef.noiseImgName circleSize:circleSize];
// 五。绘制1个像素宽度的外部边框~
// [self drawOnePixelBorder:outBorderVetices verticesCount:outBorderVeticesCount];
// 至此 textureDef 所占据的堆内存可以释放掉了!!
// 搞死哥了,哥在后面又用到过这个东西,结果总是曝出 EXC_BAD_ACCESS
// 不过虽然 delete 掉了 textureDef,但奇怪的是,有时候依然还是能够访问到多边形顶点数组的数据~
delete textureDef;
// 5: Call CCRenderTexture:end
[rt end];
// 6: Create a new Sprite from the texture
return rt.sprite.texture;
}
@end