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檔的讀取並顯示出來。可以自動輪動。




2013年7月16日 星期二

C++字串string使用說明書

C++ 的std::string非常強大方便,但是如果考慮到速度效率,則還是使用原來的c string比較好。

另外std::string::npos原來是代表 -1,但是因為它的型態是size_t,因此就變成了unsigned int,因此就變成了此整數的最大值。大約為4294967295

在使用上sting::npos代表不等於,因此作為比較上的使用例子如下
string s1( "123456789" );
  size_t x = s1.find_first_of( '0', 0 );
  
  if (x == string::npos)  // 代表找不到
  {
       cout << "not find" << endl;
 }
 




使用說明的完整內容如下,轉貼自網路

傳統c字串使用'\0'作為結束字元,而c++字串string不使用這種方式來處理字串
c++字串原型如下
typedef basic_string<char>     string;         
typedef basic_string<wchar_t>  wstring;        //寬字元
若要使用需引入string標頭檔,basic_string這個版樣類別一般稱為基本字串類別

字串的宣告
  string s;                         空字串,string()
  string s="";                      空字串
  string s="String";                包含"String"的字串   
  string s("String");               包含"String"的字串,string(char*)  
  string s(5,'A');                  包含5個A字串的字串AAAAA,string(int,char)  
  string s=r;                       r為string字串,複製一份r的字串做為字串,string(const string&)
  string s(r,2,4);                  r為string字串,複製r[2]開始的4個字元做為字串,string(const string&,int,int)  
  string s(r.begin()+2,r.end());    r為string字串,複製r[0+2]開始到末端字元做為字串,string(const string&,string::iterator,string::iterator)  
  string s(r+2,4);                  r為傳統字串,r+2的char位置開始4個字元做為字串,string(char*,int)
  不能使用單一字元及數字做為初始化,例:
  string s='A';
  string s=20;
 
string迭代器
  string::iterator iter;
  string::iterator被定義在string的公用區域裡,iter的作用有如指標一般能利用+,-,++,--改變所指向的字元,也能用*取出字元值
  若字串為常數字串,可使用string::const_iterator,和常數特性一樣不能做為修改
 
string類別函式
  string::iterator begin()      回傳開頭位置
  string::iterator end()        回傳結束位置
  int size()                    回傳字串長度                     
  int length()                  回傳字串長度
  string::npos                  其值為系統代表的最大正整數
  operator[]                    下標運算子,與傳統字串操作的效果一樣,用在等號左邊或右邊都可以
  at()                          與下標運算子一樣,但會檢查是否超出下標範圍,若超出會立即終止
  operator=                     指定運算子,可指定為字元,傳統字串,或另一個string
  c_str()                       以傳統字串型式輸出
  operator==                    以下七個皆為用於string比較的運算子
  operator!=
  operator>
  operator>=
  operator<
  operator<=
  operator==
  operator+                     用於string相加,其中一個運算元必須是string,另一個運算元可以字元或傳統字串
  operator+=                    用於string相加,也可以是字元或傳統字串和string相加
  append(string)                字串相加,與一個string相加
  append(string::iterator,string::iterator)字串相加,與迭代器的範圍字串相加
  append(string,int,int)        字串相加,與一個string相加,但指定其由第幾個足標到第幾個足標範圍內的字串相加
  append(char*)                 字串相加,與一個傳統字串相加
  append(char*,int)             字串相加,與一個傳統字串相加,並指定相加的字數範圍
  append(int,char)              字串相加,相加多少個字元
  insert(int,string)            插入字串,從第一個參數的足標開始插入
  insert(int,string,int,int)    插入字串,以第一個參數的足標開始插入,插入的範圍是三和四參數範圍的足標
  insert(string::iterator,string::iterator,string::iterator)插入字串,從第一個迭代器插入,插入範圍是第二和第三個迭代器的範圍
  insert(int,char*)             插入字串,以第一個參數的足標開始插入
  insert(int,char*,int)         插入字串,以第一個參數的足標開始插入,第三個參數為字元數
  insert(int,int,char)          插入字串,以第一個參數的足標開始插入,此為插入n個字元
  insert(string::iterator,char) 插入字串,以第一個參數的迭代器開始插入,此為插入一個字元
    //除了參數中有使用迭代器的intert()以外,其他均會回傳字件參考型別
  substr(int)                   複製子字串,由參數的足標開始到結束被複製出來
  substr(int,int)               複製子字串,由第一個參數的走標開始第二個參數個字元數,複製出來
  find( ,int)                   搜尋子字串,第一個參數可以是string,傳統字串或字元,第二個參數代表從第幾個足標位置開始搜尋
  find(char*,int,int)           針對傳統字串的搜尋子字串,第三個參數代表前幾個字元,以前n個字元做為搜尋
  rfind()                       由後方開始搜尋,參數請參考find()不同的是,第二個參數的意義為由第二個參數往前搜尋
  find_first_of()               搜尋字元,回傳第一個找到的位置,參數請參考find()
  find_last_of()                搜尋字元,回傳最後一個找到的位置,參數請參考find()
  find_first_not_of()           搜尋字元,回傳第一個不是參數裡的字元的位置,參數請參考find()
  find_last_not_of()            搜尋字元,回傳最後一個不是參數裡的字元的位置,參數請參考find()
    //find若找不到符合條件,會回傳string::npos
    //find()與Rfind()是搜尋字串,另外四個是搜尋字元,只要是符合第一個參數裡有的字元就算是了 例:
    //搜尋只要是數字的第一個字元位置str.find_first_of("0123456789");
    //搜尋各種左括號的第一個字元位置str.find_first_of("[{(<");
  replace(int,int,string)       取代子字串,這裡的五個取代子字串前兩個參數都是從第幾個足標開始的幾個字元數開始取代
  replace(int,int,string,int,int)取代子字串,要取代的字串是第三個參數的第幾個足標開始的幾個字元數
  replace(int,int,char*)        用於傳統字串
  replace(int,int,char*,int)    用於傳統字串,第四個參收是字元數
  replace(int,int,int,char)     取代的字串為n(參3)個字元(參4)
  replace(string::iterator,string::iterator,string)使用迭代器指定被取代的範圍
  replace(string::iterator,string::iterator,char*)
  replace(string::iterator,string::iterator,char*,int)最後一個參數代表字元數
  replace(string::iterator,string::iterator,int,char)取代n個字元
  erase()                           清除所有字串
  erase(int)                        清除參數1足標以後的字串
  erase(int,int)                    清除參數1足標以後的n(參2)個字元數
  erase(string::iterator)           清除迭代器所指的以後的字串  
  erase(string::iterator,string::iterator)清除兩迭代器所指範圍的字串
  bool empty()                 檢查是否為空字串
  resize(size_type n,char ch)  調整字串長度為n,如果n比原字串大則多出的字元補上ch字元,若是小則去除多餘的字串  
  swap(string& a,string& b)    交換兩字串

2013年7月15日 星期一

選擇一個 open source engine for game

選擇一個適合且免費的遊戲引擎,目前的首選

2D 使用
Cocos2D – Framework for building 2D games for iPod Touch, iPhone and iPad. Claims to be used by more than 2500 games on the App Store.

Sparrow Framework
新發現的game engine,只有2D功能。目前看來還蠻多游戲用它來開發,表列在此

3D 使用
Oolong – Free to use game engine written in C++ that lets you create new iOS games and port existing games to iOS devices. 更新只到 2012年,原因可能是開發者已經到業界上班了。

開放原始碼的遊戲引擎,使用Bullet物理引擎,但文件較不完整。遊戲開發初學者不建議使用。


Irrlicht Engine一個開源的跨平台3D engine,資料可參考wiki,似乎很強大,但好像沒有看到iphone上有誰使用它來開發。


Unreal Development Kit – Free version of the industry-leading Unreal Engine III. UDK is used to create games, apps and advanced 3D simulations. Supports iOS and Android. 沒有OPEN source

NME – Free open source framework that lets you develop Android, iOS, BlackBerry and Windows Phone apps from a single codebase. No C or C++ skills required.

3D engine難選,怕是花了時間學了,最後卻要收費並且也未必好用。Unity最多人推薦,但收費也最貴,暫時先直接使用OPENGLES,寫一些基本就好了。


參考網址
http://maniacdev.com/2009/08/the-open-source-iphone-game-engine-comparison

http://www.mobyaffiliates.com/blog/ios-android-mobile-game-development-tools-frameworks-engines-resources/

http://stackoverflow.com/questions/12068018/choosing-3d-engine-for-ios-in-c

2013年7月14日 星期日

CGBitmapInfo 資料整理

 CGBitmapInfo 在自行產生圖檔資料時,需要設定此圖檔的相關資料,此時就要用下面參數來設定。

enum CGImageAlphaInfo {
    kCGImageAlphaNone,               /* For example, RGB. */
    kCGImageAlphaPremultipliedLast,  /* For example, premultiplied RGBA */
    kCGImageAlphaPremultipliedFirst, /* For example, premultiplied ARGB */
    kCGImageAlphaLast,               /* For example, non-premultiplied RGBA */
    kCGImageAlphaFirst,              /* For example, non-premultiplied ARGB */
    kCGImageAlphaNoneSkipLast,       /* For example, RBGX. */
    kCGImageAlphaNoneSkipFirst,      /* For example, XRGB. */
    kCGImageAlphaOnly                /* No color data, alpha data only */
};
typedef enum CGImageAlphaInfo CGImageAlphaInfo;

enum {
    kCGBitmapAlphaInfoMask = 0x1F,   //-> CGImageAlphaInfo
    kCGBitmapFloatComponents = (1 << 8),
  
    kCGBitmapByteOrderMask = 0x7000,
    kCGBitmapByteOrderDefault = (0 << 12),
    kCGBitmapByteOrder16Little = (1 << 12),
    kCGBitmapByteOrder32Little = (2 << 12),
    kCGBitmapByteOrder16Big = (3 << 12),
    kCGBitmapByteOrder32Big = (4 << 12)
};
typedef uint32_t CGBitmapInfo; /* Available in MAC OS X 10.4 & later. */
 
參考code
http://stackoverflow.com/questions/6073259/getting-rgb-pixel-data-from-cgimage
 
使用參考例 
CGBitmapContextCreate()的使用方法 

 
kCGBitmapAlphaInfoMask
The alpha information mask. Use this to extract alpha information that specifies whether a bitmap contains an alpha channel and how the alpha channel is generated.
Available in OS X v10.4 and later.
Declared in CGImage.h.
kCGBitmapFloatComponents
The components of a bitmap are floating-point values.
Available in OS X v10.4 and later.
Declared in CGImage.h.
kCGBitmapByteOrderMask
The byte ordering of pixel formats.
Available in OS X v10.4 and later.
Declared in CGImage.h.
kCGBitmapByteOrderDefault
The default byte order.
Available in OS X v10.4 and later.
Declared in CGImage.h.
kCGBitmapByteOrder16Little
16-bit, little endian format.
Available in OS X v10.4 and later.
Declared in CGImage.h.
kCGBitmapByteOrder32Little
32-bit, little endian format.
Available in OS X v10.4 and later.
Declared in CGImage.h.
kCGBitmapByteOrder16Big
16-bit, big endian format.
Available in OS X v10.4 and later.
Declared in CGImage.h.
kCGBitmapByteOrder32Big
32-bit, big endian format.
Available in OS X v10.4 and later.
Declared in CGImage.h.
 
 
kCGImageAlphaFirst
The alpha component is stored in the most significant bits of each pixel. For example, non-premultiplied ARGB.
Available in OS X v10.0 and later.
Declared in CGImage.h.
kCGImageAlphaLast
The alpha component is stored in the least significant bits of each pixel. For example, non-premultiplied RGBA.
Available in OS X v10.0 and later.
Declared in CGImage.h.
kCGImageAlphaNone
There is no alpha channel. If the total size of the pixel is greater than the space required for the number of color components in the color space, the least significant bits are ignored. This value is equivalent to kCGImageAlphaNoneSkipLast.
Available in OS X v10.0 and later.
Declared in CGImage.h.
kCGImageAlphaNoneSkipFirst
There is no alpha channel. If the total size of the pixel is greater than the space required for the number of color components in the color space, the most significant bits are ignored.
Available in OS X v10.0 and later.
Declared in CGImage.h.
kCGImageAlphaOnly
There is no color data, only an alpha channel.
Available in OS X v10.3 and later.
Declared in CGImage.h.
kCGImageAlphaNoneSkipLast
There is no alpha channel. If the total size of the pixel is greater than the space required for the number of color components in the color space, the least significant bits are ignored. This value is equivalent to kCGImageAlphaNone.
Available in OS X v10.0 and later.
Declared in CGImage.h.
kCGImageAlphaPremultipliedFirst
The alpha component is stored in the most significant bits of each pixel and the color components have already been multiplied by this alpha value. For example, premultiplied ARGB.
Available in OS X v10.0 and later.
Declared in CGImage.h.
kCGImageAlphaPremultipliedLast
The alpha component is stored in the least significant bits of each pixel and the color components have already been multiplied by this alpha value. For example, premultiplied RGBA.
Available in OS X v10.0 and later.
Declared in CGImage.h.