当前位置:  编程技术>移动开发
本页文章导读:
    ▪ViewGroup学习之作图过程        ViewGroup学习之绘制过程Android UI界面由以下树形结构组成, 从图中可以看出, UI界面是有View与ViewGroup两大类控件组成,在下面树形图中不管是View还是ViewGroup都是从android.view.View中派生, 而ViewGroup.........
    ▪ Git学习笔记(2)-Git基本操作        Git学习笔记(2)--Git基本操作 Git学习笔记(2)--Git基本操作 Gitgit 首先 介绍一本Git的书,<<Pro Git>>,此书的网络版是可以免费获取的,是一本非常好的介绍Git的书籍。 然后,介绍.........
    ▪ 在使用 CCRenderTexture、shader 绘制几何图元时需要注意的一些细节有关问题       在使用 CCRenderTexture、shader 绘制几何图元时需要注意的一些细节问题一直对 cocos2d 的 opengl 混合机制不太明晰,昨日纠查 bug 的时候连带着注意了一下, CCNode 中包含了一个 m_glServerState 的成员.........

[1]ViewGroup学习之作图过程
    来源: 互联网  发布时间: 2014-02-18
ViewGroup学习之绘制过程
Android UI界面由以下树形结构组成, 从图中可以看出, UI界面是有View与ViewGroup两大类控件组成,在下面树形图中不管是View还是ViewGroup都是从android.view.View中派生, 而ViewGroup作为容器, 它可以装载和管理其下的一些列由android.view.View派生出来的元素(View和ViewGroup):

       

      由android.view.View派生出来的单一控件元素常见的有TextView, Button, ImageView等, 派生出的容器有LinearLayout, FrameLayout 等, 也有一些由ViewGroup派生出来的控件做为单一控件元素使用的, 比如说ListView, 当然我们也可以把ListView当做容器使用。Android通过布局可以完成很多有创意富有美感的界面, ViewGroup的作用很大,这里单独拿出来研究。

 

  ViewGroup实现了android.view.ViewParent和android.view.ViewManager两个接口, 赋予其装载子控件和管理子控件的能力。这篇主要讲Android控件如何绘制到界面上的。

  控件显示到界面上主要分三个流程, 如下图。这是一个非常自然的想法, 得到大小后才可以布局, 布局好了才可以绘制; 这三个流程都是按照上图树形结构递归的。对于这三个流程,只要对Android控件稍有研究的人都

         

会发现, 每一个控件都有measure(), layout(), draw()方法, 下面分别分析其作用:

measure 递归: 

    1、判断是否需要重新计算大小

    2、调用onMeasure, 如果是ViewGroup类型, 则遍历所有子控件的measure方法,计算出子控件大小,

    3、使用setMeasuredDimension(int, int)确定自身计算的大小

    由于第二步会调用子控件的measure方法, 在子控件的大小计算当中也会经历这三步动作, 直到整个树遍历完, 此时此控件及其子控件的大小都确定了, 在这里强调控件的大小是由父控件和自身决定的,当然取决在于父控件, 控件自身只提供参考值, 这是因为控件的measure方法是由父控件调用的, 而父控件的控件有限,可能不完全按照你的申请要求给出, 这里留待以后讨论关于布局参数问题。

在android.view.View对于measure流程已经实现了一部分:

public final void measure(int widthMeasureSpec, int heightMeasureSpec) {
     ...
   // measure ourselves, this should set the measured dimension flag back
     onMeasure(widthMeasureSpec, heightMeasureSpec);
     ...
}

对于android.view.View来说它不需要遍历子控件了, 下面贴出一个我实现的一个onMeasure :

@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //获取mode和size, 方便给children分配空间
        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        final int widthSize = MeasureSpec.getSize(widthMeasureSpec);

        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        final int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        //TODO 这里可以检查你的大小, 或者mode

        final int count = getChildCount();
        for(int i = 0; i < count; i++) {
            final View view = getChildAt(i);

            //这里只是举一个例子, 这里给child多少大小根据实际来定
            int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY);
            int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY);

            view.measure(childWidthMeasureSpec, childHeightMeasureSpec);
        }

        // 得出自己计算出的大小, 这里也是一个例子, 可以根据所有子控件占多大空间
        // 给出, 这里也根据要实现的效果看, 这部分建议看LinearLayout等容器的源码
        setMeasuredDimension(widthSize, heightSize);
    }

 

layout 递归: 

    1、设置自身相对父控件的位置并判断是否需要重新布局,使用setFrame(left, top, right, bottom);

    2、调用onLayout()布局子控件

在android.view.View也实现了此流程的一部分:

public void layout(int l, int t, int r, int b) {
    ...
    onLayout(changed, l, t, r, b);
    ...
}

下面我也简单的实现了第二步:

@Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        final int count = getChildCount();
        int widthSpan = 0;
        int heightSpan = 0;
        for(int i = 0; i < count; i++) {
            final View child = getChildAt(i);
            child.layout(widthSpan, heightSpan, child.getMeasuredWidth(), child.getMeasuredHeight());
            widthSpan += child.getMeasuredWidth();
            heightSpan += child.getMeasuredHeight();
        }
    }

这是一个简陋的Grid布局。 

draw递归: 

    1、绘制背景 

    2、调用onDraw()绘制控件内容

    3、调用dispatchDraw()绘制所有的子控件

    4、绘制渐变边界等

    5、绘制装饰品, 比如滑动条等

draw递归在android.view.View已经有完整的实现, 自定义ViewGroup时一般只需要重写onDraw实现如何绘制内容就够了, 当然所有的流程都可以重写, 如果需要的话。下面看一下android.view.View里面draw递归的原型:

public void draw(Canvas canvas) {
        // Step 1, draw the background, if needed
        ...// Step 2, draw the content
        onDraw(canvas);

        // Step 3, draw the children
        dispatchDraw(canvas);

        // Step 4, draw the fade effect and restore layers
        ...
    
     //Step 5, draw decorations
        onDrawScrollBars(canvas);
}

     上面三个递归, 解决了一颗控件树的显示问题, 现在大家会很奇怪, 到底是谁发起这个递归, 即最上层的父控件到底是谁, 查看源码可以看到, 在android.view下面有一个ViewRoot(更新后变成ViewRootImpl)隐藏类, 在其performTraversals()方法中发起这三个递归,这个类没有研究太深入, 以后补上。在performTraversals()中大概的流程是:

private void performTraversals() {
     final View host = mView;
     ...
     host.measure();
     ...
     host.layout();
     ...
     host.draw();
     ...
}

这样就实现了一个大的递归, 把完整的界面给绘制出来了。下面我自己写一个实现ViewGroup的Demo:

package com.ui.viewgroup;

import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;

public class ViewGroupImpl extends ViewGroup {

    public class LayoutParams extends ViewGroup.LayoutParams {
        public int left = 0;
        public int top = 0;

        public LayoutParams(int width, int height) {
            super(width, height);
        }

        public LayoutParams(int left, int top, int width, int height) {
            super(width, height);
            this.left = left;
            this.top = top;
        }
    }

    public ViewGroupImpl(Context context) {
        this(context, null);
    }

    public ViewGroupImpl(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public void addInScreen(View child, int left, int top, int width, int height) {
        addView(child, new LayoutParams(left, top, width, height));
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        final int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        // 检测控件大小是否符合要求
        if(widthMode == MeasureSpec.UNSPECIFIED || heightMode == MeasureSpec.UNSPECIFIED) {
            throw new IllegalArgumentException("不合法的MeasureSpec mode");
        }

        // 计算子控件大小
        final int count = getChildCount();
        for(int i = 0; i < count; i++) {
            final View child = getChildAt(i);
            final LayoutParams lp = (LayoutParams)child.getLayoutParams();

            //确定大小的
            final int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(lp.width,
                    MeasureSpec.EXACTLY);
            final int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(lp.height,
                    MeasureSpec.EXACTLY);

            child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
        }

        // 设置计算的控件大小
        setMeasuredDimension(widthSize, heightSize);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        final int count = getChildCount();
        LayoutParams lp;
        for(int i = 0; i < count; i++) {
            final View child = getChildAt(i);
            lp = (LayoutParams)child.getLayoutParams();
            //相对父控件坐标
            child.layout(lp.left, lp.top, lp.left + lp.width, lp.top + lp.width);
        }
    }

    // draw递归 不需要我们接管,

    @Override
    public void draw(Canvas canvas) {
        super.draw(canvas);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        super.dispatchDraw(canvas);
    }
}

Activity:

@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        ViewGroupImpl viewGroupImpl = new ViewGroupImpl(this);
        setContentView(viewGroupImpl, new LayoutParams(LayoutParams.MATCH_PARENT,
                LayoutParams.MATCH_PARENT));

        // 因为此时无法获取viewGroupImpl的实际大小, 所以只好假设一个大小
        final int parentWidth = 400;
        final int parentHeight = 700;

        final int maxWidthSize = parentWidth / 4;
        final int maxHeightSize = parentHeight / 4;

        Random random = new Random();

        for(int i = 0; i < 50; i++) {
            int left = random.nextInt(parentWidth) - 10;
            int top = random.nextInt(parentHeight) - 10;

            int width = random.nextInt(maxWidthSize) + 10;
            int height = random.nextInt(maxHeightSize) + 10;

            ImageView child = new ImageView(this);
            child.setImageResource(R.drawable.ic_launcher);
            viewGroupImpl.addInScreen(child, left, top, width, height);
        }

下面是效果图:


    
[2] Git学习笔记(2)-Git基本操作
    来源: 互联网  发布时间: 2014-02-18
Git学习笔记(2)--Git基本操作
Git学习笔记(2)--Git基本操作
Gitgit
首先
介绍一本Git的书,<<Pro Git>>,此书的网络版是可以免费获取的,是一本非常好的介绍Git的书籍。
然后,介绍一下我的运行环境,是ubuntu10.10,Git版本是1.7.1。

现在,进入正题介绍一下基本的Git命令,通过这些命令,你可以搭建一个单机版的Git库,开始你的工作,并且,在你是用Git管理你的软件时,你绝大部分时间使用的命令就是这几个。
这些命令有:

git init          初始化Git库
git add           向Git库提交文件修改(包括创建文件)
git commit        基于此分支提交一个更改
git reset         去除目标提交之后的一切提交记录(世界清净级大招)
git log           查看当前分支下的提交记录
git status        查看当前状态
git checkout      切换分支或回到某次提交
git branch        创建分支,查看分支等
git merge         合并目标分支到当前分支

从现在开始,我们一一实践这些命令
首先我们创建文件夹GitTest

#mkdir GitTest
#cd GitTest

然后创建文件readme,test并在test输入字符串“1”

#touch readme
#echo "1">test

接下来,执行一下三个操作

#git init                          创建git仓库
#git config user.name yym          配置作者名
#git config user.email yym@**.com  配置email
#git add .                         向git仓库中添加文件(.表示当前目录及其子目录下所有文件)
#git commit -m "initial"           进行第一次提交

现在,分别运行三个命令

#ls -a
.  ..  .git  readme  test

如果你看到.git恭喜你,你已经有了一个Git仓库,如果你没看到,抱歉,请重新安装Git。

#git status
# On branch master
nothing to commit (working directory clean)

翻译一下,你在分支master上,没什么可以提交的(工作文件夹很干净)
这里有两个概念需要解释,都很重要:分支,干净
1.branch分支是Git的一个重要概念,可以说Git是以这个概念为核心设计的。你可以把分支理解为你当前的工作发展方向,你的程序所在的位置,你的未来。一般来说,会有如下分支稳定版本bug修复分支,程序发展分支1~n,特性分支,发展分支,主分支等等。分支的管理和权限分配构成里项目的组织结构,这就像数据结构之于算法。
关于分支的妙用,这里推荐一个篇文章
《Git分支管理是一门艺术》
2.干净,这是一个美妙的词。干净代表你的程序没有什么需要提交的修改,意味着你完成了这个阶段性成果,当然这是在你的程序是正确的情况下。

#git log
commit 5b1ac4cff1bc7d91622ba6d5f733db1d2ba2af0f
Author: yym <yym@**.com>
Date:   Wed Sep 28 17:56:06 2011 +0800

    initial

commit代表提交,后面的hash值是这次提交的唯一标志,接下来是作者与时间,然后就是这次提交的名称。简洁直观

接下来,我们修改readme文件及test文件

#echo I" create this dir for learning Git">>readme
#echo “test”>test

注意>>和>的区别

创建文件notrack

#touch notrack

然后我们输入
#git status
# On branch master
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified:   readme
# modified:   test
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
# notrack
no changes added to commit (use "git add" and/or "git commit -a")

很好,我们发现,我们还在master分支上(当然!),然后,我们发现readme与test处于修改未更新状态,notrack处于未追踪状态。这是什么意思呢?

要回答这个问题,就需要介绍一个很要的概念。在Git的世界中,文件被分为3类:
1.未追踪,也就是说在此文件夹下,但是未被Git库追踪。
2.未修改,这代表这个文件未被改变
3.修改未更新,这就是上面的状态了
4.已暂存,处于这种状态,那就是等着提交(commit)了

现在我们需要用到add命令,将修改提交打Git库中。

#git add readme
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
# modified:   readme
#
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified:   test
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
# notrack

此时,你就可以将修改提交到Git库中,当然,你也可以将test文件的修改也暂存一起提交。这里我只提交单个文件的修改

#git commit -m "2nd commit"

#git status
# On branch master
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified:   test
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
# notrack
no changes added to commit (use "git add" and/or "git commit -a")
可以看到,刚才的readme文件的修改已经被提交了

#git log
commit ae79a590fa13673a584bc5cea08eaa260a7dd473
Author: yym <yym@**.com>
Date:   Wed Sep 28 18:10:48 2011 +0800

    2nd commit

commit 52a2d3bb92cc54a69f43a6118ca3ee1d1b520156
Author: yym <yym@**.com>
Date:   Wed Sep 28 18:01:29 2011 +0800

    initial

这是提交记录,就不多说了。现在,我们把test文件也提交了。

#git add test
#git commit -m "3rd commit"
#git log

commit b8d7f73a84944bc38a36990512ab5d9ceda77fef
Author: yym <yym@**.com>
Date:   Thu Sep 29 09:34:51 2011 +0800

    3rd commit

commit ae79a590fa13673a584bc5cea08eaa260a7dd473
Author: yym <yym@**.com>
Date:   Wed Sep 28 18:10:48 2011 +0800

    2nd commit

commit 52a2d3bb92cc54a69f43a6118ca3ee1d1b520156
Author: yym <yym@**.com>
Date:   Wed Sep 28 18:01:29 2011 +0800

    initial

突然,你想回退到2nd commit,想看看当时test文件中的内容。
你可以使用命令
#git checkout ae79a590fa13673a584bc5cea08eaa260a7dd473
#cat 1
1
看完test之前的内容后,你觉得还是第三次提交的内容比较合适,又想回到第三次提交,同样的,你可以
#git checkout  b8d7
#cat test
test

你可以不必打出所有位数,只要你保证他是独一无二的,但是你至少需要打出四位。
好吧,不要觉得我是个反复无常的人,现在我有觉得3rd commit完全是多余,我想回到2nd,彻底丢弃之后的内容。只需输入如下命令
#git reset --hard ae79
#git log

commit ae79a590fa13673a584bc5cea08eaa260a7dd473
Author: yym <yym@**.com>
Date:   Wed Sep 28 18:10:48 2011 +0800

    2nd commit

commit 52a2d3bb92cc54a69f43a6118ca3ee1d1b520156
Author: yym <yym@**.com>
Date:   Wed Sep 28 18:01:29 2011 +0800

    initial
最后,觉得每次都要add所有修改文件太麻烦了?
ok
git commit -a -m "CommitName"
你可以使用如上命令跳过暂存区域,或者你也可以把它看作是自动add已修改文件
关于Git的一部分基本操作就介绍到这里,下文会介绍Git的另一部分常用操作。


    
[3] 在使用 CCRenderTexture、shader 绘制几何图元时需要注意的一些细节有关问题
    来源: 互联网  发布时间: 2014-02-18
在使用 CCRenderTexture、shader 绘制几何图元时需要注意的一些细节问题

一直对 cocos2d 的 opengl 混合机制不太明晰,昨日纠查 bug 的时候连带着注意了一下,

CCNode 中包含了一个 m_glServerState 的成员,这个东西是与 混合开启与否相关联的,

混合默认是开启的。

CCLayerColor、CCSprite 等类型里面包含了一个 m_blendFunc 成员,这个东西是与采用怎么样的混合方式相关联的。

在 CCProtocols.h 的 CCBlendProtocol 的 @brief 注释里面可以看到,

默认是采用 {GL_ONE, GL_ONE_MINUS_SRC_ALPHA} 或 

{GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA} 的混合方式,选择哪种与 premultiplied alpha 相关。


当一个场景被绘制的时候,会根据子节点的 z 值来决定绘制的先后顺序,

在具体绘制某个可视子节点的时候,会根据该节点的 m_blendFunc 成员来决定用什么样的方式混合。

cocos2d 只是对 opengles 简化使用的一种封装!这里存在一个问题:

在 CCRenderTexture 上面绘制东西的时候,绘制几何图元 或 拿 sprite 对象执行 visit 动作的时候,

如果不调用  glBlendFunc 来指定混合方式的话,就会沿用绘制上一个 sprite 的混合方式。

显然这就让此次操作的结果带有不确定性,因为谁也没办法预料之前绘制的最后一个 sprite 采用的是何种混合方式。

(这里说的有点儿夸张了,实际上很多数情况下都不会对 sprite 的 blendFunc 做设置)

最稳妥的方式就是:在 CCRenderTexture 上面绘制的东西的时候即时设置一下混合方式,消除不确定性

代码:ccGLBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

需求多变,但是记住默认的混合参数是没有害处的,默认的为 {GL_ONE, GL_ONE_MINUS_SRC_ALPHA}。


另外一个问题就是,该采用何种的 shader?

毫无疑问,我在刚接触 shader 的时候也是碰了一鼻子灰,

经过一连串开发的磨砺,我才逐渐得以一窥全貌

(不敢托大,这里的全貌指的是有了一个大体的正确认识,gles1都还未能摸透就被迫迁移到2,这令我亚历山大)

cocos2d 缓存了一些常用的 shader,分别是用于一些特别的绘制情形。


打个比方来说,现在有一个需求,要绘制 50 个相同颜色的点,

要达到最高的性能,可以用 kCCShader_Position_uColor 这个枚举值所代表的 shader 来画,

这个 uColor 的 u 表示 uniform,具有 “统一” 的意思,

也就是说,不管花多少个点,都只能采用同一种颜色。


但如果我要绘制五十个不同颜色的点呢?

这确实是个问题,很显然已经超出上面那个缓存的 shader 对象所掌管的能力范围了。

不过这依然不是一个难题,用 kCCShader_PositionColor 从缓存里面拿相应的 shader 就能满足需求了~

具体方式是传入一个长度为 50 的颜色数组,再传入一个长度为 50 的位置数组,然后绘制。


挺能的啊,再出个难题!那五光十色的材质是怎么贴出来的呢?

答案也是  shader,而且是具备贴材质能力的 shader,

具体是那种我就不指明了,自己去摸索吧~

(提示:请于之前提及过的两个枚举值的定义处寻找答案)


又扩展了一些知识,当然这些知识是与主体有所关联的,

因为在 CCRenderTexture 上面绘制东西的时候也有关于 shader 方面的东西要注意,

与混合方式差不多的意思,不过这里的是 shader 是否启用 vertexArrayAttribute

没做仔细测试,不清楚 cocos2d  缓存的 kCCShader_Position_uColor 是否默认就启用了 Position 的 vertexArrayAttribute

同上,为了消除不确定因素,这里最好也是使用一下下面的代码:

ccGLEnableVertexAttribs(kCCVertexAttribFlag_Position);


上一些代码来看一看吧(一个专门用来往 RenderTexture 上面画东西的单例类):

ItemRender.h

//
//  ItemRender.h
//  DreamStack
//
//  Created by Bruce Yang on 12-12-26.
//  Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
//

#ifndef DreamStack_ItemRender_h
#define DreamStack_ItemRender_h

#include "cocos2d.h"
#include "Box2D.h"

USING_NS_CC;

class ItemRender {
public:
    void drawSolidPolygon(const b2Vec2* vertices, int32 vertexCount);
    
    void drawSolidCircle(const b2Vec2& center, float32 radius);
    
    static ItemRender* sharedInstance();
    
private:
    // 采用 cocos2d 缓存的 shader 对象~
    void setupCachedShader();
    
    // 采用由自己亲手创建的 shader 对象~
    void setupMyShader();
    
    ItemRender();
    ~ItemRender();
    
    static ItemRender* m_pItemRender;
	CCGLProgram* m_pGLProgram;
	GLint m_iColorLocation;
};

#endif

ItemRender.cpp

//
//  ItemRender.cpp
//  DreamStack
//
//  Created by Bruce Yang on 12-12-26.
//  Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
//

#include "ItemRender.h"

/**
 * p~
 */
void ItemRender::drawSolidPolygon(const b2Vec2* vertices, int32 vertexCount) {
    
    m_pGLProgram->use();
	m_pGLProgram->setUniformForModelViewProjectionMatrix();
    
    ccGLEnableVertexAttribs(kCCVertexAttribFlag_Position);
    ccGLBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
    
    glUniform4f( m_iColorLocation, 1.f, 1.f, 1.f, 1.f);
    glVertexAttribPointer(kCCVertexAttrib_Position, 2, GL_FLOAT, GL_FALSE, 0, vertices);
	glDrawArrays(GL_TRIANGLE_FAN, 0, vertexCount);
    
	CHECK_GL_ERROR_DEBUG();
}


void ItemRender::drawSolidCircle(const b2Vec2& center, float32 radius) {
    
    m_pGLProgram->use();
	m_pGLProgram->setUniformForModelViewProjectionMatrix();
    
    ccGLEnableVertexAttribs(kCCVertexAttribFlag_Position);
    ccGLBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
    
	const float32 t_fSegsCount = 32.f;
	int t_iVertsCount = 32;
	const float32 t_fIncrement = 2.f * b2_pi / t_fSegsCount;
	float32 theta = 0.f;
    
	GLfloat glVertices[t_iVertsCount * 2];
	for (int32 i = 0; i < t_fSegsCount; ++ i) {
		b2Vec2 v = center + radius * b2Vec2(cosf(theta), sinf(theta));
		glVertices[i * 2] = v.x;
		glVertices[i * 2 + 1] = v.y;
		theta += t_fIncrement;
	}
    
	glUniform4f( m_iColorLocation, 1.f, 1.f, 1.f, 1.f);
	glVertexAttribPointer(kCCVertexAttrib_Position, 2, GL_FLOAT, GL_FALSE, 0, glVertices);
	glDrawArrays(GL_TRIANGLE_FAN, 0, t_iVertsCount);
    
	CHECK_GL_ERROR_DEBUG();
}


#pragma mark

ItemRender* ItemRender::sharedInstance() {
    if (!m_pItemRender) {
        m_pItemRender = new ItemRender();
    }
    return m_pItemRender;
}

void ItemRender::setupCachedShader() {
    m_pGLProgram = CCShaderCache::sharedShaderCache()->programForKey(kCCShader_Position_uColor);
    m_iColorLocation = glGetUniformLocation(m_pGLProgram->getProgram(), "u_color");
}

void ItemRender::setupMyShader() {
    m_pGLProgram = NULL;
    m_iColorLocation = (GLint)0;
}

ItemRender::ItemRender() {
    this->setupCachedShader();
}

ItemRender::~ItemRender() {
    
}

ItemRender* ItemRender::m_pItemRender = 0;


还有就是,带 ccGL- 前缀的方法都是 cocos2d 封装的一层带缓存作用的方法。

其内部机制也非常简单,就是判断一下当前要改变到的值和老值是否相同,不同的话才去修改该值。

后续还会对 cocos2d-x 2.x,opengles 2.0 做更深入细致的探索,敬请关注~



    
最新技术文章:
▪Android开发之登录验证实例教程
▪Android开发之注册登录方法示例
▪Android获取手机SIM卡运营商信息的方法
▪Android实现将已发送的短信写入短信数据库的...
▪Android发送短信功能代码
▪Android根据电话号码获得联系人头像实例代码
▪Android中GPS定位的用法实例
▪Android实现退出时关闭所有Activity的方法
▪Android实现文件的分割和组装
▪Android录音应用实例教程
▪Android双击返回键退出程序的实现方法
▪Android实现侦听电池状态显示、电量及充电动...
▪Android获取当前已连接的wifi信号强度的方法
▪Android实现动态显示或隐藏密码输入框的内容
▪根据USER-AGENT判断手机类型并跳转到相应的app...
▪Android Touch事件分发过程详解
▪Android中实现为TextView添加多个可点击的文本
▪Android程序设计之AIDL实例详解
▪Android显式启动与隐式启动Activity的区别介绍
▪Android按钮单击事件的四种常用写法总结
▪Android消息处理机制Looper和Handler详解
▪Android实现Back功能代码片段总结
▪Android实用的代码片段 常用代码总结
▪Android实现弹出键盘的方法
▪Android中通过view方式获取当前Activity的屏幕截...
▪Android提高之自定义Menu(TabMenu)实现方法
▪Android提高之多方向抽屉实现方法
▪Android提高之MediaPlayer播放网络音频的实现方法...
▪Android提高之MediaPlayer播放网络视频的实现方法...
▪Android提高之手游转电视游戏的模拟操控
 


站内导航:


特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

©2012-2021,,E-mail:www_#163.com(请将#改为@)

浙ICP备11055608号-3