顯示具有 Xcode 標籤的文章。 顯示所有文章
顯示具有 Xcode 標籤的文章。 顯示所有文章

2014年4月8日 星期二

xcode自我判定錯誤,所產生的自我迴圈。

1. xxx.h設定一個變數

@property (nonatomic) BOOL deleteMP;




2. xxx.m 不小心寫了一個 包含這個變數的呼叫函數,此處xcode會自行判定為設定呼叫
- (void) setDeleteMP:(int)winPoints
{
    if (self.replaceMP!= YES && self.isFrame == NO) {
        self.deleteMP = YES;
        self.winPoints = winPoints;
}




3. 然後在其他某處使用了

xxx.deleteMP = YES;



4. 於是形成了一個自我迴圈,不斷呼叫 setDeleteMP。
很有趣的一個錯誤產生,居然是xcode的自我判定錯誤,而這個錯誤雖然很容易抓,還是寫出來當作以後的警戒。

2013年12月3日 星期二

怎樣使用Exception Breakpoints

有時候會遇到無法理解的Exception錯誤,Xcode提供了一個Exception Breakpoints的設定方式,以下為xcode5的範例。

 1. 首先到Breakpoints navigator,按下紅色匡所指的箭頭,就會出現,其快速鍵在Xcode5下為cmd+7



2.  在Breakpoints navigator的左下角有一個“+”號,指向它之後,會出現四種特殊的breakpoints選項,第一個就是exception breakpoints

3. 加入一個新的exception breakpoints後,就可以再一次執行會發生錯誤的app code了。如果使用右鍵,也可以修改這個breakpoints的執行條件




4. 再一次執行錯誤的app code後,就會直接停止在真正錯誤的程式行,而不會是跳離開的main.m這個地方了。




原始資料可參考
http://www.alauda.ro/2013/02/03/xcode-4-exception-breakpoints/



重點備註:
在使用cocos2d-iphone 的playBackgroundMusic來播放音檔時,必須要取消exception break,
不然在preload music file會出現錯誤。

refence--> http://stackoverflow.com/questions/18579761/cocos2d-thread-error-when-trying-to-add-background-music

2013年11月12日 星期二

ios7 只能用cocos2D v2.x版了

查詢了官網最新的v1.1RC0版 說明相關資料

* Base SDK 4.1 or newer should be used.
  • Don't report bugs if you are using a previous version.
  • Don't you have Base SDK 4.1 ? Install Xcode 3.2.6 or newer.
  • How to set Base SDK to 4.1: Xcode → Project → Edit project Settings → Build → Base SDK
Only Xcode 4 can be used with cocos2d, Xcode 3 isn't supported anymore.
With Xcode versions below 4.2.1 the compiler will generate warnings about '#pragma clang' statements. These can be safely commented out.
CocosLive is not supported anymore and has been taken out of the templates.
This version still supports armv6 (iPhone 3G, iPod touch 2G and lower), to compile for armv6 use Xcode 4.4.1 or lower.
RC0 has been tested intensively and will also become the stable release of 1.1., if no show stopping bugs will be found.

iPhone5 + iOS6 support


因此可以說沒救了,只能使用v2.1版了,希望程式碼不需要改動太多才好。


官方參考網址
http://www.cocos2d-iphone.org/wiki/doku.php/prog_guide:migrate_to_v2.0


改版過程失敗

1. CCNode.h的position_ 變數,改版後變成 _position , tag_及 contentSize_也是一樣

2. Box2D 中的b2DebugDraw 變成 b2Draw

3....


最重要的是如果外部代碼直接使用OPENGLES1,那就真的難救了。
只能就部分了解的想辦法解決了。

大改寫可能會比較快一些,並且可就了解的部分再最佳化了。 


Xcode的array語法使用誤例

Xcode 的C++語法比較嚴謹

b2Vec2 vertices[vertexCount]; ==> 不可以這樣用,要改成下面的方法
錯誤告示  variable length array of non-POD element type 'b2Vec2'

   
b2Vec2 *vertices = new b2Vec2[vertexCount]; // 修改後可用,xcode比較嚴謹


使用後要手動使用delete來釋放記憶體。
delete [] vertices; 
 
 
另外一種用法,改成vector
a)
std::vector<b2Vec2> vertices(count);
vertices[0].set(2, 3);
vertices[1].set(3, 4);
...

b)
std::vector<b2Vec2> vertices;
vertices.push_back(b2Vec2(2, 3));
vertices.push_back(b2Vec2(3, 4)); 

Box2D在Xcode上的使用設定

基本環境,已經加入cocos2D,然後需要加入Box2D時,其設定如下。

1.將Box2D的source Code加入到Project下,原始碼放在cocos2D/external下,先放在libs次目錄下。


2. 設定Build搜尋目錄

3. 所有使用到Box2D的.m檔,其副檔名改成.mm,這樣才能吃進c++所寫的Box2D







2013年11月2日 星期六

cocos2D-iphone開發輔助工具列表

主要參考自 http://yehnan.blogspot.tw/2012/10/cocos2d-iphone.html

有收費的功能較強,如果真的沒錢,就自己尋找破解版吧。Mac/Windows都有。


點陣字型(bitmap font):
* BMFont(AngelCode Bitmap Font Generator),有Windows版。免費確認可用。使用說明
* Glyph Designer,有Mac版。 收費
* bmGlyph(bitmap glyph),有Mac版。 收費
* fonteditor,有Mac、Java版。不會用,找不到使用說明。
* LabelAtlasCreator,有Mac版。 只能產生plist檔,無Fnt檔,不能用
* Hiero Bitmap Font Tool,太舊已無更新,只能在舊版機器上用,Java


Texture Atlas(Sprite Sheet):
* TexturePacker,有Windows、Mac、Ubuntu版。lite版產生的PNG檔會有雜質。
* Zwoptex,有Mac、Flash版。免費版可用
* Atlas Lite ,Mac App Store上的免費工具
* darkFunction Editor,有Java版。只能產生xml格式
* SpriteHelper,與LevelHelper為姊妹產品,兩者搭配使用效果更佳,有Mac版。
* Sprite Sheet Packer,不能直接輸出cocos2d相容的格式,有Windows版。

xcode內建功能



關卡、場景編輯(Scene and Level):
* CocosBuilder,有Mac版。
* Cocoshop,有Mac版。
* LevelHelper,有Mac版。
* JSONWorldBuilder,有Mac版。

Tilemap磁磚拼貼式地圖:
* Tiled Map Editor,開放原始碼,儲存格式在此,有Windows跟Mac版,Java版不再更新。
* iTileMaps,有iPad、iPhone版。

Particle System粒子系統:
* Particle Designer,有Mac版。
* ParticleCreator,有Mac版。

Physics Engine物理引擎:
* PhysicsEditor,有Windows跟Mac版。
* VertexHelper,有Mac版。
* Mekanimo,有Windows版。
* PhysicsBench,有Mac版。

音訊、音檔編輯與格式轉換:
* Audacity,音訊編輯,開放原始碼,有Windows、Mac跟Linux版。
* WinFF,音訊格式轉換,開放原始碼,有Windows跟Linux版。
* Sound Converter,音訊格式轉換,有Mac版。小檔500K以下不用錢?
* Audio Converter,音訊格式轉換,有Windows版。
* afconvert,音訊格式轉換,Mac OS X命令列模式下的工具。
* GarageBand,有Mac版,錄音,音訊編輯。。

影像編輯:
* GIMP,強大的影像編輯軟體。有Windows、Mac、Linux版。
* Seashore,基本型影像編輯軟體,以GIMP底層技術為基礎,使用與GIMP相同的原生影像檔格式。有Mac版。
* Pixen,適合用來繪製像素畫,具有動畫編輯功能。有Mac版。
* ArtIcons,適合用來繪製游標、小圖示、像素畫。有Windows版。
* Microangelo,適合用來繪製游標、小圖示、像素畫。有Windows版。
* Inkscape,向量圖編輯軟體,開放原始碼,格式為Scalable Vector Graphics (SVG),有Windows、Mac、Ubuntu版。

其他:
* Spriter,製作遊戲中人物動畫(玩家角色、怪物)的工具,有Windows、Mac、Linux版。目前尚未被cocos2d-iphone支援。

很多工具都有提供試用版或功能較少的免費版,可先試用,若不滿意,那就請投資預算囉。

參考資料:
* Steffen Itterheim的The Complete (?) List Of Cocos2D Tools
* abitofcode 的Cocos2d – useful tools
* Ludum Dare » Tools,列出一些有名且免費的工具 

2013年10月24日 星期四

ipad及iphone預設的啓動背景圖

參考網頁 http://www.idev101.com/code/User_Interface/launchImages.html

原始官方文件 https://developer.apple.com/library/ios/DOCUMENTATION/iPhone/Conceptual/iPhoneOSProgrammingGuide/App-RelatedResources/App-RelatedResources.html#//apple_ref/doc/uid/TP40007072-CH6-SW12


其中藍色字的是預設的檔名。 有了這些檔案後,IOS執行程式後,會自動先顯示這些圖檔,才會開始進入程式去執行,因此可以當作Logo來用。



Screen sizes (in pixels) of the iPhone 4S and iPhone 5















2013年10月23日 星期三

cocos2D基本動作例子

以原本template產生的HelloWorldLayer.m來作修改,原本Hello的Label移除,加入兩個移動的飛機圖,然後令他自行移動。


// on "init" you need to initialize your instance
-(id) init
{
    // always call "super" init
    // Apple recommends to re-assign "self" with the "super" return value
    if( (self=[super init])) {
      
        // ask director the the window size
        CGSize size = [[CCDirector sharedDirector] winSize];
      
        /*
        // create and initialize a Label
        CCLabelTTF *label = [CCLabelTTF labelWithString:@"Hello World" fontName:@"Marker Felt" fontSize:64];
      
        // position the label on the center of the screen
        label.position =  ccp( size.width /2 , size.height/2 );
        */
      
        CCSprite *spaceCargoShip = [CCSprite spriteWithFile:@"el-plane.png"];
        [spaceCargoShip setPosition:ccp(size.width/2, size.height/4)];
      
        [spaceCargoShip setScale:0.5];
      
        [spaceCargoShip setRotation:270];
      
        [self addChild:spaceCargoShip];
      
        // 原始點往目標點移動,每次移動5點
        id moveAction = [CCMoveTo actionWithDuration:5.0f position:ccp(size.width, size.height)];
                                            //position:ccp(0, size.height/2)];
        [spaceCargoShip runAction:moveAction];
      
      
        CCSprite *spaceCargoShip2 = [CCSprite spriteWithFile:@"url.png"];
        [spaceCargoShip2 setPosition:ccp(size.width/3, size.height/3)];
      
        [spaceCargoShip2 setScale:0.2];
      
        [spaceCargoShip2 setRotation:270];
      
        [self addChild:spaceCargoShip2];
      
        // 原始點往目標點移動,每次移動5點
        id moveAction2 = [CCMoveTo actionWithDuration:5.0f position:ccp(0, size.height)];
      
        [spaceCargoShip2 runAction:moveAction2];
        

      
      
        // add the label as a child to this Layer
        //[self addChild: label];
    }
    return self;
}


結果截圖


2013年10月21日 星期一

安裝cocos2d

為了寫出更好的遊戲,嘗試使用cocos2D,所以就先試著安裝cocos2d

1. 先到官網 Cocos2D 下載目前的最新版  cocos2d-iphone-2.1.tar.gz  ,或者較舊的版本cocos2d-iphone-1.0.1.tar.gz,兩者皆可,可同時安裝。

2. 下載完後,先將檔案放在一個自建的目錄如Cocos2D,然後點擊檔案後自動解壓縮,就會看到所產生的目錄cocos2d-iphone-1.0.1,或cocos2d-iphone-2.1。

3. 使用終端機terminal



4. 使用cd 到解壓縮之後的子目錄下面,如.../Cocos2D/cocos2d-iphone-1.0.1,然後打入 sudo ./install-templates.sh ,會出現方框需要輸入你的密碼,就會安裝所需的檔案(templates)到Xcode的目錄下了。


5. 如果Xcode在安裝時是正在使用中,就需要關閉後再啓動Xcode,這樣才能使用。


6.  在Xcode下使用File>New Project,就會看見template,左邊上面是cocos2d-1.01,下面是cocos2d-2.1,右邊是1.01的三個template,2.1有四個template。


7. 選取一個來作Hello World的測試,因為是template,所以產生後就立刻可以Run了。如果剛升級到Xcode5.0,因為template是針對Xcode4.0所做的,因此要調整一下LLVM到5.0,不然會無法執行。

 8. 順利執行Hello World在iphone5S的Simulator上


2013年9月28日 星期六

Xcode 下設定Debug用的Marco


需要使用額外的Macro來做Debug用的話,可參考圖中,只要加上所需要的變數如Debug=1,或者DebugMode = 1之類,就可以用了



在程式碼中再加入#ifdef  .... #endif,就可以與Release版區隔開了。
#ifdef DebugMode
   
    if (big3S == YES)
        NSLog(@"胡了大三元");
   
#endif



2013年7月17日 星期三

OpenGL基本實作(十五)(PVRTC 載入)


PVRTC是Apple推薦的texture壓縮格式,因此在iphone 3D Programming中的texture format重點就在PVRTC,以下是將書中範例轉成iPad的實作過程

1. 全新的專案



2.將texture及相關檔案放入,其中cmath及shaders與之前的例子相同,直接沿用。mainViewController相關檔案也是沿用就可以了。


3. PowerVR目錄主要是放置PVRTC的Header及相關定義,

由於需要其PVRTC的textheader來記錄讀取PVRTC的資料,來源有兩個
一個從Apple:  http://developer.apple.com/library/ios/#samplecode/PVRTextureLoader/Listings/Classes_PVRTexture_m.html

一個從安裝的Imagination的SDK: 位置在/Users/Shared/Imagination/PowerVR/GraphicsSDK/SDK_3.1/Tools/PVRTTexture.h 及PVRTGlobal.h

4.ApplicationEngine.cpp是此例子的重點,記錄要用到的texture檔,及讀取檔案的方法

#include "Interfaces.hpp"
#include "ParametricSurface.hpp"

using namespace std;

const string TextureFiles[] = {
    "Grasshopper.png",
/*    "Utopia4444.pvr",
    "Grasshopper565.pvr",
    "Luma8.png",
    "LumaAlpha8.png",
    "Rgb8.png",
    "Rgba8.png",
    "LetterA.png",
    "Utopia.png",*/
    "Astronomy.jpg",
    "Utopia5551.pvr",   //使用Imagination的tool產生的
    "Astronomy4444.pvr", //使用Imagination的tool產生的
    "girl3.pvr",  // RGBA565, use texturetool
    "pets3.pvr",  // use texturetool

};

class ApplicationEngine : public IApplicationEngine {
public:
    ApplicationEngine(IRenderingEngine* renderingEngine);
    ~ApplicationEngine();
    void Initialize(int width, int height);
    void OnFingerUp(ivec2 location) {}
    void OnFingerDown(ivec2 location);
    void OnFingerMove(ivec2 oldLocation, ivec2 newLocation) {}
    void Render() const;
    void UpdateAnimation(float dt);
private:
    void LoadTexture();
    ivec2 m_screenSize;
    ivec2 m_centerPoint;
    IRenderingEngine* m_renderingEngine;
    int m_textureIndex;
    float m_timer;
};
  
IApplicationEngine* CreateApplicationEngine(IRenderingEngine* renderingEngine)
{
    return new ApplicationEngine(renderingEngine);
}

ApplicationEngine::ApplicationEngine(IRenderingEngine* renderingEngine) :
    m_renderingEngine(renderingEngine),
    m_timer(0)
{
}

ApplicationEngine::~ApplicationEngine()
{
    delete m_renderingEngine;
}

void ApplicationEngine::Initialize(int width, int height)
{
    m_screenSize = ivec2(width, height);
    //m_centerPoint = m_screenSize / 2;

    vector<ISurface*> surfaces(1);
    surfaces[0] = new Quad(2, 2);
    m_renderingEngine->Initialize(surfaces); //先產生物件,後面再載入texture
    delete surfaces[0];
  
    m_textureIndex = 0;
    LoadTexture(); // 載入texture
}

void ApplicationEngine::Render() const
{
    vector<Visual> visuals(1);
    visuals[0].Color = vec3(1, 1, 1);
    visuals[0].LowerLeft = ivec2(-100, 0); // -160
    //visuals[0].ViewportSize = ivec2(m_screenSize.x*2, m_screenSize.y);
    visuals[0].ViewportSize = ivec2(m_screenSize.x, m_screenSize.y); // fixed viewPortSize for iPad
    visuals[0].Orientation = Quaternion();
    m_renderingEngine->Render(visuals);
}

// 這裡提供手指按下後,立刻輪換下一張圖檔的功能
void ApplicationEngine::OnFingerDown(ivec2 location)
{
    m_textureIndex++;
    if (m_textureIndex >= sizeof(TextureFiles) / sizeof(TextureFiles[0]))
        m_textureIndex = 0; //超過就回到第一個檔案
  
    LoadTexture();
}


void ApplicationEngine::UpdateAnimation(float dt)
{
    m_timer += dt;  // 每隔一段時間,就輪換一張圖檔
    if (m_timer > 0.75f) { //時間必須大於0.75
        m_timer = 0;
        //OnFingerDown(ivec2(0, 0));
      
        m_textureIndex++;
        if (m_textureIndex >= sizeof(TextureFiles) / sizeof(TextureFiles[0]))
            m_textureIndex = 0;
      
        LoadTexture();
    }
}

void ApplicationEngine::LoadTexture()
{
    string filename = TextureFiles[m_textureIndex];
    string suffix = ".pvr";
    size_t i = filename.rfind(suffix);
    if (i != string::npos && i == (filename.length() - suffix.length())) //最後檔尾為pvr檔的
        m_renderingEngine->SetPvrTexture(filename);  //處理PVRTC
    else
        m_renderingEngine->SetPngTexture(filename);  // 處理一般的PNG/JPG檔

}


5. GLView.h與前例一樣,GLView.mm簡化許多

#import "GLView.h"

@implementation GLView

+ (Class) layerClass
{
    return [CAEAGLLayer class];
}

- (id) initWithFrame: (CGRect) frame
{
    if (self = [super initWithFrame:frame])
    {
        CAEAGLLayer* eaglLayer = (CAEAGLLayer*) self.layer;
        eaglLayer.opaque = YES;

        EAGLRenderingAPI api = kEAGLRenderingAPIOpenGLES2;
        m_context = [[EAGLContext alloc] initWithAPI:api];
       
        if (!m_context) {
            api = kEAGLRenderingAPIOpenGLES1;
            m_context = [[EAGLContext alloc] initWithAPI:api];
        }
       
        if (!m_context || ![EAGLContext setCurrentContext:m_context]) {
            //[self release];
            return nil;
        }
       
        m_resourceManager = CreateResourceManager();

        if (api == kEAGLRenderingAPIOpenGLES1) {
            NSLog(@"Using OpenGL ES 1.1");
            m_renderingEngine = ES1::CreateRenderingEngine(m_resourceManager);
        } else {
            NSLog(@"Using OpenGL ES 2.0");
            m_renderingEngine = ES2::CreateRenderingEngine(m_resourceManager);
        }
       
        m_applicationEngine = CreateApplicationEngine(m_renderingEngine);

        [m_context
            renderbufferStorage:GL_RENDERBUFFER
            fromDrawable:eaglLayer];
               
        int width = CGRectGetWidth(frame);
        int height = CGRectGetHeight(frame);
        m_applicationEngine->Initialize(width, height);
       
        [self drawView: nil];
        m_timestamp = CACurrentMediaTime();
       
        CADisplayLink* displayLink;
        displayLink = [CADisplayLink displayLinkWithTarget:self
                                     selector:@selector(drawView:)];
       
        [displayLink addToRunLoop:[NSRunLoop currentRunLoop]
                     forMode:NSDefaultRunLoopMode];
    }
    return self;
}

- (void) drawView: (CADisplayLink*) displayLink
{
    if (displayLink != nil) {
        float elapsedSeconds = displayLink.timestamp - m_timestamp;
        m_timestamp = displayLink.timestamp;
        m_applicationEngine->UpdateAnimation(elapsedSeconds);
    }
   
    m_applicationEngine->Render();
    [m_context presentRenderbuffer:GL_RENDERBUFFER];
}

//手指按下後
- (void) touchesBegan: (NSSet*) touches withEvent: (UIEvent*) event
{
    UITouch* touch = [touches anyObject];
    CGPoint location  = [touch locationInView: self];
    m_applicationEngine->OnFingerDown(ivec2(location.x, location.y));
}

@end

6. Interfaces.hpp是本例的另一個重點,定義texture格式變數

#pragma once
#include "Vector.hpp"
#include "Quaternion.hpp"
#include <vector>
#include <string>

using std::vector;
using std::string;

enum VertexFlags {
    VertexFlagsNormals = 1 << 0,
    VertexFlagsTexCoords = 1 << 1,
};

enum TextureFormat {
    TextureFormatGray,
    TextureFormatGrayAlpha,
    TextureFormatRgb,
    TextureFormatRgba,
    TextureFormatPvrtcRgb2,
    TextureFormatPvrtcRgba2,
    TextureFormatPvrtcRgb4,
    TextureFormatPvrtcRgba4,
    TextureFormat565,
    TextureFormat5551,
};

struct TextureDescription {
    TextureFormat Format;
    int BitsPerComponent;
    ivec2 Size;
    int MipCount;
};


struct IApplicationEngine {
    virtual void Initialize(int width, int height) = 0;
    virtual void Render() const = 0;
    virtual void UpdateAnimation(float timeStep) = 0;
    virtual void OnFingerUp(ivec2 location) = 0;
    virtual void OnFingerDown(ivec2 location) = 0;
    virtual void OnFingerMove(ivec2 oldLocation, ivec2 newLocation) = 0;
    virtual ~IApplicationEngine() {}
};

struct ISurface {
    virtual int GetVertexCount() const = 0;
    virtual int GetLineIndexCount() const = 0;
    virtual int GetTriangleIndexCount() const = 0;
    virtual void GenerateVertices(vector<float>& vertices,
                                  unsigned char flags = 0) const = 0;
    virtual void GenerateLineIndices(vector<unsigned short>& indices) const = 0;
    virtual void GenerateTriangleIndices(vector<unsigned short>& indices) const = 0;
    virtual ~ISurface() {}
};

struct Visual {
    vec3 Color;
    ivec2 LowerLeft;
    ivec2 ViewportSize;
    Quaternion Orientation;
};

struct IRenderingEngine {
    virtual void Initialize(const vector<ISurface*>& surfaces) = 0;
    virtual void Render(const vector<Visual>& visuals) const = 0;
    virtual void SetPngTexture(const string& file) const = 0;
    virtual void SetPvrTexture(const string& file) const = 0;

    virtual ~IRenderingEngine() {}
};

struct IResourceManager {
    virtual string GetResourcePath() const = 0;
    //virtual TextureDescription LoadPngImage(const string& filename) = 0;
    virtual TextureDescription LoadPvrImage(const string& filename) = 0;
    virtual TextureDescription LoadImage(const string& filename) = 0;
    virtual TextureDescription GenerateCircle() = 0;

    virtual void* GetImageData() = 0;
    virtual void UnloadImage() = 0;
    virtual ~IResourceManager() {}
};

IApplicationEngine* CreateApplicationEngine(IRenderingEngine*);
IResourceManager* CreateResourceManager();

namespace ES1  { IRenderingEngine* CreateRenderingEngine(IResourceManager*); }
namespace ES2  { IRenderingEngine* CreateRenderingEngine(IResourceManager*); }


7. RenderingEngine.ES1.cpp,由於著重在ES2,因此對ES1沒有做什麼修改。ES1與ES2讀取texture檔的方式一樣。

#include <OpenGLES/ES1/gl.h>
#include <OpenGLES/ES1/glext.h>
#include "Interfaces.hpp"
#include "Matrix.hpp"
#include <iostream>
#include <assert.h>

using namespace std;

namespace ES1 {

struct Drawable {
    GLuint VertexBuffer;
    GLuint IndexBuffer;
    int IndexCount;
};

class RenderingEngine : public IRenderingEngine {
public:
    RenderingEngine(IResourceManager* resourceManager);
    void Initialize(const vector<ISurface*>& surfaces);
    void Render(const vector<Visual>& visuals) const;
    void SetPngTexture(const string& name) const;
    void SetPvrTexture(const string& file) const;

private:
    vector<Drawable> m_drawables;
    GLuint m_colorRenderbuffer;
    GLuint m_depthRenderbuffer;
    mat4 m_translation;
    IResourceManager* m_resourceManager;
    mutable float m_offset;
};
   
IRenderingEngine* CreateRenderingEngine(IResourceManager* resourceManager)
{
    return new RenderingEngine(resourceManager);
}

RenderingEngine::RenderingEngine(IResourceManager* resourceManager)
{
    m_resourceManager = resourceManager;
    m_offset = 0;
    glGenRenderbuffersOES(1, &m_colorRenderbuffer);
    glBindRenderbufferOES(GL_RENDERBUFFER_OES, m_colorRenderbuffer);
}

void RenderingEngine::Initialize(const vector<ISurface*>& surfaces)
{
    vector<ISurface*>::const_iterator surface;
    for (surface = surfaces.begin(); surface != surfaces.end(); ++surface) {
       
        // Create the VBO for the vertices.
        vector<float> vertices;
        unsigned char vertexFlags = VertexFlagsTexCoords;
        (*surface)->GenerateVertices(vertices, vertexFlags);
        GLuint vertexBuffer;
        glGenBuffers(1, &vertexBuffer);
        glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
        glBufferData(GL_ARRAY_BUFFER,
                     vertices.size() * sizeof(vertices[0]),
                     &vertices[0],
                     GL_STATIC_DRAW);
       
        // Create a new VBO for the indices if needed.
        int indexCount = (*surface)->GetTriangleIndexCount();
        GLuint indexBuffer;
        if (!m_drawables.empty() && indexCount == m_drawables[0].IndexCount) {
            indexBuffer = m_drawables[0].IndexBuffer;
        } else {
            vector<GLushort> indices(indexCount);
            (*surface)->GenerateTriangleIndices(indices);
            glGenBuffers(1, &indexBuffer);
            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
            glBufferData(GL_ELEMENT_ARRAY_BUFFER,
                         indexCount * sizeof(GLushort),
                         &indices[0],
                         GL_STATIC_DRAW);
        }
       
        Drawable drawable = { vertexBuffer, indexBuffer, indexCount};
        m_drawables.push_back(drawable);
    }

    // Extract width and height from the color buffer.
    int width, height;
    glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES,
                                    GL_RENDERBUFFER_WIDTH_OES, &width);
    glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES,
                                    GL_RENDERBUFFER_HEIGHT_OES, &height);

    // Create a depth buffer that has the same size as the color buffer.
    glGenRenderbuffersOES(1, &m_depthRenderbuffer);
    glBindRenderbufferOES(GL_RENDERBUFFER_OES, m_depthRenderbuffer);
    glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES,
                             width, height);

    // Create the framebuffer object.
    GLuint framebuffer;
    glGenFramebuffersOES(1, &framebuffer);
    glBindFramebufferOES(GL_FRAMEBUFFER_OES, framebuffer);
    glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES,
                                 GL_RENDERBUFFER_OES, m_colorRenderbuffer);
    glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES,
                                 GL_RENDERBUFFER_OES, m_depthRenderbuffer);
    glBindRenderbufferOES(GL_RENDERBUFFER_OES, m_colorRenderbuffer);

    // Set up various GL state.
    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_TEXTURE_2D);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    // Set up the texture state.
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);


    // Set up the material properties.
    vec4 specular(0.5f, 0.5f, 0.5f, 1);
    glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular.Pointer());
    glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 50.0f);

    m_translation = mat4::Translate(0, 0, -7);
}

void RenderingEngine::Render(const vector<Visual>& visuals) const
{
    glClearColor(0.5f, 0.5f, 0.5f, 1);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
   
    vector<Visual>::const_iterator visual = visuals.begin();
    for (int visualIndex = 0; visual != visuals.end(); ++visual, ++visualIndex) {
       
        // Set the viewport transform.
        ivec2 size = visual->ViewportSize;
        ivec2 lowerLeft = visual->LowerLeft;
        glViewport(lowerLeft.x, lowerLeft.y, size.x, size.y);
       
        // Set the light position.
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
       
        // Set the model-view transform.
        mat4 rotation = visual->Orientation.ToMatrix();
        mat4 modelview = rotation * m_translation;
        glLoadMatrixf(modelview.Pointer());
       
        // Set the projection transform.
        float h = 4.0f * size.y / size.x;
        mat4 projection = mat4::Frustum(-2, 2, -h / 2, h / 2, 5, 10);
        glMatrixMode(GL_PROJECTION);
        glLoadMatrixf(projection.Pointer());
       
        // Set the diffuse color.
        vec3 color = visual->Color * 0.75f;
        vec4 diffuse(color.x, color.y, color.z, 1);
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse.Pointer());

        // Draw the surface.
        int stride = sizeof(vec3) +  sizeof(vec2);
        const GLvoid* texCoordOffset = (const GLvoid*) sizeof(vec3);
        const Drawable& drawable = m_drawables[visualIndex];
        glBindBuffer(GL_ARRAY_BUFFER, drawable.VertexBuffer);
        glVertexPointer(3, GL_FLOAT, stride, 0);
        glTexCoordPointer(2, GL_FLOAT, stride, texCoordOffset);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, drawable.IndexBuffer);
        glDrawElements(GL_TRIANGLES, drawable.IndexCount, GL_UNSIGNED_SHORT, 0);
    }
}

void RenderingEngine::SetPngTexture(const string& filename) const
{
    //將檔案的information設定給description,然後將圖檔內容放在m_imageData
    TextureDescription description = m_resourceManager->LoadImage(filename);
    //TextureDescription description = m_resourceManager->GenerateCircle();
   
    GLenum format;
    switch (description.Format) {
        case TextureFormatGray:      format = GL_LUMINANCE;       break;
        case TextureFormatGrayAlpha: format = GL_LUMINANCE_ALPHA; break;
        case TextureFormatRgb:       format = GL_RGB;             break;
        case TextureFormatRgba:      format = GL_RGBA;            break;
    }
   
    GLenum type;
    switch (description.BitsPerComponent) {
        case 8: type = GL_UNSIGNED_BYTE; break;
        case 4:
            if (format == GL_RGBA) {
                type = GL_UNSIGNED_SHORT_4_4_4_4;
                break;
            }
            // intentionally fall through
        default:
            assert(!"Unsupported format.");
    }
   
    void* data = m_resourceManager->GetImageData();
    ivec2 size = description.Size;
    glTexImage2D(GL_TEXTURE_2D, 0, format, size.x, size.y, 0, format, type, data);
    m_resourceManager->UnloadImage();
}

void RenderingEngine::SetPvrTexture(const string& filename) const
{
    TextureDescription description = m_resourceManager->LoadPvrImage(filename);
    unsigned char* data = (unsigned char*) m_resourceManager->GetImageData();
    int width = description.Size.x;
    int height = description.Size.y;
   
    int bitsPerPixel;
    GLenum format;
    bool compressed = true;
    switch (description.Format) {
        case TextureFormatPvrtcRgba2:
            bitsPerPixel = 2;
            format = GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
            break;
        case TextureFormatPvrtcRgb2:
            bitsPerPixel = 2;
            format = GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG;
            break;
        case TextureFormatPvrtcRgba4:
            bitsPerPixel = 4;
            format = GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
            break;
        case TextureFormatPvrtcRgb4:
            bitsPerPixel = 4;
            format = GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG;
            break;
        default:
            compressed = false;
            break;
    }
   
    if (compressed) {
        for (int level = 0; level < description.MipCount; ++level) {
            GLsizei size = max(32, width * height * bitsPerPixel / 8);
            glCompressedTexImage2D(GL_TEXTURE_2D, level, format, width, height, 0, size, data);
            data += size;
            width >>= 1; height >>= 1;
        }
    } else {
        GLenum type;
        switch (description.Format) {
            case TextureFormatRgba:
                assert(description.BitsPerComponent == 4);
                format = GL_RGBA;
                type = GL_UNSIGNED_SHORT_4_4_4_4;
                bitsPerPixel = 16;
                break;
            case TextureFormat565:
                format = GL_RGB;
                type = GL_UNSIGNED_SHORT_5_6_5;
                bitsPerPixel = 16;
                break;
            case TextureFormat5551:
                format = GL_RGBA;
                type = GL_UNSIGNED_SHORT_5_5_5_1;
                bitsPerPixel = 16;
                break;
        }
        for (int level = 0; level < description.MipCount; ++level) {
            glTexImage2D(GL_TEXTURE_2D, level, format, width, height, 0, format, type, data);
            GLsizei size = width * height * bitsPerPixel / 8;
            data += size;
            width >>= 1; height >>= 1;
        }
    }
   
    m_resourceManager->UnloadImage();
}

}


8.RenderingEngine.ES2.cpp

#include <OpenGLES/ES2/gl.h>
#include <OpenGLES/ES2/glext.h>
#include "Interfaces.hpp"
#include "Matrix.hpp"
#include <assert.h>
#include <iostream>
#include <algorithm>

using namespace std;

namespace ES2 {

#define STRINGIFY(A)  #A
#include "./Shaders/TexturedLighting.vert"
#include "./Shaders/TexturedLighting.frag"

struct UniformHandles {
    GLuint Modelview;
    GLuint Projection;
    GLuint NormalMatrix;
    GLuint LightPosition;
    GLint AmbientMaterial;
    GLint SpecularMaterial;
    GLint Shininess;
    GLint Sampler;
};

struct AttributeHandles {
    GLint Position;
    GLint Normal;
    GLint DiffuseMaterial;
    GLint TextureCoord;
};
   
struct Drawable {
    GLuint VertexBuffer;
    GLuint IndexBuffer;
    int IndexCount;
};

class RenderingEngine : public IRenderingEngine {
public:
    RenderingEngine(IResourceManager*);
    void Initialize(const vector<ISurface*>& surfaces);
    void Render(const vector<Visual>& visuals) const;
    void SetPngTexture(const string& name) const;
    void SetPvrTexture(const string& file) const;
private:
    GLuint BuildShader(const char* source, GLenum shaderType) const;
    GLuint BuildProgram(const char* vShader, const char* fShader) const;
    vector<Drawable> m_drawables;
    GLuint m_colorRenderbuffer;
    GLuint m_depthRenderbuffer;
    mat4 m_translation;
    UniformHandles m_uniforms;
    AttributeHandles m_attributes;
    IResourceManager* m_resourceManager;
};

IRenderingEngine* CreateRenderingEngine(IResourceManager* resourceManager)
{
    return new RenderingEngine(resourceManager);
}

RenderingEngine::RenderingEngine(IResourceManager* resourceManager)
{
    m_resourceManager = resourceManager;
    glGenRenderbuffers(1, &m_colorRenderbuffer);
    glBindRenderbuffer(GL_RENDERBUFFER, m_colorRenderbuffer);
}

void RenderingEngine::Initialize(const vector<ISurface*>& surfaces)
{
    vector<ISurface*>::const_iterator surface;
    for (surface = surfaces.begin(); surface != surfaces.end(); ++surface) {
       
        // Create the VBO for the vertices.
        vector<float> vertices;
        unsigned char vertexFlags = VertexFlagsTexCoords;
        (*surface)->GenerateVertices(vertices, vertexFlags);
        GLuint vertexBuffer;
        glGenBuffers(1, &vertexBuffer);
        glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
        glBufferData(GL_ARRAY_BUFFER,
                     vertices.size() * sizeof(vertices[0]),
                     &vertices[0],
                     GL_STATIC_DRAW);
       
        // Create a new VBO for the indices if needed.
        int indexCount = (*surface)->GetTriangleIndexCount();
        GLuint indexBuffer;
        if (!m_drawables.empty() && indexCount == m_drawables[0].IndexCount) {
            indexBuffer = m_drawables[0].IndexBuffer;
        } else {
            vector<GLushort> indices(indexCount);
            (*surface)->GenerateTriangleIndices(indices);
            glGenBuffers(1, &indexBuffer);
            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
            glBufferData(GL_ELEMENT_ARRAY_BUFFER,
                         indexCount * sizeof(GLushort),
                         &indices[0],
                         GL_STATIC_DRAW);
        }
       
        Drawable drawable = { vertexBuffer, indexBuffer, indexCount};
        m_drawables.push_back(drawable);
    }
   
    // Extract width and height.
    int width, height;
    glGetRenderbufferParameteriv(GL_RENDERBUFFER,
                                 GL_RENDERBUFFER_WIDTH, &width);
    glGetRenderbufferParameteriv(GL_RENDERBUFFER,
                                 GL_RENDERBUFFER_HEIGHT, &height);
   
    // Create a depth buffer that has the same size as the color buffer.
    glGenRenderbuffers(1, &m_depthRenderbuffer);
    glBindRenderbuffer(GL_RENDERBUFFER, m_depthRenderbuffer);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);
   
    // Create the framebuffer object.
    GLuint framebuffer;
    glGenFramebuffers(1, &framebuffer);
    glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                              GL_RENDERBUFFER, m_colorRenderbuffer);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
                              GL_RENDERBUFFER, m_depthRenderbuffer);
    glBindRenderbuffer(GL_RENDERBUFFER, m_colorRenderbuffer);
   
    // Create the GLSL program.
    GLuint program = BuildProgram(SimpleVertexShader, SimpleFragmentShader);
    glUseProgram(program);

    // Extract the handles to attributes and uniforms.
    m_attributes.Position = glGetAttribLocation(program, "Position");
    m_attributes.Normal = glGetAttribLocation(program, "Normal");
    m_attributes.DiffuseMaterial = glGetAttribLocation(program, "DiffuseMaterial");
    m_attributes.TextureCoord = glGetAttribLocation(program, "TextureCoord");
    m_uniforms.Projection = glGetUniformLocation(program, "Projection");
    m_uniforms.Modelview = glGetUniformLocation(program, "Modelview");
    m_uniforms.NormalMatrix = glGetUniformLocation(program, "NormalMatrix");
    m_uniforms.LightPosition = glGetUniformLocation(program, "LightPosition");
    m_uniforms.AmbientMaterial = glGetUniformLocation(program, "AmbientMaterial");
    m_uniforms.SpecularMaterial = glGetUniformLocation(program, "SpecularMaterial");
    m_uniforms.Shininess = glGetUniformLocation(program, "Shininess");
    m_uniforms.Sampler = glGetUniformLocation(program, "Sampler");
   
    // Set the active sampler to stage 0.  Not really necessary since the uniform
    // defaults to zero anyway, but good practice.
    glActiveTexture(GL_TEXTURE0);
    glUniform1i(m_uniforms.Sampler, 0);
   
    // Set up the texture state.
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);


    // Set up some default material parameters.
    glUniform3f(m_uniforms.AmbientMaterial, 0.04f, 0.04f, 0.04f);
    glUniform3f(m_uniforms.SpecularMaterial, 0.5, 0.5, 0.5);
    glUniform1f(m_uniforms.Shininess, 50);

    // Initialize various state.
    glEnableVertexAttribArray(m_attributes.Position);
    glEnableVertexAttribArray(m_attributes.TextureCoord);
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    // Set up transforms.
    m_translation = mat4::Translate(0, 0, -7);
}

void RenderingEngine::Render(const vector<Visual>& visuals) const
{
    glClearColor(0.5f, 0.5f, 0.5f, 1);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    vector<Visual>::const_iterator visual = visuals.begin();
    for (int visualIndex = 0; visual != visuals.end(); ++visual, ++visualIndex) {

        // Set the viewport transform.
        ivec2 size = visual->ViewportSize;
        ivec2 lowerLeft = visual->LowerLeft;
        glViewport(lowerLeft.x, lowerLeft.y, size.x, size.y);
       
        // Set the model-view transform.
        mat4 modelview = m_translation;
        glUniformMatrix4fv(m_uniforms.Modelview, 1, 0, modelview.Pointer());
       
        // Set the projection transform.
        float h = 4.0f * size.y / size.x;
       
        // 參數的調整方向暫時還無法瞭解,使用試誤法找出最佳值,只要near值大於7.x就無法顯示影像,此處在調整顯示的位置與大小
        //mat4 projectionMatrix = mat4::Frustum(-2, 2, -h / 2, h / 2, 5, 10); // original
        mat4 projectionMatrix = mat4::Frustum(-1.5f, 0.8f,  -1, 1, 7.0f, 10);

       
        glUniformMatrix4fv(m_uniforms.Projection, 1, 0, projectionMatrix.Pointer());
       
        // Set the diffuse color.
        vec3 color = visual->Color * 0.75f;
        glVertexAttrib4f(m_attributes.DiffuseMaterial, color.x, color.y, color.z, 1);
       
        // Draw the surface.
        int stride = sizeof(vec3) + sizeof(vec2);
        const GLvoid* texCoordOffset = (const GLvoid*) sizeof(vec3);
        GLint position = m_attributes.Position;
        GLint texCoord = m_attributes.TextureCoord;
        const Drawable& drawable = m_drawables[visualIndex];
        glBindBuffer(GL_ARRAY_BUFFER, drawable.VertexBuffer);
        glVertexAttribPointer(position, 3, GL_FLOAT, GL_FALSE, stride, 0);
        glVertexAttribPointer(texCoord, 2, GL_FLOAT, GL_FALSE, stride, texCoordOffset);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, drawable.IndexBuffer);
        glDrawElements(GL_TRIANGLES, drawable.IndexCount, GL_UNSIGNED_SHORT, 0);
    }
}

GLuint RenderingEngine::BuildShader(const char* source, GLenum shaderType) const
{
    GLuint shaderHandle = glCreateShader(shaderType);
    glShaderSource(shaderHandle, 1, &source, 0);
    glCompileShader(shaderHandle);
   
    GLint compileSuccess;
    glGetShaderiv(shaderHandle, GL_COMPILE_STATUS, &compileSuccess);
   
    if (compileSuccess == GL_FALSE) {
        GLchar messages[256];
        glGetShaderInfoLog(shaderHandle, sizeof(messages), 0, &messages[0]);
        cout << messages;
        exit(1);
    }
   
    return shaderHandle;
}

GLuint RenderingEngine::BuildProgram(const char* vertexShaderSource,
                                     const char* fragmentShaderSource) const
{
    GLuint vertexShader = BuildShader(vertexShaderSource, GL_VERTEX_SHADER);
    GLuint fragmentShader = BuildShader(fragmentShaderSource, GL_FRAGMENT_SHADER);
   
    GLuint programHandle = glCreateProgram();
    glAttachShader(programHandle, vertexShader);
    glAttachShader(programHandle, fragmentShader);
    glLinkProgram(programHandle);
   
    GLint linkSuccess;
    glGetProgramiv(programHandle, GL_LINK_STATUS, &linkSuccess);
    if (linkSuccess == GL_FALSE) {
        GLchar messages[256];
        glGetProgramInfoLog(programHandle, sizeof(messages), 0, &messages[0]);
        cout << messages;
        exit(1);
    }
   
    return programHandle;
}

void RenderingEngine::SetPngTexture(const string& filename) const
{
    //將檔案的information設定給description,然後將圖檔內容放在m_imageData
    TextureDescription description = m_resourceManager->LoadImage(filename);
    //TextureDescription description = m_resourceManager->GenerateCircle();
   
    GLenum format;
    switch (description.Format) {
        case TextureFormatGray:      format = GL_LUMINANCE;       break;
        case TextureFormatGrayAlpha: format = GL_LUMINANCE_ALPHA; break;
        case TextureFormatRgb:       format = GL_RGB;             break;
        case TextureFormatRgba:      format = GL_RGBA;            break;
    }

    GLenum type;
    switch (description.BitsPerComponent) {
        case 8: type = GL_UNSIGNED_BYTE; break;
        /*case 4:  // PNG檔沒有4bits的,所以可移除
            if (format == GL_RGBA) {
                type = GL_UNSIGNED_SHORT_4_4_4_4;
                break;
            }
            // intentionally fall through */

        default:
            assert(!"Unsupported format.");
    }

    void* data = m_resourceManager->GetImageData();
    ivec2 size = description.Size;
    glTexImage2D(GL_TEXTURE_2D, 0, format, size.x, size.y, 0, format, type, data);
    m_resourceManager->UnloadImage();
}

void RenderingEngine::SetPvrTexture(const string& filename) const
{
    TextureDescription description = m_resourceManager->LoadPvrImage(filename);
    unsigned char* data = (unsigned char*) m_resourceManager->GetImageData();
    int width = description.Size.x;
    int height = description.Size.y;
   
    int bitsPerPixel;
    GLenum format;
    bool compressed = true;
   
    switch (description.Format) {
        case TextureFormatPvrtcRgba2:
            bitsPerPixel = 2;
            format = GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
            break;
        case TextureFormatPvrtcRgb2:
            bitsPerPixel = 2;
            format = GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG;
            break;
        case TextureFormatPvrtcRgba4:
            bitsPerPixel = 4;
            format = GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
            break;
        case TextureFormatPvrtcRgb4:
            bitsPerPixel = 4;
            format = GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG;
            break;
        default:
            compressed = false;  // 如果不是以上格式,就是非壓縮模式
            break;
    }
   
    if (compressed) { // 對每一個 Mipmap資料都去讀取進來
        for (int level = 0; level < description.MipCount; ++level) {
            GLsizei size = max(32, width * height * bitsPerPixel / 8);
            glCompressedTexImage2D(GL_TEXTURE_2D, level, format, width, height, 0, size, data);
            data += size; // 將pointer指向下一個Mipmap的位置
            width >>= 1; height >>= 1;  // 每一個Mipmap都是前一個的一半大小
        }
    } else {
        GLenum type;
        switch (description.Format) {
            case TextureFormatRgba:
                assert(description.BitsPerComponent == 4);
                format = GL_RGBA;
                type = GL_UNSIGNED_SHORT_4_4_4_4;
                bitsPerPixel = 16;
                break;
            case TextureFormat565:
                format = GL_RGB;
                type = GL_UNSIGNED_SHORT_5_6_5;
                bitsPerPixel = 16;
                break;
            case TextureFormat5551:
                format = GL_RGBA;
                type = GL_UNSIGNED_SHORT_5_5_5_1;
                bitsPerPixel = 16;
                break;
        }
        for (int level = 0; level < description.MipCount; ++level) {
            GLsizei size = width * height * bitsPerPixel / 8;
            glTexImage2D(GL_TEXTURE_2D, level, format, width, height, 0, format, type, data);
            data += size;
            width >>= 1; height >>= 1;
        }
    }
   
    m_resourceManager->UnloadImage();
}

}

9. ResourceManager.mm,處理載入檔案的細節程式碼

#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>
#import <string>
#import <iostream>
#import "Interfaces.hpp"
#import "./PowerVR/PVRTTexture.h"

using namespace std;

class ResourceManager : public IResourceManager {
public:
    ResourceManager()
    {
        m_imageData = 0;
    }
    string GetResourcePath() const
    {
        NSString* bundlePath =[[NSBundle mainBundle] resourcePath];
        return [bundlePath UTF8String];
    }
    TextureDescription LoadImage(const string& file)
    {
        NSString* basePath = [NSString stringWithUTF8String:file.c_str()];
        NSString* resourcePath = [[NSBundle mainBundle] resourcePath];
        NSString* resourcePath2 = [resourcePath stringByAppendingString:@"/Textures"]; // add by kk
        NSString* fullPath = [resourcePath2 stringByAppendingPathComponent:basePath];
        UIImage* uiImage = [UIImage imageWithContentsOfFile:fullPath];
               
        TextureDescription description;
        description.Size.x = CGImageGetWidth(uiImage.CGImage);
        description.Size.y = CGImageGetHeight(uiImage.CGImage);
        description.BitsPerComponent = 8;  // 此處所讀檔案一定是8bits模式, normal picture file
        description.Format = TextureFormatRgba;
        description.MipCount = 1;
        m_hasPvrHeader = false;

        // one component = R, G, B, A的任一個, bpp = bits per pixel , so normal png = RGBA 32bits = 32bpp
        int bpp = description.BitsPerComponent / 2;  // RGBA = 24bits = 4bytes = 8(bits)/2
       
        int byteCount = description.Size.x * description.Size.y * bpp;// 這裡的bpp 是bytes per pixel
       
        unsigned char* data = (unsigned char*) calloc(byteCount, 1);
       
        CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
        CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big;
       
        // 當data這個記憶區塊定址好了,使用CGBitmapContextCreate這個function,將其context轉換制定成一個圖形儲存空間
        CGContextRef context = CGBitmapContextCreate(data,
            description.Size.x,
            description.Size.y,
            description.BitsPerComponent,
            bpp * description.Size.x,
            colorSpace,
            bitmapInfo);
       
        CGColorSpaceRelease(colorSpace);
        CGRect rect = CGRectMake(0, 0, description.Size.x, description.Size.y);
        CGContextDrawImage(context, rect, uiImage.CGImage);
        CGContextRelease(context);
       
        m_imageData = [NSData dataWithBytesNoCopy:data length:byteCount freeWhenDone:YES];
        //使用方法 http://stackoverflow.com/questions/8691997/behavior-of-nsdata-initwithbytesnocopylengthfreewhendone
       
        return description;
    }

    TextureDescription GenerateCircle() // 在OPENGLES上面畫上一個圓圈
    {
        TextureDescription description;
        description.Size = ivec2(256, 256);
        description.BitsPerComponent = 8;
        description.Format = TextureFormatRgba;

        int bpp = description.BitsPerComponent / 2;
        int byteCount = description.Size.x * description.Size.y * bpp;
        unsigned char* data = (unsigned char*) calloc(byteCount, 1);
       
        CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
        CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big;
        CGContextRef context = CGBitmapContextCreate(data,
                                                     description.Size.x,
                                                     description.Size.y,
                                                     description.BitsPerComponent,
                                                     bpp * description.Size.x,
                                                     colorSpace,
                                                     bitmapInfo);
        CGColorSpaceRelease(colorSpace);
               
        CGRect rect = CGRectMake(5, 5, 246, 246);
        CGContextSetRGBFillColor(context, 0, 0, 1, 1);
        CGContextFillEllipseInRect(context, rect);

        CGContextRelease(context);
       
        m_imageData = [NSData dataWithBytesNoCopy:data length:byteCount freeWhenDone:YES];
        return description;
    }
  
    TextureDescription LoadPvrImage(const string& file)
    {
        NSString* basePath = [NSString stringWithUTF8String:file.c_str()];
        NSString* resourcePath = [[NSBundle mainBundle] resourcePath];
        NSString* resourcePath2 = [resourcePath stringByAppendingString:@"/Textures"]; // 圖檔的次目錄
        NSString* fullPath = [resourcePath2 stringByAppendingPathComponent:basePath];
       
        m_imageData = [NSData dataWithContentsOfFile:fullPath];
        m_hasPvrHeader = true;
        PVR_Texture_Header* header = (PVR_Texture_Header*) [m_imageData bytes];
        bool hasAlpha = header->dwAlphaBitMask ? true : false;

        TextureDescription description;
       
        //低精度的非壓縮格式(565,5551,4444)往往被忽視。不同於塊壓縮,它們不會導致斑點影像中的工件。雖然他們不能很好地工作,他們是相當不錯的圖像,平滑的色彩梯度保存在照片中的細節,並保持乾淨的線條簡單的矢量藝術。
        switch (header->dwpfFlags & PVRTEX_PIXELTYPE) {
            case OGL_RGB_565:  //
                description.Format = TextureFormat565;
                break;
            case OGL_RGBA_5551:
                description.Format = TextureFormat5551;
                break;
            case OGL_RGBA_4444:
                description.Format = TextureFormatRgba;
                description.BitsPerComponent = 4;
                break;
            case OGL_PVRTC2:   
                description.Format = hasAlpha ? TextureFormatPvrtcRgba2 :
                                                TextureFormatPvrtcRgb2;
                break;
            case OGL_PVRTC4:
                description.Format = hasAlpha ? TextureFormatPvrtcRgba4 :
                                                TextureFormatPvrtcRgb4;
                break;
            default:
                assert(!"Unsupported PVR image.");
                break;
        }
       
        description.Size.x = header->dwWidth;
        description.Size.y = header->dwHeight;
        description.MipCount = header->dwMipMapCount;
       
        if (description.MipCount ==0) // 當Mipmap count 為零時,強制設為一
            description.MipCount =1; // 目前還不知道0與1的差別。

       
        return description;
    }
    void* GetImageData()
    {
        if (!m_hasPvrHeader)
            return (void*) [m_imageData bytes];
       
        PVR_Texture_Header* header = (PVR_Texture_Header*) [m_imageData bytes];
        char* data = (char*) [m_imageData bytes];
        unsigned int headerSize = header->dwHeaderSize;
        return data + headerSize;
    }
    void UnloadImage()
    {
        m_imageData = 0;
    }
private:
    NSData* m_imageData;
    bool m_hasPvrHeader;
};

IResourceManager* CreateResourceManager()
{
    return new ResourceManager();
}


10. run script的部分,使用apple的texturetool,及時產生PVRTC檔,雖然不需要及時,只是展示了可及時Encode的功能罷了。






11. 結果顯示,只是一個平面,用來顯示texture檔的讀取並顯示出來。可以自動輪動。