根據前一個實作例,修改一下,加入灰階的圖檔,以作為Texture的實驗,為此並加入自動旋轉的機制,以方便觀察Filter的修補。因為要做Filter的實驗,因此也有
GL_TEXTURE_MIN_FILTER及GL_TEXTURE_MAG_FILTER這兩個選項的實驗。
1. 為了新的實驗,將原本的實作專案稍改一下名稱
2. 加入一個黑白相間的圖檔,以作為灰階texture filter的測試
3. 依序就修改之處貼出GLView.h
#import <UIKit/UIKit.h>
#import "Interfaces.hpp"
#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>
@interface GLView : UIView {
@private
IApplicationEngine* m_applicationEngine;
IRenderingEngine* m_renderingEngine;
IResourceManager* m_resourceManager; // for Textured File
EAGLContext* m_context;
float m_timestamp;
@public
float smallIconRotateXValue;
float smallIconRotateYValue;
float smallIconRotateZValue;
float lightPosX;
float lightPosY;
float lightPosZ;
int GLSL_mode;
int textureMode;
int ES_mode;
int textureWrapS;
int textureWrapT;
int textureMagFilter;
int textureMinFilter;
BOOL enAutoRoate;
Quaternion old_orientation;
CADisplayLink* displayLink;
}
- (void) drawView: (CADisplayLink*) displayLink;
- (id) initSet:(CGRect) frame;
- (void) setGLSL:(int) mode;
- (void) setTexture:(int) mode;
- (void) setES:(int) mode;
- (void) setTextureWrapS:(int) mode;
- (void) setTextureWrapT:(int) mode;
- (void) setTextureMagFilter:(int) mode;
- (void) setTextureMinFilter:(int) mode;
- (void) enAutoRotate;
- (void) resetdisplayLink;
@end
4. GLView.mm
#import "GLView.h"
@implementation GLView
{
}
+ (Class) layerClass
{
return [CAEAGLLayer class];
}
- (id) initWithFrame: (CGRect) frame
{
smallIconRotateXValue =0;
smallIconRotateYValue =0;
smallIconRotateZValue =0;
lightPosX =0.25;
lightPosY =0.25;
lightPosZ =1;
GLSL_mode = 0;
textureMode = DefaultTexture;
ES_mode = 1;
textureWrapS =0;
textureWrapT =0;
textureMagFilter =0;
textureMinFilter =0;
old_orientation = Quaternion(0, 0, 0, 1);
if (self = [super initWithFrame:frame])
{
if ([self initSet:frame] == nil)
return nil;
}
return self;
}
- (id) initSet:(CGRect) frame
{
CAEAGLLayer* eaglLayer = (CAEAGLLayer*) self.layer;
eaglLayer.opaque = YES;
EAGLRenderingAPI api;
if (ES_mode == 1)
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;
}
m_resourceManager = Darwin::CreateResourceManager();
if (api == kEAGLRenderingAPIOpenGLES1) {
NSLog(@"Using OpenGL ES 1.1");
//m_renderingEngine = WireframeES1::CreateRenderingEngine();
//m_renderingEngine = SolidES1::CreateRenderingEngine();
m_renderingEngine = TexturedES1::CreateRenderingEngine(m_resourceManager);
} else {
NSLog(@"Using OpenGL ES 2.0");
//m_renderingEngine = WireframeES2::CreateRenderingEngine(); // 完成 m_colorRenderbuffer 設定
//m_renderingEngine = SolidES2::CreateRenderingEngine(); // replace
m_renderingEngine = TexturedES2::CreateRenderingEngine(m_resourceManager);
}
m_applicationEngine = ParametricViewer::CreateApplicationEngine(m_renderingEngine);
m_applicationEngine->SetIconRotateValue(smallIconRotateXValue, smallIconRotateYValue, smallIconRotateZValue);
//m_applicationEngine->setLightPos(lightPosX, lightPosY, lightPosZ);
//m_applicationEngine->setOldRotation(old_orientation);
//m_applicationEngine->setGLSL(GLSL_mode);
m_applicationEngine->setTexture(textureMode);
m_applicationEngine->setTextureWrapS(textureWrapS);
m_applicationEngine->setTextureWrapT(textureWrapT);
m_applicationEngine->setTextureMagFilter(textureMagFilter);
m_applicationEngine->setTextureMinFilter(textureMinFilter);
[m_context
renderbufferStorage:GL_RENDERBUFFER
fromDrawable: eaglLayer];
int width = CGRectGetWidth(frame);
int height = CGRectGetHeight(frame);
m_applicationEngine->Initialize(width, height);
[self setdisplayLink];
return self;
}
.....
- (void) setTextureMagFilter:(int) mode
{
textureMagFilter = mode;
}
- (void) setTextureMinFilter:(int) mode
{
textureMinFilter = mode;
}
- (void) enAutoRotate
{
enAutoRoate = YES;
m_applicationEngine->setAutoRotate();
}
.....
- (void) touchesBegan: (NSSet*) touches withEvent: (UIEvent*) event
{
UITouch* touch = [touches anyObject];
CGPoint location = [touch locationInView: self];
m_applicationEngine->OnFingerDown(ivec2(location.x, location.y));
enAutoRoate = NO;
}
- (void) touchesEnded: (NSSet*) touches withEvent: (UIEvent*) event
{
UITouch* touch = [touches anyObject];
CGPoint location = [touch locationInView: self];
m_applicationEngine->OnFingerUp(ivec2(location.x, location.y)); //傳入所按的平面位置
enAutoRoate = NO;
}
- (void) touchesMoved: (NSSet*) touches withEvent: (UIEvent*) event
{
UITouch* touch = [touches anyObject];
CGPoint previous = [touch previousLocationInView: self];
CGPoint current = [touch locationInView: self];
m_applicationEngine->OnFingerMove(ivec2(previous.x, previous.y),
ivec2(current.x, current.y));
enAutoRoate = NO;
}
@end
namespace FacetedES2 { IRenderingEngine* CreateRenderingEngine() { return 0; } }
namespace SolidGL2 { IRenderingEngine* CreateRenderingEngine() { return 0; } }
namespace TexturedGL2 { IRenderingEngine* CreateRenderingEngine() { return 0; } }
5. Interfaces.hpp
#pragma once
#include "Vector.hpp"
#include "Quaternion.hpp"
#include <vector>
#include <string>
using std::vector;
using std::string;
enum VertexFlags {
VertexFlagsNormals = 1 << 0, // ==1
VertexFlagsTexCoords = 1 << 1, // ==2
};
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 void SetIconRotateValue(float x, float y, float z) =0; // add for icon rotation
virtual void setLightPos(float x, float y, float z) = 0; // add for light position
virtual void setGLSL(int mode) =0;
virtual void setTexture(int mode) =0;
virtual void setTextureWrapS(int mode) =0;
virtual void setTextureWrapT(int mode) =0;
virtual void setTextureMagFilter(int mode) =0;
virtual void setTextureMinFilter(int mode) =0;
virtual void setAutoRotate() =0;
//virtual Quaternion get_m_orientation() =0;
virtual ~IApplicationEngine() {}
};
.....
struct IRenderingEngine {
virtual void Initialize(const vector<ISurface*>& surfaces) = 0;
virtual void Render(const vector<Visual>& visuals) const = 0;
virtual void setLightPos(float x, float y, float z) =0; //const = 0; /// 不能使用const
virtual void setGLSL(int mode) =0;
virtual void setTexture(int mode) =0;
virtual void setTextureWrapS(int mode) =0;
virtual void setTextureWrapT(int mode) =0;
virtual void setTextureMagFilter(int mode) =0;
virtual void setTextureMinFilter(int mode) =0;
//virtual void setAutoRotate();
///virtual Quaternion get_m_orientation () const =0;
virtual ~IRenderingEngine() {}
};
#define DefaultTexture 5
.....
6. mainViewController.mm
#import "mainViewController.h"
#import "Interfaces.hpp" //define放置處
@interface mainViewController ()
{
int GLSL_mode;
int textureMode;
int ES_mode;
int textureWrapS;
int textureWrapT;
BOOL isAutoRotate;
int textureMinFilter;
int textureMagFilter;
}
@end
@implementation mainViewController
{
UISlider *sIconXRotateSlider;
UISlider *sIconYRotateSlider;
UISlider *sIconZRotateSlider;
UISlider *lightPosXSlider;
UISlider *lightPosYSlider;
UISlider *lightPosZSlider;
//UISegmentedControl *GLSL_Selector;
UISegmentedControl *textureSelector;
UISegmentedControl *ES_Mode_Selector;
UISegmentedControl *textureWrapS_Selector;
UISegmentedControl *textureWrapT_Selector;
UIButton *autoRotateBtn;
UISegmentedControl *textureMinFilterSel;
UISegmentedControl *textureMagFilterSel;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
CGRect screenBounds = [[UIScreen mainScreen] bounds];
m_window = [[UIWindow alloc] initWithFrame: screenBounds];
m_view = [[GLView alloc] initWithFrame: screenBounds];
[m_window addSubview: m_view];
[m_window makeKeyAndVisible];
[self setSlideInterface1];
[self setSlideInterface2];
[self setSlideInterface3];
[self setSlideInterfaceLightX];
[self setSlideInterfaceLightY];
[self setSlideInterfaceLightZ];
//[self setGLSL_Selector];
[self setTextureSelector];
[self setES_Selector];
[self setTextureWrapS];
[self setTextureWrapT];
[self setAutoRotateBtn];
[self setTextureMinFilter];
[self setTextureMagFilter];
[m_window addSubview:sIconXRotateSlider];
[m_window addSubview:sIconYRotateSlider];
[m_window addSubview:sIconZRotateSlider];
[m_window addSubview:lightPosXSlider];
[m_window addSubview:lightPosYSlider];
[m_window addSubview:lightPosZSlider];
[m_window addSubview:textureSelector];
[m_window addSubview:ES_Mode_Selector];
//[m_window addSubview:textureWrapS_Selector];
//[m_window addSubview:textureWrapT_Selector];
[m_window addSubview:autoRotateBtn];
[m_window addSubview:textureMinFilterSel];
[m_window addSubview:textureMagFilterSel];
GLSL_mode = 0;
textureMode = 0;
ES_mode = 1; // ES = 2.0
textureWrapS = 0;
textureWrapT = 0;
}
.....
- (void) setAutoRotateBtn
{
autoRotateBtn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
//動態產生一個RoundedRect 形式的 Button
autoRotateBtn.frame = CGRectMake(0,0, 100, 30); // 大小
[autoRotateBtn setCenter:CGPointMake(700, 100)];//位置放在x=150, y=50的位置
// 由於設定成LandScape,X在垂直方向
autoRotateBtn.transform = CGAffineTransformMakeRotation( M_PI / 2.0);
[autoRotateBtn addTarget:self action:@selector(startRotate:) forControlEvents:UIControlEventTouchUpInside];
//設定Button動作呼叫的function在 onHelloActionButton,方式為按下
//_helloActionButton.= @"Action Button";
[autoRotateBtn setTitle:@"自動旋轉" forState:UIControlStateNormal];
//將動態Button上放置Action Button這兩個字
}
- (void) setTextureMinFilter
{
//[self removeSubViewByLabelClass];
NSArray *itemArray =[NSArray arrayWithObjects: @"LINEAR", @"NEAREST", @"NEAREST_NEAREST",@"LINEAR_NEAREST" ,@"LINEAR_LINEAR",@"NEAREST_LINEAR",nil];
//使用陣列來建立UISegmentedControl
textureMinFilterSel= [[UISegmentedControl alloc] initWithItems:itemArray];
//設定外觀大小與初始選項
textureMinFilterSel.segmentedControlStyle = UISegmentedControlStyleBar;
textureMinFilterSel.frame = CGRectMake(20.0, 100.0, 800.0, 44.0);
[textureMinFilterSel setCenter:CGPointMake(600, 400)];
textureMinFilterSel.selectedSegmentIndex = 0;
textureMinFilterSel.tag = 1;
// 由於設定成LandScape,X在垂直方向
textureMinFilterSel.transform = CGAffineTransformMakeRotation( M_PI / 2.0);
//設定所觸發的事件條件與對應事件
[textureMinFilterSel addTarget:self action:@selector(textureMinFilterChoice:) forControlEvents:UIControlEventValueChanged];
//加入畫面中並釋放記憶體
[self.view addSubview:textureMinFilterSel];
}
- (void) setTextureMagFilter
{
//[self removeSubViewByLabelClass];
NSArray *itemArray =[NSArray arrayWithObjects:@"LINEAR", @"NEAREST" ,nil];
//使用陣列來建立UISegmentedControl
textureMagFilterSel= [[UISegmentedControl alloc] initWithItems:itemArray];
//設定外觀大小與初始選項
textureMagFilterSel.segmentedControlStyle = UISegmentedControlStyleBar;
textureMagFilterSel.frame = CGRectMake(20.0, 100.0, 200.0, 44.0);
[textureMagFilterSel setCenter:CGPointMake(550, 100)];
textureMagFilterSel.selectedSegmentIndex = 0;
textureMagFilterSel.tag = 1;
// 由於設定成LandScape,X在垂直方向
textureMagFilterSel.transform = CGAffineTransformMakeRotation( M_PI / 2.0);
//設定所觸發的事件條件與對應事件
[textureMagFilterSel addTarget:self action:@selector(textureMagFilterChoice:) forControlEvents:UIControlEventValueChanged];
//加入畫面中並釋放記憶體
[self.view addSubview:textureMagFilterSel];
}
......
- (void) textureMagFilterChoice:(id)sender {
textureMagFilter = [sender selectedSegmentIndex];
[m_view setTextureMagFilter:textureMagFilter];
[m_view initSet:m_window.frame];
}
- (void) textureMinFilterChoice:(id)sender {
textureMinFilter = [sender selectedSegmentIndex];
[m_view setTextureMinFilter:textureMinFilter];
[m_view initSet:m_window.frame];
}
- (void) startRotate:(id)sender {
[m_view enAutoRotate];
}
@end
7. RenderingEngine.ES1.cpp
#include <OpenGLES/ES1/gl.h>
#include <OpenGLES/ES1/glext.h>
#include "Interfaces.hpp"
#include "Matrix.hpp"
#include <iostream>
using namespace std;
//namespace WireframeES1 {
//namespace SolidES1 {
namespace TexturedES1 {
struct Drawable {
GLuint VertexBuffer;
GLuint IndexBuffer;
int IndexCount;
};
class RenderingEngine : public IRenderingEngine {
public:
// RenderingEngine();
RenderingEngine(IResourceManager* resourceManager);
void Initialize(const vector<ISurface*>& surfaces);
void Render(const vector<Visual>& visuals) const;
void setLightPos(float x, float y, float z); // const // 使用const就變成惟讀
void setGLSL(int mode);
void setTexture(int mode);
void setTextureWrapS(int mode);
void setTextureWrapT(int mode);
void setTextureMagFilter(int mode);
void setTextureMinFilter(int mode);
//void setAutoRotate();
private:
vector<Drawable> m_drawables;
GLuint m_colorRenderbuffer;
GLuint m_depthRenderbuffer;
GLuint m_gridTexture; // new var in texture
mat4 m_translation;
IResourceManager* m_resourceManager; // new var in texture
int textureMode;
int textureWrapS;
int textureWrapT;
int textureMagFilter;
int textureMinFilter;
float lightPosX;
float lightPosY;
float lightPosZ;
};
.....
RenderingEngine::RenderingEngine(IResourceManager* resourceManager)
{
m_resourceManager = resourceManager;
glGenRenderbuffersOES(1, &m_colorRenderbuffer);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, m_colorRenderbuffer);
//GLSL_Mode = 0;
textureMode = DefaultTexture;
}
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 = VertexFlagsNormals | VertexFlagsTexCoords; // new in texture
//(*surface)->GenerateVertices(vertices);
//(*surface)->GenerateVertices(vertices, VertexFlagsNormals); // replace
(*surface)->GenerateVertices(vertices, vertexFlags); // new in texture
GLuint vertexBuffer;
glGenBuffers(1, &vertexBuffer); //設定GPU memory 給 Vertex用
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, // 將vertex資料存到GPU memory
vertices.size() * sizeof(vertices[0]), // 確認記憶體大小
&vertices[0], GL_STATIC_DRAW);
// Create a new VBO for the indices if needed.
//int indexCount = (*surface)->GetLineIndexCount();
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)->GenerateLineIndices(indices); // 4個 indices為一組
(*surface)->GenerateTriangleIndices(indices); // replace
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);
//---------- start of texture process --------------------------
float degree;
//一個檢查的機制指令,來確認其各異向性紋理過濾最大運算能力。
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, °ree);
// Load the texture.
glGenTextures(1, &m_gridTexture);
//====== Texture filtering =============================================================
glBindTexture(GL_TEXTURE_2D, m_gridTexture);
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); //指定自動產生Mipmap的小圖
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
if (textureMinFilter == 1)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
else if (textureMinFilter == 2)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
else if (textureMinFilter == 3)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
else if (textureMinFilter == 4)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
else if (textureMinFilter == 5)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);
else
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
if (textureMinFilter == 1)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
else if (textureMinFilter == 2)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
if (textureMode !=5)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, degree);
//=========================================================================
//------ texture coordinate ------------------------------------------------------------
glBindTexture(GL_TEXTURE_2D, m_gridTexture);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
if (textureWrapS == 1)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
else if (textureWrapS == 2)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
else
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
if (textureWrapT == 1)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
else if (textureWrapT == 2)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
else
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
//-------------------------------------------------------------------------
//m_resourceManager->LoadPngImage("Grid16");
if (textureMode == 2)
m_resourceManager->LoadPngImage("Spiked32x32");
else if (textureMode == 4)
m_resourceManager->LoadPngImage("大雄128x64");
else if (textureMode == 3)
m_resourceManager->LoadPngImage("flake64x64");
else if (textureMode == 1)
m_resourceManager->LoadPngImage("Sunflower16x16");
else if (textureMode == 5)
m_resourceManager->LoadPngImage("Checkerboard");
else
m_resourceManager->LoadPngImage("Grid16");
void* pixels = m_resourceManager->GetImageData();
ivec2 size = m_resourceManager->GetImageSize();
if (textureMode ==5)
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, size.x, size.y, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, pixels);
else
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
//glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, size.x, size.y, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, pixels);
m_resourceManager->UnloadImage();
//---------- end of texture process --------------------------
// Set up various GL state.
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
////Tell OpenGL to enable the texture coordinate vertex attribute.
glEnable(GL_LIGHTING); // new
glEnable(GL_LIGHT0); // Enable lighting and turn on the first light source (known as GL_LIGHT0). The iPhone supports up to eight light sources, but we're using only one.
glEnable(GL_DEPTH_TEST); // new
glEnable(GL_TEXTURE_2D);
// 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);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // replace 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); // original
//glViewport(lowerLeft.y, lowerLeft.x, size.y, size.x);
// Set the light position.
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
//vec4 lightPosition(0.25, 0.25, 1, 0);
vec4 lightPosition(lightPosX,lightPosY, lightPosZ,0);
glLightfv(GL_LIGHT0, GL_POSITION, lightPosition.Pointer());
// Set the model-view transform.
mat4 rotation = visual->Orientation.ToMatrix();
mat4 modelview = rotation * m_translation;
// glMatrixMode(GL_MODELVIEW); //指定哪一个矩阵是当前矩阵,
// GL_MODELVIEW/GL_PROJECTION/GL_TEXTURE 但在 texture 取消了
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());
//glMatrixMode(GL_TEXTURE); // new in texture
//glTranslatef(0.01f, 0, 0); // new in texture 貼圖會轉動是這個指令,並且會影響到GL_CLAMP_TO_EDGE的設定,這是ES1.x的缺點之一
// // Set the color.
// vec3 color = visual->Color;
// glColor4f(color.x, color.y, color.z, 1);
//
// 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()); /// 顯示出金屬色
//------------ start to replace in texture --------------------
// Draw the surface.
int stride = sizeof(vec3) + sizeof(vec3) + sizeof(vec2);
const GLvoid* normalOffset = (const GLvoid*) sizeof(vec3);
const GLvoid* texCoordOffset = (const GLvoid*) (2 * sizeof(vec3));
const Drawable& drawable = m_drawables[visualIndex];
glBindBuffer(GL_ARRAY_BUFFER, drawable.VertexBuffer);
glVertexPointer(3, GL_FLOAT, stride, 0);
glNormalPointer(GL_FLOAT, stride, normalOffset);
glTexCoordPointer(2, GL_FLOAT, stride, texCoordOffset);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, drawable.IndexBuffer);
glDrawElements(GL_TRIANGLES, drawable.IndexCount, GL_UNSIGNED_SHORT, 0);
//------------ end to replace in texture --------------------
}
}
void RenderingEngine::setLightPos(float x, float y, float z) // const // 使用const就變成惟讀函數
{
lightPosX = x;
lightPosY = y;
lightPosZ = z;
}
void RenderingEngine::setGLSL(int mode)
{
//GLSL_mode = mode;
}
void RenderingEngine::setTexture(int mode)
{
textureMode = mode;
}
void RenderingEngine::setTextureWrapS(int mode)
{
textureWrapS = mode;
}
void RenderingEngine::setTextureWrapT(int mode)
{
textureWrapT = mode;
}
void RenderingEngine::setTextureMagFilter(int mode)
{
textureMagFilter = mode;
}
void RenderingEngine::setTextureMinFilter(int mode)
{
textureMinFilter = mode;
}
}
8. RenderingEngine.ES2.cpp
#include <OpenGLES/ES2/gl.h>
#include <OpenGLES/ES2/glext.h>
#include "Interfaces.hpp"
#include "Matrix.hpp"
#include <iostream>
namespace TexturedES2 {
#define STRINGIFY(A) #A
/*
#include "./Shaders/Simple.es2.vert"
#include "./Shaders/Simple.es2.frag"
#include "./Shaders/PixelLighting.es2.frag"
#include "./Shaders/PixelLighting.es2.vert"
#include "./Shaders/ToonShading.es2.frag"
*/
#include "./Shaders/TexturedLighting.es2.vert"
#include "./Shaders/TexturedLighting.es2.frag"
struct UniformHandles {
GLuint Modelview;
GLuint Projection;
GLuint NormalMatrix;
GLuint LightPosition;
GLint AmbientMaterial;
GLint SpecularMaterial;
GLint Shininess;
GLint Sampler; // new in texture
};
struct AttributeHandles {
GLint Position;
GLint Normal;
GLint DiffuseMaterial;
GLint TextureCoord; // new in texture
};
struct Drawable {
GLuint VertexBuffer;
GLuint IndexBuffer;
int IndexCount;
};
class RenderingEngine : public IRenderingEngine {
public:
// RenderingEngine();
RenderingEngine(IResourceManager*); // replace in texture
void Initialize(const vector<ISurface*>& surfaces);
void Render(const vector<Visual>& visuals) const;
void setLightPos(float x, float y, float z) ; // const // 使用const就變成惟讀
void setGLSL(int mode);
void setTexture (int mode);
void setTextureWrapS(int mode);
void setTextureWrapT(int mode);
void setTextureMagFilter(int mode);
void setTextureMinFilter(int mode);
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; // new 改成用struct 模式來控制 GLSL 檔中的uniform 變數
AttributeHandles m_attributes; // new 改成用struct 模式來控制 GLSL 檔中的 attribute 變數
GLuint m_gridTexture; // new in texture
IResourceManager* m_resourceManager; // new in texture
float lightPosX;
float lightPosY;
float lightPosZ;
int GLSL_Mode;
int textureMode;
int textureWrapS;
int textureWrapT;
int textureMagFilter;
int textureMinFilter;
};
.....
RenderingEngine::RenderingEngine(IResourceManager* resourceManager)
{
m_resourceManager = resourceManager;
glGenRenderbuffers(1, &m_colorRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, m_colorRenderbuffer);
GLSL_Mode = 0;
textureMode = DefaultTexture;
}
//只要與Initialize有關的變數,都要重新啓動
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;
/*
//(*surface)->GenerateVertices(vertices);
(*surface)->GenerateVertices(vertices, VertexFlagsNormals); // new / replace
*/
unsigned char vertexFlags = VertexFlagsNormals | VertexFlagsTexCoords;
(*surface)->GenerateVertices(vertices, vertexFlags); // now vertexFlags == 3
//Tell the ParametricSurface object that
//we need normals by passing in the new VertexFlagsNormals flag.
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); // 新增drawable至 m_drawables 的尾端,必要時會進行記憶體配置。
}
// 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);
// 设置FrameBuffer并使用glFramebufferRenderBuffer相互关联
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);
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"); // for texture
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"); // for texture
// 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);
// Load the texture.
glGenTextures(1, &m_gridTexture);
glBindTexture(GL_TEXTURE_2D, m_gridTexture);
//====== Texture filtering =============================================================
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); only in v1.1
//
if (textureMinFilter == 1)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
else if (textureMinFilter == 2)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
else if (textureMinFilter == 3)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
else if (textureMinFilter == 4)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
else if (textureMinFilter == 5)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);
else
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
if (textureMinFilter == 1)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
else if (textureMinFilter == 2)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, degree); only in v1.1
//==============================
//------ texture coordinate ------------------------------------------------------------
//glBindTexture(GL_TEXTURE_2D, m_gridTexture);
if (textureWrapS == 1)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
else if (textureWrapS == 2)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
else
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
if (textureWrapT == 1)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
else if (textureWrapT == 2)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
else
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
//--------------------------------
//glHint(GL_GENERATE_MIPMAP_HINT, GL_FASTEST);
if (textureMode == 2)
m_resourceManager->LoadPngImage("Spiked32x32");
else if (textureMode == 4)
m_resourceManager->LoadPngImage("大雄128x64");
else if (textureMode == 3)
m_resourceManager->LoadPngImage("flake64x64");
else if (textureMode == 1)
m_resourceManager->LoadPngImage("Sunflower16x16");
else if (textureMode == 5)
m_resourceManager->LoadPngImage("Checkerboard");
else
m_resourceManager->LoadPngImage("Grid16");
void* pixels = m_resourceManager->GetImageData();
ivec2 size = m_resourceManager->GetImageSize();
if (textureMode == 5)
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, size.x, size.y, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, pixels);
else
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.x, size.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
m_resourceManager->UnloadImage(); // 這時已經不需圖檔資源了,已經在GL_TEXTURE_2D中了。
glGenerateMipmap(GL_TEXTURE_2D); //自動產生Mipmap的小圖
// 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);
// // Set up some matrices.
// m_translation = mat4::Translate(0, 0, -7);
// m_projectionUniform = glGetUniformLocation(simpleProgram, "Projection");
// m_modelviewUniform = glGetUniformLocation(simpleProgram, "Modelview");
// Initialize various state.
glEnableVertexAttribArray(m_attributes.Position);
glEnableVertexAttribArray(m_attributes.Normal);
glEnableVertexAttribArray(m_attributes.TextureCoord); // for texture
glEnable(GL_DEPTH_TEST);
// Set up transforms. (change line position)
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();
// 將所有的圖像都畫出,Button上的圖像,使用相對小的Size(64,48), 主圖大小為(320,432)
// 0~5, 5指的是主畫面
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.
//vec4 lightPosition(0.25, 0.25, 1, 0);
vec4 lightPosition(lightPosX,lightPosY, lightPosZ,0);
glUniform3fv(m_uniforms.LightPosition, 1, lightPosition.Pointer());
// Set the model-view transform.
mat4 rotation = visual->Orientation.ToMatrix(); // 只有主圖像的旋轉四元值被讀入,並轉為矩陣。
mat4 modelview = rotation * m_translation; // m_translation =[0,0, -7]
//glUniformMatrix4fv(m_modelviewUniform, 1, 0, modelview.Pointer());
glUniformMatrix4fv(m_uniforms.Modelview, 1, 0, modelview.Pointer());
// Set the normal matrix.
// It's orthogonal, so its Inverse-Transpose is itself!
mat3 normalMatrix = modelview.ToMat3();
glUniformMatrix3fv(m_uniforms.NormalMatrix, 1, 0, normalMatrix.Pointer());
// Set the projection transform.
float h = 4.0f * size.y / size.x;
mat4 projectionMatrix = mat4::Frustum(-2, 2, -h / 2, h / 2, 5, 10);
//glUniformMatrix4fv(m_projectionUniform, 1, 0, projectionMatrix.Pointer());
glUniformMatrix4fv(m_uniforms.Projection, 1, 0, projectionMatrix.Pointer());
// Set the color.
// vec3 color = visual->Color;
// glVertexAttrib4f(m_colorSlot, color.x, color.y, color.z, 1);
//
// 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(vec3) + sizeof(vec2);
const GLvoid* normalOffset = (const GLvoid*) sizeof(vec3);
const GLvoid* texCoordOffset = (const GLvoid*) (2 * sizeof(vec3));
GLint position = m_attributes.Position;
GLint normal = m_attributes.Normal;
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(normal, 3, GL_FLOAT, GL_FALSE, stride, normalOffset);
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);
}
}
.....
void RenderingEngine::setTextureMagFilter(int mode)
{
textureMagFilter = mode;
}
void RenderingEngine::setTextureMinFilter(int mode)
{
textureMinFilter = mode;
}
}
9. ApplicationEngine.Viewer.cpp
#include "Interfaces.hpp"
#include "ParametricEquations.hpp"
using namespace std;
namespace ParametricViewer {
static const int SurfaceCount = 6;
static const int ButtonCount = SurfaceCount - 1;
struct Animation {
bool Active;
float Elapsed;
float Duration;
Visual StartingVisuals[SurfaceCount];
Visual EndingVisuals[SurfaceCount];
};
class ApplicationEngine : public IApplicationEngine {
public:
//ApplicationEngine(IRenderingEngine* renderingEngine, IResourceManager* resourceManager);
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);
void SetIconRotateValue(float x, float y, float z);
void setLightPos(float x, float y, float z);
void setGLSL(int mode);
void setTexture(int mode);
void setTextureWrapS(int mode);
void setTextureWrapT(int mode);
void setAutoRotate();
void setTextureMagFilter(int mode);
void setTextureMinFilter(int mode);
//Quaternion get_m_orientation();
//void set_m_orientation(Quaternion in_orientation);
private:
void PopulateVisuals(Visual* visuals) const;
int MapToButton(ivec2 touchpoint) const;
vec3 MapToSphere(ivec2 touchpoint) const;
float m_trackballRadius;
ivec2 m_screenSize;
ivec2 m_centerPoint;
ivec2 m_fingerStart;
bool m_spinning;
Quaternion m_orientation;
Quaternion m_previousOrientation;
int m_currentSurface;
ivec2 m_buttonSize;
int m_pressedButton;
int m_buttonSurfaces[ButtonCount];
Animation m_animation;
bool m_animationAuto; // add by kirenenko for auto rotating
IRenderingEngine* m_renderingEngine;
//IResourceManager* m_resourceManager; // objViewer only
float smallIconRotateXValue;
float smallIconRotateYValue;
float smallIconRotateZValue;
float lightPosX;
float lightPosY;
float lightPosZ;
int GLSL_Mode;
int textureMode;
int textureWrapS;
int textureWrapT;
int textureMagFilter;
int textureMinFilter;
//Quaternion old_m_orientation;
};
IApplicationEngine* CreateApplicationEngine(IRenderingEngine* renderingEngine)
{
return new ApplicationEngine(renderingEngine);
}
ApplicationEngine::ApplicationEngine(IRenderingEngine* renderingEngine) :
m_spinning(false),
m_pressedButton(-1),
m_renderingEngine(renderingEngine)
{
m_animation.Active = false;
m_animationAuto = 1;
m_buttonSurfaces[0] = 0;
m_buttonSurfaces[1] = 1;
m_buttonSurfaces[2] = 4;
m_buttonSurfaces[3] = 5;
m_buttonSurfaces[4] = 2;
m_currentSurface = 3; //調換一下順序,方便觀察
textureMode = DefaultTexture;
}
ApplicationEngine::~ApplicationEngine()
{
delete m_renderingEngine;
}
void ApplicationEngine::Initialize(int width, int height)
{
m_trackballRadius = width / 3;
m_buttonSize.y = height / 10;
m_buttonSize.x = 4 * m_buttonSize.y / 3;
m_screenSize = ivec2(width, height - m_buttonSize.y);
m_centerPoint = m_screenSize / 2;
vector<ISurface*> surfaces(SurfaceCount);
surfaces[0] = new Cone(3, 1); // 設定半徑及高,其他
surfaces[1] = new Sphere(1.4f);
surfaces[2] = new Torus(1.4f, 0.3f);
surfaces[3] = new TrefoilKnot(1.8f);
surfaces[4] = new KleinBottle(0.2f);
surfaces[5] = new MobiusStrip(1);
//m_renderingEngine->setGLSL(GLSL_Mode);
m_renderingEngine->setTexture(textureMode);
m_renderingEngine->setTextureWrapS(textureWrapS);
m_renderingEngine->setTextureWrapT(textureWrapT);
m_renderingEngine->setTextureMagFilter(textureMagFilter);
m_renderingEngine->setTextureMinFilter(textureMinFilter);
m_renderingEngine->Initialize(surfaces);
for (int i = 0; i < SurfaceCount; i++)
delete surfaces[i];
}
void ApplicationEngine::PopulateVisuals(Visual* visuals) const
{
//設定所有圖像的顏色與大小,包含主圖及Button
for (int buttonIndex = 0; buttonIndex < ButtonCount; buttonIndex++) {
int visualIndex = m_buttonSurfaces[buttonIndex];
//visuals[visualIndex].Color = vec3(0.25f, 0.25f, 0.25f);
visuals[visualIndex].Color = vec3(1, 1, 1);
if (m_pressedButton == buttonIndex)
visuals[visualIndex].Color = vec3(0.5f, 0.5f, 0.5f);
// 設定每一個Button上的圖案大小
// visuals[visualIndex].ViewportSize = m_buttonSize;
// visuals[visualIndex].LowerLeft.x = buttonIndex * m_buttonSize.x;
// visuals[visualIndex].LowerLeft.y = 0;
// visuals[visualIndex].Orientation = Quaternion(); // 基本button的旋轉值為0
visuals[visualIndex].ViewportSize = m_buttonSize;
visuals[visualIndex].LowerLeft.x = 0;
visuals[visualIndex].LowerLeft.y = m_screenSize.y - buttonIndex * m_buttonSize.y ;
//visuals[visualIndex].Orientation = Quaternion(0,0,0,1); // 基本button的旋轉值為0
/* texture code
visuals[visualIndex].ViewportSize = m_buttonSize;
visuals[visualIndex].LowerLeft.x = buttonIndex * m_buttonSize.x;
visuals[visualIndex].LowerLeft.y = 0;
visuals[visualIndex].Orientation = Quaternion();
*/
float angleValueX = smallIconRotateXValue; // -1 ~ 1 , 負值為順時鐘
float angleX = M_PI_2 *angleValueX;
float sinx = sin(angleX);
float cosx = cos(angleX);
float angleValueY = smallIconRotateYValue; // -1 ~ 1 , 負值為順時鐘
float angleY = M_PI_2 *angleValueY;
float siny = sin(angleY);
float cosy = cos(angleY);
float angleValueZ = smallIconRotateZValue; // -1 ~ 1 , 負值為順時鐘
float angleZ = M_PI_2 *angleValueZ;
float sinz = sin(angleZ);
float cosz = cos(angleZ);
Quaternion x = Quaternion(sinx*1,sinx*0, sinx*0, cosx);
Quaternion y = Quaternion(siny*0,siny*1, siny*0, cosy);
Quaternion z = Quaternion(sinz*0,sinz*0, sinz*1, cosz);
Quaternion xy = x.Rotated(y);
Quaternion xyz = xy.Rotated(z);
visuals[visualIndex].Orientation = xyz;
}
// 顯示主圖的顏色,m_spinning代表手指按下的狀態,蓋掉前面所設的值
//visuals[m_currentSurface].Color = m_spinning ? vec3(1, 1, 0.75f) : vec3(1, 1, 0.5f); //沒按時是金黃色
visuals[m_currentSurface].Color = m_spinning ? vec3(1, 1, 0.75f) : vec3(1, 1, 1); // 回復黑白色
visuals[m_currentSurface].LowerLeft = ivec2(0, m_buttonSize.y);
visuals[m_currentSurface].ViewportSize = ivec2(m_screenSize.x, m_screenSize.y);
visuals[m_currentSurface].Orientation = m_orientation; //主圖的旋轉值
}
void ApplicationEngine::Render() const
{
vector<Visual> visuals(SurfaceCount);
if (!m_animation.Active) {
//visuals[0]->set_m_orientation(old_m_orientation);
PopulateVisuals(&visuals[0]);
} else {
float t = m_animation.Elapsed / m_animation.Duration;
for (int i = 0; i < SurfaceCount; i++) {
// 找出起始的visuals[x] 及最後的visuals[y]
const Visual& start = m_animation.StartingVisuals[i];
const Visual& end = m_animation.EndingVisuals[i];
Visual& tweened = visuals[i]; // 這時的 visuals[]中是空的
// 以下將所有的值重新填到新的visuals[]中,根據現在所見的狀態
tweened.Color = start.Color.Lerp(t, end.Color); //將顏色做線性插補取得時間變化值
tweened.LowerLeft = start.LowerLeft.Lerp(t, end.LowerLeft);
tweened.ViewportSize = start.ViewportSize.Lerp(t, end.ViewportSize);
tweened.Orientation = start.Orientation.Slerp(t, end.Orientation);
}
}
m_renderingEngine->setLightPos(lightPosX,lightPosY,lightPosZ);
m_renderingEngine->Render(visuals);
}
void ApplicationEngine::UpdateAnimation(float dt)
{
if (m_animation.Active) { // 改選成另一個物件
m_animation.Elapsed += dt;
if (m_animation.Elapsed > m_animation.Duration)
m_animation.Active = false;
}
if (m_animationAuto) { // 第一次為true,計算主圖的旋轉值
vec3 axis(0, 1, 0);
float angle = M_PI / 2;
Quaternion spin = Quaternion::CreateFromAxisAngle(axis, angle);
Quaternion rotated = m_orientation.Rotated(spin);
m_orientation = m_orientation.Slerp(dt / 5, rotated);
}
}
.....
void ApplicationEngine::setAutoRotate()
{
m_animationAuto = 1;
}
void ApplicationEngine::setTextureMagFilter(int mode)
{
textureMagFilter = mode;
}
void ApplicationEngine::setTextureMinFilter(int mode)
{
textureMinFilter = mode;
}
// 3. 手指離開
void ApplicationEngine::OnFingerUp(ivec2 location)
{
m_spinning = false;
m_animationAuto = false;
if (m_pressedButton != -1 && m_pressedButton == MapToButton(location) &&
!m_animation.Active) // 如果按選了其他的物件,就進行以下的程序
{
m_animation.Active = true;
m_animation.Elapsed = 0;
m_animation.Duration = 0.25f;
PopulateVisuals(&m_animation.StartingVisuals[0]);
swap(m_buttonSurfaces[m_pressedButton], m_currentSurface); // 點選的Button圖像與主圖像交換
PopulateVisuals(&m_animation.EndingVisuals[0]);
}
m_pressedButton = -1;
}
// 1. 壓下手指
void ApplicationEngine::OnFingerDown(ivec2 location)
{
m_animationAuto = false;
m_fingerStart = location;
m_previousOrientation = m_orientation;
m_pressedButton = MapToButton(location); // 取得現在的旋轉值
if (m_pressedButton == -1)
m_spinning = true;
}
// 2. 移動手指讓物件轉動
void ApplicationEngine::OnFingerMove(ivec2 oldLocation, ivec2 location)
{
m_animationAuto = false;
if (m_spinning) {
vec3 start = MapToSphere(m_fingerStart);
vec3 end = MapToSphere(location);
Quaternion delta = Quaternion::CreateFromVectors(start, end); // 取得方向向量
m_orientation = delta.Rotated(m_previousOrientation); // 根據前一個旋轉值,計算再次旋轉後的值,此為主圖所用
}
if (m_pressedButton != -1 && m_pressedButton != MapToButton(location))
m_pressedButton = -1;
}
// 確認所按的位置為主圖像的位置,並回傳所按的點,經計算後的3D位置。
vec3 ApplicationEngine::MapToSphere(ivec2 touchpoint) const
{
vec2 p = touchpoint - m_centerPoint;
// Flip the Y axis because pixel coords increase towards the bottom.
p.y = -p.y;
const float radius = m_trackballRadius;
const float safeRadius = radius - 1;
if (p.Length() > safeRadius) {
float theta = atan2(p.y, p.x);
p.x = safeRadius * cos(theta);
p.y = safeRadius * sin(theta);
}
float z = sqrt(radius * radius - p.LengthSquared());
vec3 mapped = vec3(p.x, p.y, z);
return mapped / radius;
}
/*
// 確認按到了Button 的位置,並回傳所按的Button代號。原始的
int ApplicationEngine::MapToButton(ivec2 touchpoint) const
{
if (touchpoint.y < m_screenSize.y - m_buttonSize.y)
return -1;
int buttonIndex = touchpoint.x / m_buttonSize.x;
if (buttonIndex >= ButtonCount)
return -1;
return buttonIndex;
}
*/
// 確認按到了Button 的位置,並回傳所按的Button代號。 修改後給 landscape用
int ApplicationEngine::MapToButton(ivec2 touchpoint) const
{
if (touchpoint.x > m_buttonSize.x)
return -1;
//m_screenSize.y - buttonIndex * m_buttonSize.y ;
int buttonIndex = (touchpoint.y) / m_buttonSize.y;
if (buttonIndex >= ButtonCount)
return -1;
return buttonIndex;
}
}
10. 結果,並看不出差異之所在,也許實驗的例子太差的緣故。