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

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年6月15日 星期六

苹果在iOS 7中弃用了哪些API

我们知道苹果在iOS 7 SDK中开放了超过1500个新的API,但我们也知道随着开发技术和设备的进步,有些过时的API是必须废弃掉的,我们来看看苹果在iOS 7中弃用了哪些API。

轉貼自  http://www.cocoachina.com/applenews/devnews/2013/0614/6411.html


1.The Map Kit framework includes deprecations for the MKOverlayView class and its various subclasses. The existing overlay views have been replaced with an updated set of overlay renderer objects that descend from the MKOverlayRenderer class. For more information about the classes of this framework, see Map Kit Framework Reference.
2.The AudioSession API in the Audio Toolbox framework is deprecated. Applications should use theAVAudioSession  class in the AV Foundation framework instead.
3.The CLRegion class in the Core Location framework is replaced by the CLCircularRegion  class. The CLRegion class continues to exist as an abstract base class that supports both geographic and beacon regions.
4.The UUID property of the CBCentral class is deprecated. To specify the unique ID of your central objects, use the identifier property instead.
5.The Game Kit framework contains assorted deprecations intended to clean up the existing API and provide better support for new features.
6.The UIKit framework contains the following deprecations:
The wantsFullScreenLayout property of UIViewController is deprecated. In iOS 7 and later, view controllers always support full screen layout.
The  UIPopoverController  class no longer supports the notion of an arrow direction; it supports a presentation direction.
UIColor  objects that provided background textures for earlier versions of iOS are gone.
7.Many drawing additions to the NSString class are deprecated in favor of newer variants.
8.The gethostuuid function in the NSString  library is deprecated.
9.In iOS 7 and later, if you ask for the MAC address of an iOS device, the system returns the value 02:00:00:00:00:00. If you need to identify the device, use the identifierForVendor  property of UIDevice instead. (Apps that need an identifier for their own advertising purposes should consider using the advertisingIdentifier  property of ASIdentifierManager instead.)
不过,苹果也不会立刻终结某些API的寿命,会有一个限定时期以方便开发者过渡至新的更好的API。有时,一些API可能是在某些事件暂停使用,做一些更改,而有的API可能会永远远离操作系统了。
作为一个开发者,要尽量避免使用已经弃用的API,至少新代码或者新项目中不能再使用弃用的API,如果现在的代码中使用了弃用的API,要尽可能快地更新你的代码。不过,编译器会在使用弃用API的时候给予提醒。

更多API变更的详细信息可查看:iOS 7.0 API Diffs.

2013年6月5日 星期三

Xcode 上可參考使用的math library


1. oolongengine

Logo

http://code.google.com/p/oolongengine/

The Oolong Engine is written in C++ with some help from Objective-C. It will help you to create new games and port existing games to the iPhone, the iPod touch and the iPad. Here is its feature list:
  • OpenGL ES 1.1 and OpenGL 2.0 (> iPhone 3GS, iPod touch third gen, iPad) support
  • Math library that supports floating-point calculations with an interface very similar to the D3D math library
  • Support for numerous texture formats including the PowerVR 2-bit, 4-bit and normal map compression formats
  • Support for PowerVR's POD (Scene and Meshes), .3DS and .blend file formats
  • Touch screen support
  • Accelerometer support
  • Text rendering to support a basic UI
  • Timing: several functions that can replace rdstc, QueryPerformance etc.
  • Profiler: industry proven in-game profiler
  • Resources streaming system
  • Bullet SDK support (for 3D Physics)
  • Audio engine with OpenAL support
  • Networking with the ENet library
  • Industry proven memory manager from http://www.fluidstudios.com

2013年6月1日 星期六

OPENGLES 的參考書: iPhone 3D Programming

O'Reilly 無償提供網路閱讀及實作範例下載,對OPENGLES的學習非常有效。


網路書址   http://ofps.oreilly.com/titles/9780596804824/

範例網址   http://examples.oreilly.com/9780596804831/readme.html#ModelViewer.SimpleWireframe


感謝 O'Reilly 無私提供

2013年5月28日 星期二

OpenGL基本實作(七)

這是一個從iphone 3D Programm書上第二章上改過來的實作例,改成使用xcode4.6.2,並加入切換的Button,讓ES1及ES2兩種模式可以切換。為了區別兩者的不 同,投射顏色的顯示改成不同。前一個例子使用storyBoard的靜態模式來改寫,此例則改成用動態模式,所有功能因此都很正常。

iphone 3D Programm書上第二章的中文翻譯網址如下,可瞭解本例的細節。
http://blog.csdn.net/favormm/article/details/6920318


1. 先開一個專案




2. 加入所需 framework以及所新增的檔名,如下圖


3. 因為改成使用動態模式,因此storyboard內的元件一律清空。

4. 先新增GLSL的檔案
frag.glsl

const char* SimpleFragmentShader = STRINGIFY(
                                            
varying lowp vec4 DestinationColor;
                                            
void main()
{
    gl_FragColor = DestinationColor;
}
);

vertex.glsl

const char* SimpleVertexShader = STRINGIFY(

attribute vec4 Position;
attribute vec4 SourceColor;
varying vec4 DestinationColor;  // value output to frag.glsl
uniform mat4 Projection;
uniform mat4 Modelview;

void main()
{
    DestinationColor = SourceColor;
    gl_Position = Projection * Modelview * Position;
}

);

5. 將三個數學運算的檔案加入


Quaternion.hpp

#include "Matrix.hpp"

template <typename T>
struct QuaternionT {
    T x;
    T y;
    T z;
    T w;
   
    QuaternionT();
    QuaternionT(T x, T y, T z, T w);
   
    QuaternionT<T> Slerp(T mu, const QuaternionT<T>& q) const;
    QuaternionT<T> Rotated(const QuaternionT<T>& b) const;
    QuaternionT<T> Scaled(T scale) const;
    T Dot(const QuaternionT<T>& q) const;
    Matrix3<T> ToMatrix() const;
    Vector4<T> ToVector() const;
    QuaternionT<T> operator-(const QuaternionT<T>& q) const;
    QuaternionT<T> operator+(const QuaternionT<T>& q) const;
    bool operator==(const QuaternionT<T>& q) const;
    bool operator!=(const QuaternionT<T>& q) const;
   
    void Normalize();
    void Rotate(const QuaternionT<T>& q);
   
    static QuaternionT<T> CreateFromVectors(const Vector3<T>& v0, const Vector3<T>& v1);
    static QuaternionT<T> CreateFromAxisAngle(const Vector3<T>& axis, float radians);
};

template <typename T>
inline QuaternionT<T>::QuaternionT() : x(0), y(0), z(0), w(1)
{
}

template <typename T>
inline QuaternionT<T>::QuaternionT(T x, T y, T z, T w) : x(x), y(y), z(z), w(w)
{
}

// Ken Shoemake's famous method.
template <typename T>
inline QuaternionT<T> QuaternionT<T>::Slerp(T t, const QuaternionT<T>& v1) const
{
    const T epsilon = 0.0005f;
    T dot = Dot(v1);
   
    if (dot > 1 - epsilon) {
        QuaternionT<T> result = v1 + (*this - v1).Scaled(t);
        result.Normalize();
        return result;
    }
   
    if (dot < 0)
        dot = 0;
   
    if (dot > 1)
        dot = 1;
   
    T theta0 = std::acos(dot);
    T theta = theta0 * t;
   
    QuaternionT<T> v2 = (v1 - Scaled(dot));
    v2.Normalize();
   
    QuaternionT<T> q = Scaled(std::cos(theta)) + v2.Scaled(std::sin(theta));
    q.Normalize();
    return q;
}

template <typename T>
inline QuaternionT<T> QuaternionT<T>::Rotated(const QuaternionT<T>& b) const
{
    QuaternionT<T> q;
    q.w = w * b.w - x * b.x - y * b.y - z * b.z;
    q.x = w * b.x + x * b.w + y * b.z - z * b.y;
    q.y = w * b.y + y * b.w + z * b.x - x * b.z;
    q.z = w * b.z + z * b.w + x * b.y - y * b.x;
    q.Normalize();
    return q;
}

template <typename T>
inline QuaternionT<T> QuaternionT<T>::Scaled(T s) const
{
    return QuaternionT<T>(x * s, y * s, z * s, w * s);
}

template <typename T>
inline T QuaternionT<T>::Dot(const QuaternionT<T>& q) const
{
    return x * q.x + y * q.y + z * q.z + w * q.w;
}

template <typename T>
inline Matrix3<T> QuaternionT<T>::ToMatrix() const
{
    const T s = 2;
    T xs, ys, zs;
    T wx, wy, wz;
    T xx, xy, xz;
    T yy, yz, zz;
    xs = x * s;  ys = y * s;  zs = z * s;
    wx = w * xs; wy = w * ys; wz = w * zs;
    xx = x * xs; xy = x * ys; xz = x * zs;
    yy = y * ys; yz = y * zs; zz = z * zs;
    Matrix3<T> m;
    m.x.x = 1 - (yy + zz); m.y.x = xy - wz;  m.z.x = xz + wy;
    m.x.y = xy + wz; m.y.y = 1 - (xx + zz); m.z.y = yz - wx;
    m.x.z = xz - wy; m.y.z = yz + wx;  m.z.z = 1 - (xx + yy);
    return m;
}

template <typename T>
inline Vector4<T> QuaternionT<T>::ToVector() const
{
    return Vector4<T>(x, y, z, w);
}

template <typename T>
QuaternionT<T> QuaternionT<T>::operator-(const QuaternionT<T>& q) const
{
    return QuaternionT<T>(x - q.x, y - q.y, z - q.z, w - q.w);
}

template <typename T>
QuaternionT<T> QuaternionT<T>::operator+(const QuaternionT<T>& q) const
{
    return QuaternionT<T>(x + q.x, y + q.y, z + q.z, w + q.w);
}

template <typename T>
bool QuaternionT<T>::operator==(const QuaternionT<T>& q) const
{
    return x == q.x && y == q.y && z == q.z && w == q.w;
}

template <typename T>
bool QuaternionT<T>::operator!=(const QuaternionT<T>& q) const
{
    return !(*this == q);
}

// Compute the quaternion that rotates from a to b, avoiding numerical instability.
// Taken from "The Shortest Arc Quaternion" by Stan Melax in "Game Programming Gems".
template <typename T>
inline QuaternionT<T> QuaternionT<T>::CreateFromVectors(const Vector3<T>& v0, const Vector3<T>& v1)
{
    if (v0 == -v1)
        return QuaternionT<T>::CreateFromAxisAngle(vec3(1, 0, 0), Pi);
   
    Vector3<T> c = v0.Cross(v1);
    T d = v0.Dot(v1);
    T s = std::sqrt((1 + d) * 2);
   
    QuaternionT<T> q;
    q.x = c.x / s;
    q.y = c.y / s;
    q.z = c.z / s;
    q.w = s / 2.0f;
    return q;
}

template <typename T>
inline QuaternionT<T>  QuaternionT<T>::CreateFromAxisAngle(const Vector3<T>& axis, float radians)
{
    QuaternionT<T> q;
    q.w = std::cos(radians / 2);
    q.x = q.y = q.z = std::sin(radians / 2);
    q.x *= axis.x;
    q.y *= axis.y;
    q.z *= axis.z;
    return q;
}

template <typename T>
inline void QuaternionT<T>::Normalize()
{
    *this = Scaled(1 / std::sqrt(Dot(*this)));
}

template <typename T>
inline void QuaternionT<T>::Rotate(const QuaternionT<T>& q2)
{
    QuaternionT<T> q;
    QuaternionT<T>& q1 = *this;
   
    q.w = q1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z;
    q.x = q1.w * q2.x + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y;
    q.y = q1.w * q2.y + q1.y * q2.w + q1.z * q2.x - q1.x * q2.z;
    q.z = q1.w * q2.z + q1.z * q2.w + q1.x * q2.y - q1.y * q2.x;
   
    q.Normalize();
    *this = q;
}

typedef QuaternionT<float> Quaternion;




---------------------------------------------------------

Matrix.hpp

#include "Vector.hpp"

template <typename T>
struct Matrix2 {
    Matrix2()
    {
        x.x = 1; x.y = 0;
        y.x = 0; y.y = 1;
    }
    Matrix2(const T* m)
    {
        x.x = m[0]; x.y = m[1];
        y.x = m[2]; y.y = m[3];
    }
    vec2 x;
    vec2 y;
};

template <typename T>
struct Matrix3 {
    Matrix3()
    {
        x.x = 1; x.y = 0; x.z = 0;
        y.x = 0; y.y = 1; y.z = 0;
        z.x = 0; z.y = 0; z.z = 1;
    }
    Matrix3(const T* m)
    {
        x.x = m[0]; x.y = m[1]; x.z = m[2];
        y.x = m[3]; y.y = m[4]; y.z = m[5];
        z.x = m[6]; z.y = m[7]; z.z = m[8];
    }
    Matrix3 Transposed() const
    {
        Matrix3 m;
        m.x.x = x.x; m.x.y = y.x; m.x.z = z.x;
        m.y.x = x.y; m.y.y = y.y; m.y.z = z.y;
        m.z.x = x.z; m.z.y = y.z; m.z.z = z.z;
        return m;
    }
    const T* Pointer() const
    {
        return &x.x;
    }
    vec3 x;
    vec3 y;
    vec3 z;
};

template <typename T>
struct Matrix4 {
    Matrix4()
    {
        x.x = 1; x.y = 0; x.z = 0; x.w = 0;
        y.x = 0; y.y = 1; y.z = 0; y.w = 0;
        z.x = 0; z.y = 0; z.z = 1; z.w = 0;
        w.x = 0; w.y = 0; w.z = 0; w.w = 1;
    }
    Matrix4(const Matrix3<T>& m)
    {
        x.x = m.x.x; x.y = m.x.y; x.z = m.x.z; x.w = 0;
        y.x = m.y.x; y.y = m.y.y; y.z = m.y.z; y.w = 0;
        z.x = m.z.x; z.y = m.z.y; z.z = m.z.z; z.w = 0;
        w.x = 0; w.y = 0; w.z = 0; w.w = 1;
    }
    Matrix4(const T* m)
    {
        x.x = m[0];  x.y = m[1];  x.z = m[2];  x.w = m[3];
        y.x = m[4];  y.y = m[5];  y.z = m[6];  y.w = m[7];
        z.x = m[8];  z.y = m[9];  z.z = m[10]; z.w = m[11];
        w.x = m[12]; w.y = m[13]; w.z = m[14]; w.w = m[15];
    }
    Matrix4 operator * (const Matrix4& b) const
    {
        Matrix4 m;
        m.x.x = x.x * b.x.x + x.y * b.y.x + x.z * b.z.x + x.w * b.w.x;
        m.x.y = x.x * b.x.y + x.y * b.y.y + x.z * b.z.y + x.w * b.w.y;
        m.x.z = x.x * b.x.z + x.y * b.y.z + x.z * b.z.z + x.w * b.w.z;
        m.x.w = x.x * b.x.w + x.y * b.y.w + x.z * b.z.w + x.w * b.w.w;
        m.y.x = y.x * b.x.x + y.y * b.y.x + y.z * b.z.x + y.w * b.w.x;
        m.y.y = y.x * b.x.y + y.y * b.y.y + y.z * b.z.y + y.w * b.w.y;
        m.y.z = y.x * b.x.z + y.y * b.y.z + y.z * b.z.z + y.w * b.w.z;
        m.y.w = y.x * b.x.w + y.y * b.y.w + y.z * b.z.w + y.w * b.w.w;
        m.z.x = z.x * b.x.x + z.y * b.y.x + z.z * b.z.x + z.w * b.w.x;
        m.z.y = z.x * b.x.y + z.y * b.y.y + z.z * b.z.y + z.w * b.w.y;
        m.z.z = z.x * b.x.z + z.y * b.y.z + z.z * b.z.z + z.w * b.w.z;
        m.z.w = z.x * b.x.w + z.y * b.y.w + z.z * b.z.w + z.w * b.w.w;
        m.w.x = w.x * b.x.x + w.y * b.y.x + w.z * b.z.x + w.w * b.w.x;
        m.w.y = w.x * b.x.y + w.y * b.y.y + w.z * b.z.y + w.w * b.w.y;
        m.w.z = w.x * b.x.z + w.y * b.y.z + w.z * b.z.z + w.w * b.w.z;
        m.w.w = w.x * b.x.w + w.y * b.y.w + w.z * b.z.w + w.w * b.w.w;
        return m;
    }
    Matrix4& operator *= (const Matrix4& b)
    {
        Matrix4 m = *this * b;
        return (*this = m);
    }
    Matrix4 Transposed() const
    {
        Matrix4 m;
        m.x.x = x.x; m.x.y = y.x; m.x.z = z.x; m.x.w = w.x;
        m.y.x = x.y; m.y.y = y.y; m.y.z = z.y; m.y.w = w.y;
        m.z.x = x.z; m.z.y = y.z; m.z.z = z.z; m.z.w = w.z;
        m.w.x = x.w; m.w.y = y.w; m.w.z = z.w; m.w.w = w.w;
        return m;
    }
    Matrix3<T> ToMat3() const
    {
        Matrix3<T> m;
        m.x.x = x.x; m.y.x = y.x; m.z.x = z.x;
        m.x.y = x.y; m.y.y = y.y; m.z.y = z.y;
        m.x.z = x.z; m.y.z = y.z; m.z.z = z.z;
        return m;
    }
    const T* Pointer() const
    {
        return &x.x;
    }
    static Matrix4<T> Identity()
    {
        return Matrix4();
    }
    static Matrix4<T> Translate(T x, T y, T z)
    {
        Matrix4 m;
        m.x.x = 1; m.x.y = 0; m.x.z = 0; m.x.w = 0;
        m.y.x = 0; m.y.y = 1; m.y.z = 0; m.y.w = 0;
        m.z.x = 0; m.z.y = 0; m.z.z = 1; m.z.w = 0;
        m.w.x = x; m.w.y = y; m.w.z = z; m.w.w = 1;
        return m;
    }
    static Matrix4<T> Scale(T s)
    {
        Matrix4 m;
        m.x.x = s; m.x.y = 0; m.x.z = 0; m.x.w = 0;
        m.y.x = 0; m.y.y = s; m.y.z = 0; m.y.w = 0;
        m.z.x = 0; m.z.y = 0; m.z.z = s; m.z.w = 0;
        m.w.x = 0; m.w.y = 0; m.w.z = 0; m.w.w = 1;
        return m;
    }
    static Matrix4<T> Rotate(T degrees)
    {
        T radians = degrees * 3.14159f / 180.0f;
        T s = std::sin(radians);
        T c = std::cos(radians);
       
        Matrix4 m = Identity();
        m.x.x =  c; m.x.y = s;
        m.y.x = -s; m.y.y = c;
        return m;
    }
    static Matrix4<T> Rotate(T degrees, const vec3& axis)
    {
        T radians = degrees * 3.14159f / 180.0f;
        T s = std::sin(radians);
        T c = std::cos(radians);
       
        Matrix4 m = Identity();
        m.x.x = c + (1 - c) * axis.x * axis.x;
        m.x.y = (1 - c) * axis.x * axis.y - axis.z * s;
        m.x.z = (1 - c) * axis.x * axis.z + axis.y * s;
        m.y.x = (1 - c) * axis.x * axis.y + axis.z * s;
        m.y.y = c + (1 - c) * axis.y * axis.y;
        m.y.z = (1 - c) * axis.y * axis.z - axis.x * s;
        m.z.x = (1 - c) * axis.x * axis.z - axis.y * s;
        m.z.y = (1 - c) * axis.y * axis.z + axis.x * s;
        m.z.z = c + (1 - c) * axis.z * axis.z;
        return m;
    }
    static Matrix4<T> Frustum(T left, T right, T bottom, T top, T near, T far)
    {
        T a = 2 * near / (right - left);
        T b = 2 * near / (top - bottom);
        T c = (right + left) / (right - left);
        T d = (top + bottom) / (top - bottom);
        T e = - (far + near) / (far - near);
        T f = -2 * far * near / (far - near);
        Matrix4 m;
        m.x.x = a; m.x.y = 0; m.x.z = 0; m.x.w = 0;
        m.y.x = 0; m.y.y = b; m.y.z = 0; m.y.w = 0;
        m.z.x = c; m.z.y = d; m.z.z = e; m.z.w = -1;
        m.w.x = 0; m.w.y = 0; m.w.z = f; m.w.w = 1;
        return m;
    }
    vec4 x;
    vec4 y;
    vec4 z;
    vec4 w;
};

typedef Matrix2<float> mat2;
typedef Matrix3<float> mat3;
typedef Matrix4<float> mat4;

---------------------------------------------------------

Vector.hpp

#include <cmath>

const float Pi = 4 * std::atan(1.0f);
const float TwoPi = 2 * Pi;

template <typename T>
struct Vector2 {
    Vector2() {}
    Vector2(T x, T y) : x(x), y(y) {}
    T Dot(const Vector2& v) const
    {
        return x * v.x + y * v.y;
    }
    Vector2 operator+(const Vector2& v) const
    {
        return Vector2(x + v.x, y + v.y);
    }
    Vector2 operator-(const Vector2& v) const
    {
        return Vector2(x - v.x, y - v.y);
    }
    Vector2 operator/(float s) const
    {
        return Vector2(x / s, y / s);
    }
    Vector2 operator*(float s) const
    {
        return Vector2(x * s, y * s);
    }
    void Normalize()
    {
        float s = 1.0f / Length();
        x *= s;
        y *= s;
    }
    Vector2 Normalized() const
    {
        Vector2 v = *this;
        v.Normalize();
        return v;
    }
    T LengthSquared() const
    {
        return x * x + y * y;
    }
    T Length() const
    {
        return sqrt(LengthSquared());
    }
    operator Vector2<float>() const
    {
        return Vector2<float>(x, y);
    }
    bool operator==(const Vector2& v) const
    {
        return x == v.x && y == v.y;
    }
    Vector2 Lerp(float t, const Vector2& v) const
    {
        return Vector2(x * (1 - t) + v.x * t,
                       y * (1 - t) + v.y * t);
    }
    template <typename P>
    P* Write(P* pData)
    {
        Vector2* pVector = (Vector2*) pData;
        *pVector++ = *this;
        return (P*) pVector;
    }
    T x;
    T y;
};

template <typename T>
struct Vector3 {
    Vector3() {}
    Vector3(T x, T y, T z) : x(x), y(y), z(z) {}
    void Normalize()
    {
        float s = 1.0f / std::sqrt(x * x + y * y + z * z);
        x *= s;
        y *= s;
        z *= s;
    }
    Vector3 Normalized() const
    {
        Vector3 v = *this;
        v.Normalize();
        return v;
    }
    Vector3 Cross(const Vector3& v) const
    {
        return Vector3(y * v.z - z * v.y,
                       z * v.x - x * v.z,
                       x * v.y - y * v.x);
    }
    T Dot(const Vector3& v) const
    {
        return x * v.x + y * v.y + z * v.z;
    }
    Vector3 operator+(const Vector3& v) const
    {
        return Vector3(x + v.x, y + v.y,  z + v.z);
    }
    void operator+=(const Vector3& v)
    {
        x += v.x;
        y += v.y;
        z += v.z;
    }
    void operator-=(const Vector3& v)
    {
        x -= v.x;
        y -= v.y;
        z -= v.z;
    }
    void operator/=(T s)
    {
        x /= s;
        y /= s;
        z /= s;
    }
    Vector3 operator-(const Vector3& v) const
    {
        return Vector3(x - v.x, y - v.y,  z - v.z);
    }
    Vector3 operator-() const
    {
        return Vector3(-x, -y, -z);
    }
    Vector3 operator*(T s) const
    {
        return Vector3(x * s, y * s, z * s);
    }
    Vector3 operator/(T s) const
    {
        return Vector3(x / s, y / s, z / s);
    }
    bool operator==(const Vector3& v) const
    {
        return x == v.x && y == v.y && z == v.z;
    }
    Vector3 Lerp(float t, const Vector3& v) const
    {
        return Vector3(x * (1 - t) + v.x * t,
                       y * (1 - t) + v.y * t,
                       z * (1 - t) + v.z * t);
    }
    const T* Pointer() const
    {
        return &x;
    }
    template <typename P>
    P* Write(P* pData)
    {
        Vector3<T>* pVector = (Vector3<T>*) pData;
        *pVector++ = *this;
        return (P*) pVector;
    }
    T x;
    T y;
    T z;
};

template <typename T>
struct Vector4 {
    Vector4() {}
    Vector4(T x, T y, T z, T w) : x(x), y(y), z(z), w(w) {}
    T Dot(const Vector4& v) const
    {
        return x * v.x + y * v.y + z * v.z + w * v.w;
    }
    Vector4 Lerp(float t, const Vector4& v) const
    {
        return Vector4(x * (1 - t) + v.x * t,
                       y * (1 - t) + v.y * t,
                       z * (1 - t) + v.z * t,
                       w * (1 - t) + v.w * t);
    }
    const T* Pointer() const
    {
        return &x;
    }
    T x;
    T y;
    T z;
    T w;
};

typedef Vector2<bool> bvec2;

typedef Vector2<int> ivec2;
typedef Vector3<int> ivec3;
typedef Vector4<int> ivec4;

typedef Vector2<float> vec2;
typedef Vector3<float> vec3;
typedef Vector4<float> vec4;


6. 加入IRenderingEngine.hpp的內容

enum DeviceOrientation {
    DeviceOrientationUnknown,
    DeviceOrientationPortrait,
    DeviceOrientationPortraitUpsideDown,
    DeviceOrientationLandscapeLeft,
    DeviceOrientationLandscapeRight,
    DeviceOrientationFaceUp,
    DeviceOrientationFaceDown,
};

// Creates an instance of the renderer and sets up various OpenGL state.
struct IRenderingEngine* CreateRenderer1();
struct IRenderingEngine* CreateRenderer2();

// Interface to the OpenGL ES renderer; consumed by Objective C.
struct IRenderingEngine {
    virtual void Initialize(int width, int height) = 0;
    virtual void Render() const = 0;
    virtual void UpdateAnimation(float timeStep) = 0;
    virtual void OnRotate(DeviceOrientation newOrientation) = 0;
    virtual ~IRenderingEngine() {}
};


7. RenderingEngine1.cpp

#include <OpenGLES/ES1/gl.h>
#include <OpenGLES/ES1/glext.h>
#include "IRenderingEngine.hpp"
#include "Quaternion.hpp"
#include <vector>

static const float AnimationDuration = 0.25f;

using namespace std;

struct Vertex {
    vec3 Position;
    vec4 Color;
};

struct Animation {
    Quaternion Start;
    Quaternion End;
    Quaternion Current;
    float Elapsed;
    float Duration;
};

class RenderingEngine1 : public IRenderingEngine {
public:
    RenderingEngine1();
    void Initialize(int width, int height);
    void Render() const;
    void UpdateAnimation(float timeStep);
    void OnRotate(DeviceOrientation newOrientation);
private:
    vector<Vertex> m_cone;
    vector<Vertex> m_disk;
    Animation m_animation;
    GLuint m_framebuffer;
    GLuint m_colorRenderbuffer;
    GLuint m_depthRenderbuffer;
};

IRenderingEngine* CreateRenderer1()
{
    return new RenderingEngine1();
}

RenderingEngine1::RenderingEngine1()
{
    // Create & bind the color buffer so that the caller can allocate its space.
    glGenRenderbuffersOES(1, &m_colorRenderbuffer);
    glBindRenderbufferOES(GL_RENDERBUFFER_OES, m_colorRenderbuffer);
}

void RenderingEngine1::Initialize(int width, int height)
{
    const float coneRadius = 0.5f;
    const float coneHeight = 2.866f;  //高度加高
    const int coneSlices = 40;
   
    {
        // Allocate space for the cone vertices.
        m_cone.resize((coneSlices + 1) * 2);
       
        // Initialize the vertices of the triangle strip.,使用 GL_TRIANGLE_STRIP
        vector<Vertex>::iterator vertex = m_cone.begin();
        const float dtheta = TwoPi / coneSlices;
        for (float theta = 0; vertex != m_cone.end(); theta += dtheta) {
           
            // Grayscale gradient
            float brightness = abs(sin(theta));
            vec4 color(brightness, brightness*2, brightness, 0.5); // 投射的顏色改成偏綠色。           
            // Apex vertex
            vertex->Position = vec3(0, 1, 0);
            vertex->Color = color;
            vertex++;
           
            // Rim vertex
            vertex->Position.x = coneRadius * cos(theta);
            vertex->Position.y = 1 - coneHeight;
            vertex->Position.z = coneRadius * sin(theta);
            vertex->Color = color;
            vertex++;
        }
    }
   
    {
        // Allocate space for the disk vertices.
        m_disk.resize(coneSlices + 2);
       
        // Initialize the center vertex of the triangle fan.
        vector<Vertex>::iterator vertex = m_disk.begin();
        vertex->Color = vec4(3, 0.75, 0.75, 1); // 底部顏色改掉
        vertex->Position.x = 0;
        vertex->Position.y = 1 - coneHeight;
        vertex->Position.z = 0;
        vertex++;
       
        // Initialize the rim vertices of the triangle fan.
        const float dtheta = TwoPi / coneSlices;
        for (float theta = 0; vertex != m_disk.end(); theta += dtheta) {
            vertex->Color = vec4(0.75, 0.75, 0.75, 1);
            vertex->Position.x = coneRadius * cos(theta);
            vertex->Position.y = 1 - coneHeight;
            vertex->Position.z = coneRadius * sin(theta);
            vertex++;
        }
    }
   
    // Create the depth 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; attach the depth and color buffers.
    glGenFramebuffersOES(1, &m_framebuffer);
    glBindFramebufferOES(GL_FRAMEBUFFER_OES, m_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);
   
    // Bind the color buffer for rendering.
    glBindRenderbufferOES(GL_RENDERBUFFER_OES, m_colorRenderbuffer);
   
    glViewport(0, 0, width, height);
    glEnable(GL_DEPTH_TEST);
   
    glMatrixMode(GL_PROJECTION); // 设置投影与模型-视图矩阵
    glFrustumf(-1.6f, 1.6, -2.4, 2.4, 5, 10);
   
    glMatrixMode(GL_MODELVIEW);
    glTranslatef(0, 0, -7);
}

void RenderingEngine1::Render() const
{
    glClearColor(0.5f, 0.5f, 0.5f, 1);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glPushMatrix();
   
    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_COLOR_ARRAY);
   
    mat4 rotation(m_animation.Current.ToMatrix());
    glMultMatrixf(rotation.Pointer());
   
    // Draw the cone.
    glVertexPointer(3, GL_FLOAT, sizeof(Vertex), &m_cone[0].Position.x);
    glColorPointer(4, GL_FLOAT, sizeof(Vertex),  &m_cone[0].Color.x);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, m_cone.size());
   
    // Draw the disk that caps off the base of the cone.
    glVertexPointer(3, GL_FLOAT, sizeof(Vertex), &m_disk[0].Position.x);
    glColorPointer(4, GL_FLOAT, sizeof(Vertex), &m_disk[0].Color.x);
    glDrawArrays(GL_TRIANGLE_FAN, 0, m_disk.size());
   
    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_COLOR_ARRAY);
   
    glPopMatrix();
}

void RenderingEngine1::UpdateAnimation(float timeStep)
{
    if (m_animation.Current == m_animation.End)
        return;
   
    m_animation.Elapsed += timeStep;
    if (m_animation.Elapsed >= AnimationDuration) {
        m_animation.Current = m_animation.End;
    } else {
        float mu = m_animation.Elapsed / AnimationDuration;
        m_animation.Current = m_animation.Start.Slerp(mu, m_animation.End);
    }
}

void RenderingEngine1::OnRotate(DeviceOrientation orientation)
{
    vec3 direction;
   
    switch (orientation) {
        case DeviceOrientationUnknown:
        case DeviceOrientationPortrait:
            direction = vec3(0, 1, 0);
            break;
           
        case DeviceOrientationPortraitUpsideDown:
            direction = vec3(0, -1, 0);
            break;
           
        case DeviceOrientationFaceDown:
            direction = vec3(0, 0, -1);
            break;
           
        case DeviceOrientationFaceUp:
            direction = vec3(0, 0, 1);
            break;
           
        case DeviceOrientationLandscapeLeft:
            direction = vec3(+1, 0, 0);
            break;
           
        case DeviceOrientationLandscapeRight:
            direction = vec3(-1, 0, 0);
            break;
    }
   
    m_animation.Elapsed = 0;
    m_animation.Start = m_animation.Current = m_animation.End;
    m_animation.End = Quaternion::CreateFromVectors(vec3(0, 1, 0), direction);
}

 
8. RenderingEngine2.cpp
#include <OpenGLES/ES2/gl.h>
#include <OpenGLES/ES2/glext.h>
#include "IRenderingEngine.hpp"
#include "Quaternion.hpp"
#include <vector>
#include <iostream>

#define STRINGIFY(A)  #A
#include "./frag.glsl"
#include "./vertex.glsl"

static const float AnimationDuration = 0.25f;

using namespace std;

struct Vertex {
    vec3 Position;
    vec4 Color;
};

struct Animation {
    Quaternion Start;
    Quaternion End;
    Quaternion Current;
    float Elapsed;
    float Duration;
};

class RenderingEngine2 : public IRenderingEngine {
public:
    RenderingEngine2();
    void Initialize(int width, int height);
    void Render() const;
    void UpdateAnimation(float timeStep);
    void OnRotate(DeviceOrientation newOrientation);
private:
    GLuint BuildShader(const char* source, GLenum shaderType) const;
    GLuint BuildProgram(const char* vShader, const char* fShader) const;
    vector<Vertex> m_cone;
    vector<Vertex> m_disk;
    Animation m_animation;
    GLuint m_simpleProgram;
    GLuint m_framebuffer;
    GLuint m_colorRenderbuffer;
    GLuint m_depthRenderbuffer;
};

IRenderingEngine* CreateRenderer2()
{
    return new RenderingEngine2();
}

RenderingEngine2::RenderingEngine2()
{
    // Create & bind the color buffer so that the caller can allocate its space.
    glGenRenderbuffers(1, &m_colorRenderbuffer);
    glBindRenderbuffer(GL_RENDERBUFFER, m_colorRenderbuffer);
}

void RenderingEngine2::Initialize(int width, int height)
{
    const float coneRadius = 0.5f;
    const float coneHeight = 1.866f;
    const int coneSlices = 40;
   
    {
        // Allocate space for the cone vertices.
        m_cone.resize((coneSlices + 1) * 2); // 82
       
        // Initialize the vertices of the triangle strip. 三角型序列,產生锥顶点,使用GL_TRIANGLE_STRIP
        vector<Vertex>::iterator vertex = m_cone.begin(); // 定義一個迭代的vertex變數,並指定為m_cone的第一個變數
        const float dtheta = TwoPi / coneSlices; // 一個圓切成40點,每一個角度
        for (float theta = 0; vertex != m_cone.end(); theta += dtheta) { // 圓上切點
           
            // Grayscale gradient
            float brightness = abs(sin(theta));
            vec4 color(brightness, brightness, brightness, 1);//指定一個color的Vec4,給後面的vertex設定顏色
           
            // Apex(外切,頂點) vertex,指定偶數Vertex的內容值 (0, 2, 4...)
            vertex->Position = vec3(0, 1, 0);
            vertex->Color = color;
            vertex++;
           
            // Rim(圓環,底邊的弧) vertex,指定奇數Vertex的內容值 (1, 3, 5...)
            vertex->Position.x = coneRadius * cos(theta);
            vertex->Position.y = 1 - coneHeight;
            vertex->Position.z = coneRadius * sin(theta);
            vertex->Color = color;
            vertex++;
        }
    }  // 將m_cone所有點的內容值全都設定好。
   



    {
        // Allocate space for the disk vertices. 生成锥底顶点,使用 GL_TRIANGLE_FAN模式
        m_disk.resize(coneSlices + 2);
       
        // Initialize the center vertex of the triangle fan. 底部中心點,
        vector<Vertex>::iterator vertex = m_disk.begin();
        vertex->Color = vec4(0.75, 0.75, 0.75, 1);
        vertex->Position.x = 0;
        vertex->Position.y = 1 - coneHeight;
        vertex->Position.z = 0;
        vertex++;
       
        // Initialize the rim vertices of the triangle fan.
        const float dtheta = TwoPi / coneSlices;
        for (float theta = 0; vertex != m_disk.end(); theta += dtheta) {
            vertex->Color = vec4(0.75, 0.75, 0.75, 1);
            vertex->Position.x = coneRadius * cos(theta);
            vertex->Position.y = 1 - coneHeight;
            vertex->Position.z = coneRadius * sin(theta);
            vertex++;
        }
    }
   
    // Create the depth buffer. 为深度缓冲生成一个id,绑定它,并为之分配存储空间。
    glGenRenderbuffers(1, &m_depthRenderbuffer);
    glBindRenderbuffer(GL_RENDERBUFFER, m_depthRenderbuffer);
    glRenderbufferStorage(GL_RENDERBUFFER,
                          GL_DEPTH_COMPONENT16,
                          width,
                          height);
   
    // Create the framebuffer object; attach the depth and color buffers.
    // 为缓冲对象生成id,绑定之,并把深度与颜色缓冲用glFramebufferRenderbufferOES依附于它。
    glGenFramebuffers(1, &m_framebuffer);
    glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER,
                              GL_COLOR_ATTACHMENT0,
                              GL_RENDERBUFFER,
                              m_colorRenderbuffer);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER,
                              GL_DEPTH_ATTACHMENT,
                              GL_RENDERBUFFER,
                              m_depthRenderbuffer);
   
    // Bind the color buffer for rendering. 绑定颜色缓冲,后继的绘制将作用于它。
    glBindRenderbuffer(GL_RENDERBUFFER, m_colorRenderbuffer);
   
    // Set up some GL state.
    glViewport(0, 0, width, height); //设置viewport的左下角,长,宽属性。
    glEnable(GL_DEPTH_TEST); // 为3D场景开启深度测试
   
    // Build the GLSL program.
    m_simpleProgram = BuildProgram(SimpleVertexShader, SimpleFragmentShader);
    glUseProgram(m_simpleProgram);
   
    // Set the projection matrix.  设置投影与模型-视图矩阵
    GLint projectionUniform = glGetUniformLocation(m_simpleProgram, "Projection");
    mat4 projectionMatrix = mat4::Frustum(-1.6f, 1.6, -2.4, 2.4, 5, 10);
    glUniformMatrix4fv(projectionUniform, 1, 0, projectionMatrix.Pointer());
}

void RenderingEngine2::Render() const
{
    GLuint positionSlot = glGetAttribLocation(m_simpleProgram, "Position");
    GLuint colorSlot = glGetAttribLocation(m_simpleProgram, "SourceColor");
   
    glClearColor(0.5f, 0.5f, 0.5f, 1);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
   
    glEnableVertexAttribArray(positionSlot);
    glEnableVertexAttribArray(colorSlot);
   
    mat4 rotation(m_animation.Current.ToMatrix());
    mat4 translation = mat4::Translate(0, 0, -7);
   
    // Set the model-view matrix.
    GLint modelviewUniform = glGetUniformLocation(m_simpleProgram, "Modelview");
    mat4 modelviewMatrix = rotation * translation;
    glUniformMatrix4fv(modelviewUniform, 1, 0, modelviewMatrix.Pointer());
   
    // Draw the cone.
    {
        GLsizei stride = sizeof(Vertex);
        const GLvoid* pCoords = &m_cone[0].Position.x;
        const GLvoid* pColors = &m_cone[0].Color.x;
        glVertexAttribPointer(positionSlot, 3, GL_FLOAT, GL_FALSE, stride, pCoords);
        glVertexAttribPointer(colorSlot, 4, GL_FLOAT, GL_FALSE, stride, pColors);
        glDrawArrays(GL_TRIANGLE_STRIP, 0, m_cone.size());
    }
   
    // Draw the disk that caps off the base of the cone.
    {
        GLsizei stride = sizeof(Vertex);
        const GLvoid* pCoords = &m_disk[0].Position.x;
        const GLvoid* pColors = &m_disk[0].Color.x;
        glVertexAttribPointer(positionSlot, 3, GL_FLOAT, GL_FALSE, stride, pCoords);
        glVertexAttribPointer(colorSlot, 4, GL_FLOAT, GL_FALSE, stride, pColors);
        glDrawArrays(GL_TRIANGLE_FAN, 0, m_disk.size());
    }
   
    glDisableVertexAttribArray(positionSlot);
    glDisableVertexAttribArray(colorSlot);
}

void RenderingEngine2::UpdateAnimation(float timeStep)
{
    if (m_animation.Current == m_animation.End)
        return;
   
    m_animation.Elapsed += timeStep;
    if (m_animation.Elapsed >= AnimationDuration) {
        m_animation.Current = m_animation.End;
    } else {
        float mu = m_animation.Elapsed / AnimationDuration;
        m_animation.Current = m_animation.Start.Slerp(mu, m_animation.End);
    }
}

void RenderingEngine2::OnRotate(DeviceOrientation orientation)
{
    vec3 direction;
   
    switch (orientation) {
        case DeviceOrientationUnknown:
        case DeviceOrientationPortrait:
            direction = vec3(0, 1, 0);
            break;
           
        case DeviceOrientationPortraitUpsideDown:
            direction = vec3(0, -1, 0);
            break;
           
        case DeviceOrientationFaceDown:
            direction = vec3(0, 0, -1);
            break;
           
        case DeviceOrientationFaceUp:
            direction = vec3(0, 0, 1);
            break;
           
        case DeviceOrientationLandscapeLeft:
            direction = vec3(+1, 0, 0);
            break;
           
        case DeviceOrientationLandscapeRight:
            direction = vec3(-1, 0, 0);
            break;
    }
   
    m_animation.Elapsed = 0;
    m_animation.Start = m_animation.Current = m_animation.End;
    m_animation.End = Quaternion::CreateFromVectors(vec3(0, 1, 0), direction);
}

GLuint RenderingEngine2::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]);
        std::cout << messages;
        exit(1);
    }
   
    return shaderHandle;
}

GLuint RenderingEngine2::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]);
        std::cout << messages;
        exit(1);
    }
   
    return programHandle;
}

9. GLView.h 作為OPENGLES載體的物件定義

#import <UIKit/UIKit.h>
#import "IRenderingEngine.hpp"
#import <QuartzCore/QuartzCore.h>


@interface GLView : UIView
{
    ///@private
    EAGLContext* m_context;
    IRenderingEngine* m_renderingEngine;
    float m_timestamp;
   
@public
    BOOL ForceES1 ;

}

- (void) drawView: (CADisplayLink*) displayLink;
- (void) didRotate: (NSNotification*) notification;

- (id) initSet:(CGRect) frame;



@end


10.  GLView.mm 作為OPENGLES載體的設定主程式

#import "GLView.h"

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

- (id) initWithFrame: (CGRect) frame
{
    ForceES1 = NO;
   
    if (self = [super initWithFrame:frame]) {
        if  ([self initSet:frame] == nil)
            return nil;
    }
    return self;
}


- (id) initSet:(CGRect) frame
{
    CAEAGLLayer* eaglLayer = (CAEAGLLayer*) super.layer;
    eaglLayer.opaque = YES;
   
    EAGLRenderingAPI api;
   
    if (ForceES1 == NO){
        api= kEAGLRenderingAPIOpenGLES2;
    }
    else {
        api= kEAGLRenderingAPIOpenGLES1;
    }
   
    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;
    }
   
    if (api == kEAGLRenderingAPIOpenGLES1) {
        NSLog(@"Using OpenGL ES 1.1");
        m_renderingEngine = CreateRenderer1();
    } else {
        NSLog(@"Using OpenGL ES 2.0");
        m_renderingEngine = CreateRenderer2();
    }
   
    [m_context
     renderbufferStorage:GL_RENDERBUFFER
     fromDrawable: eaglLayer];
   
    m_renderingEngine->Initialize(CGRectGetWidth(frame), CGRectGetHeight(frame));
   
    [self drawView: nil];
    m_timestamp = CACurrentMediaTime();
   
    CADisplayLink* displayLink;
    displayLink = [CADisplayLink displayLinkWithTarget:self
                                              selector:@selector(drawView:)];
   
    [displayLink addToRunLoop:[NSRunLoop currentRunLoop]
                      forMode:NSDefaultRunLoopMode];
   
    [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
   
    [[NSNotificationCenter defaultCenter]
     addObserver:self
     selector:@selector(didRotate:)
     name:UIDeviceOrientationDidChangeNotification
     object:nil];
   
    return self;
}

- (void) didRotate: (NSNotification*) notification
{
    UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
    m_renderingEngine->OnRotate((DeviceOrientation) orientation);
    [self drawView: nil];
}

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

@end

 

11. mainViewController.h


#import <UIKit/UIKit.h>
#import "GLView.h"

@interface mainViewController : UIViewController
{
    UIWindow* m_window;
    GLView *controllView;

}

@end


 12. mainViewController.mm ,此處副檔名要改成mm,因為連結的GLView.h含有C++的程式碼。 所有顯示元件都是動態產生的。


#import "mainViewController.h"

@interface mainViewController ()

@end

@implementation mainViewController
{
    UIButton *swBtn;
}


BOOL mode1;

- (void)viewDidLoad
{
    [super viewDidLoad];
   
    CGRect screenBounds = [[UIScreen mainScreen] bounds];
   
    m_window = [[UIWindow alloc] initWithFrame: screenBounds];
    controllView = [[GLView alloc] initWithFrame: screenBounds];
   
    [self setButtonInterface];    
    [m_window addSubview: controllView];
   
    [controllView addSubview:swBtn];
   
    [m_window makeKeyAndVisible];
   
    mode1 = NO;

   
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (void)setButtonInterface  // 動態產生一個的Button
{
   
    swBtn = [UIButton  buttonWithType:UIButtonTypeRoundedRect];
    //動態產生一個RoundedRect 形式的  Button
   
    swBtn.frame = CGRectMake(0,0, 100, 30); // 大小
   
    [swBtn setCenter:CGPointMake(150, 50)];//位置放在x=150, y=50的位置
   
   
    [swBtn addTarget:self action:@selector(onSwitch) forControlEvents:UIControlEventTouchUpInside];
    //設定Button動作呼叫的function在 onHelloActionButton,方式為按下
   
    //_helloActionButton.= @"Action Button";
    [swBtn setTitle:@"ES2 Mode" forState:UIControlStateNormal];
    //將動態Button上放置Action Button這兩個字
   
   
}


- (void) onSwitch
{
    mode1 = ~mode1;
   
    controllView->ForceES1 = mode1;
   
    [controllView initSet:m_window.frame];
   
    if (mode1 == 0){
        [swBtn setTitle:@"ES2 Mode" forState:UIControlStateNormal];
    }
    else
        [swBtn setTitle:@"ES1 Mode" forState:UIControlStateNormal];
}


@end

12. 結果圖,如果放到實機上,則任意轉動到六個方向上都可以顯示出向上的更正,此處就不截圖了。



2013年2月6日 星期三

OpenGLES on IOS (一)

基本注意事項

轉貼自 http://developer.apple.com/library/ios/#documentation/3DDrawing/Conceptual/OpenGLES_ProgrammingGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40008793-CH1-SW1


在OPENGLES 中 1. 1會提供許多數學運算的function,但在2.0後,這些運算function需要使用者自行提供。可參考網址中所提供的Library

 http://kirenenko-tw.blogspot.tw/2013/06/xcode-math-library.html





EAGL
Tiny glue API between OpenGL ES and UIKit. Some EAGL classes (such as CAEGLLayer) are defined in Quartz Core framework, while others (such as EAGLCon text) are defined in the OpenGL ES framework.



1. OpenGL ES is a C-based, Platform-Neutral API

Because OpenGL ES is a C-based API, it is extremely portable and widely supported. As a C API, it integrates seamlessly with Objective-C based Cocoa Touch applications. The OpenGL ES specification does not define a windowing layer; instead, the hosting operating system must provide functions to create an OpenGL ES rendering context, which accepts commands, and a framebuffer, where the results of any drawing commands are written to.





 

2. OpenGL ES is Integrated into Core Animation

Core Animation is fundamental to iOS graphics, and that includes OpenGL ES content that your application delivers to the screen. When you develop an OpenGL ES application, your OpenGL ES content is rendered to a special Core Animation layer, known as a CAEAGLLayer object. The images you render using OpenGL ES are stored in the CAEAGLLayer. Core Animation composites these images with content in other layers and delivers the final image to the screen.





 

3. Framebuffer Objects are Always the Rendering Destination

The OpenGL ES specification assumes there are two kinds of framebuffers: system-provided framebuffers and framebuffer objects. A system framebuffer is allocated using an API provided by the host operating system, and connects to the screen or windowing environment. Framebuffer objects target offscreen rendering without a direct connection to the screen or windowing environment. iOS only uses framebuffer objects; rather than create a separate system framebuffer, iOS extends the OpenGL ES API to allow a framebuffer object to be allocated so that its contents are shared with Core Animation.





 

4. Functionality May Vary on Different Devices

這一段基本不用看,因為新版的IOS都會支援ES2.0,因此不需注意ES1.0的相容性。

 

5. Applications Require Additional Performance Tuning

Graphics processors are parallelized devices optimized for graphics operations. To get great performance in your application, you must carefully design your application to feed data and commands to OpenGL ES so that the graphics hardware runs in parallel with your application. A poorly tuned application forces either the CPU or the GPU to wait for the other to finish processing commands.
You should design your application to efficiently use the OpenGL ES API. Once you have finished building your application, use Instruments to fine tune your application’s performance. If your application is bottlenecked inside OpenGL ES, use the information provided in this guide to optimize your application’s performance.
Xcode 4 provides new tools to help you improve the performance of your OpenGL ES applications.

 

6. OpenGL ES May Not Be Used in Background Applications

Applications that are running in the background may not call OpenGL ES functions. If your application accesses the graphics processor while it is in the background, it is automatically terminated by iOS. To avoid this, your application should flush any pending commands previously submitted to OpenGL ES prior to being moved into the background and avoid calling OpenGL ES until it is moved back to the foreground.

 

7. OpenGL ES Places Additional Restrictions on Multithreaded Applications

Designing applications to take advantage of concurrency can be useful to help improve your application’s performance. If you intend to add concurrency to an OpenGL ES application, you must ensure that the application does not access the same context from two different threads at the same time.
Relevant Chapters: “Concurrency and OpenGL ES”