Created
November 18, 2014 22:05
-
-
Save MichaelSnowden/0d03155e3cbd20fcd04c to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Cube.h | |
// OpenGL | |
// | |
// Created by Michael Snowden on 11/15/14. | |
// Copyright (c) 2014 MichaelSnowden. All rights reserved. | |
// | |
#import <Foundation/Foundation.h> | |
#import <OpenGLES/ES1/glext.h> | |
// Axis indices are just a way of encoding x, y, and z as integers | |
// x = 0 | |
// y = 1 | |
// z = 2 | |
// ... | |
// For example, a rotation in the xy plane (about the z axis then), uses a {0, 1} plane | |
typedef struct { | |
GLuint firstAxisIndex; | |
GLuint secondAxisIndex; | |
} Plane; | |
@interface Cube : NSObject | |
@property(assign, nonatomic) NSUInteger dim; | |
- (id)initWithDim:(NSUInteger) dim; | |
- (void)tearDownGL; | |
- (void)prepareToRender; | |
- (void)render; | |
- (void)rotateInPlane:(Plane) plane withAngle:(float) theta; | |
@end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Cube.m | |
// OpenGL | |
// | |
// Created by Michael Snowden on 11/15/14. | |
// Copyright (c) 2014 MichaelSnowden. All rights reserved. | |
// | |
#import "Cube.h" | |
#import <OpenGLES/ES1/glext.h> | |
#import <GLKit/GLKit.h> | |
#include <vector> | |
#include <algorithm> | |
#define BUFFER_OFFSET(i) ((char *)NULL + (i)) | |
#define IS_BIT_SET(var,pos) (var & 1<<pos) | |
#define MAGNITUDE 0.1f | |
std::vector<GLfloat> _vertexData; | |
std::vector<GLuint> _indexData; | |
@implementation Cube { | |
GLuint _vertexArray; | |
GLuint _vertexBuffer; | |
GLuint _indexBuffer; | |
} | |
- (id)initWithDim:(NSUInteger)dim { | |
if (self = [super init]) { | |
assert(dim > 0); | |
_dim = dim; | |
[self setupGeometry]; | |
[self setupGL]; | |
} | |
return self; | |
} | |
- (void)setupGL { | |
glGenVertexArraysOES(1, &_vertexArray); | |
glBindVertexArrayOES(_vertexArray); | |
glGenBuffers(1, &_vertexBuffer); | |
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer); | |
glBufferData(GL_ARRAY_BUFFER, _vertexData.size() * sizeof(GLfloat), &_vertexData[0], GL_DYNAMIC_DRAW); | |
glGenBuffers(1, &_indexBuffer); | |
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer); | |
glBufferData(GL_ELEMENT_ARRAY_BUFFER, _indexData.size() * sizeof(GLuint), &_indexData[0], GL_STATIC_DRAW); | |
glEnableVertexAttribArray(GLKVertexAttribPosition); | |
glVertexAttribPointer(GLKVertexAttribPosition, _dim, GL_FLOAT, GL_FALSE, _dim * sizeof(GLfloat), BUFFER_OFFSET(0)); | |
} | |
- (void)setupGeometry { | |
_vertexData.resize(_dim * (1 << _dim)); // We have 2^dim vertices. i.e. 2^3 for a cube | |
[self setupVertices]; | |
[self setupIndices]; | |
} | |
- (void)setupVertices { // Creates vertices out of corresponding bit strings | |
for (int i = 0; i < _vertexData.size() / _dim; ++i) { | |
for (int j = 0; j < _dim; ++j) { | |
_vertexData[i*_dim+j] = IS_BIT_SET(i, j) ? MAGNITUDE : -MAGNITUDE; | |
} | |
} | |
} | |
- (void)setupIndices { // Connects all vertices that differ by 1 bit | |
_indexData.reserve(_vertexData.size()); | |
for (int u = 0; u < (1 << _dim); ++u) { | |
for (int i = 1; i & ((1 << _dim) - 1); i <<= 1) { | |
if (!(u&i)) { | |
_indexData.push_back(u); | |
_indexData.push_back(u | i); | |
} | |
} | |
} | |
} | |
- (void)prepareToRender { | |
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer); | |
glBindVertexArrayOES(_vertexArray); | |
} | |
- (void)render { | |
glDrawElements(GL_LINES, _indexData.size(), GL_UNSIGNED_INT, 0); | |
} | |
- (void)tearDownGL { | |
glDeleteBuffers(1, &_vertexBuffer); | |
glDeleteVertexArraysOES(1, &_vertexArray); | |
} | |
- (void)dealloc { | |
[self tearDownGL]; | |
} | |
- (void)rotateInPlane:(Plane)plane withAngle:(float)theta { | |
assert(plane.firstAxisIndex < _dim); | |
assert(plane.secondAxisIndex < _dim); | |
for (int i = 0; i < _vertexData.size(); i += _dim) { | |
int i1 = i + plane.firstAxisIndex; | |
int i2 = i + plane.secondAxisIndex; | |
float temp = _vertexData[i1]*cos(theta) - _vertexData[i2]*sin(theta); | |
_vertexData[i2] = _vertexData[i1]*sin(theta) + _vertexData[i2]*cos(theta); | |
_vertexData[i1] = temp; | |
} | |
glBufferSubData(GL_ARRAY_BUFFER, 0, _vertexData.size() * sizeof(GLfloat), &_vertexData[0]); | |
} | |
@end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// ___VARIABLE_classPrefix:identifier___ViewController.m | |
// OpenGL | |
// | |
// Created by Michael Snowden on 11/15/14. | |
// Copyright (c) 2014 MichaelSnowden. All rights reserved. | |
// | |
#import "ViewController.h" | |
#import <OpenGLES/ES1/glext.h> | |
#import "Cube.h" | |
@interface ViewController () { | |
GLuint _program; | |
GLKMatrix4 _modelViewProjectionMatrix; | |
GLKMatrix3 _normalMatrix; | |
} | |
@property (strong, nonatomic) EAGLContext *context; | |
@property (strong, nonatomic) GLKBaseEffect *effect; | |
@property (strong, nonatomic) Cube *cube; | |
- (void)setupGL; | |
- (void)tearDownGL; | |
@end | |
@implementation ViewController | |
- (void)viewDidLoad | |
{ | |
[super viewDidLoad]; | |
self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; | |
if (!self.context) { | |
NSLog(@"Failed to create ES context"); | |
} | |
GLKView *view = (GLKView *)self.view; | |
view.context = self.context; | |
view.drawableDepthFormat = GLKViewDrawableDepthFormat24; | |
[self setupGL]; | |
} | |
- (void)dealloc | |
{ | |
[self tearDownGL]; | |
if ([EAGLContext currentContext] == self.context) { | |
[EAGLContext setCurrentContext:nil]; | |
} | |
} | |
- (void)didReceiveMemoryWarning | |
{ | |
[super didReceiveMemoryWarning]; | |
if ([self isViewLoaded] && ([[self view] window] == nil)) { | |
self.view = nil; | |
[self tearDownGL]; | |
if ([EAGLContext currentContext] == self.context) { | |
[EAGLContext setCurrentContext:nil]; | |
} | |
self.context = nil; | |
} | |
// Dispose of any resources that can be recreated. | |
} | |
- (void)setupGL | |
{ | |
[EAGLContext setCurrentContext:self.context]; | |
self.effect = [[GLKBaseEffect alloc] init]; | |
self.effect.light0.enabled = GL_TRUE; | |
self.effect.light0.diffuseColor = GLKVector4Make(1.0f, 0.4f, 0.4f, 1.0f); | |
glEnable(GL_DEPTH_TEST); | |
_cube = [[Cube alloc] initWithDim:4]; | |
float aspect = fabsf(self.view.bounds.size.width / self.view.bounds.size.height); | |
GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(65.0f), aspect, 0.1f, 100.0f); | |
self.effect.transform.projectionMatrix = projectionMatrix; | |
GLKMatrix4 baseModelViewMatrix = GLKMatrix4MakeTranslation(0.0f, 0.0f, -4.0f); | |
baseModelViewMatrix = GLKMatrix4Rotate(baseModelViewMatrix, 0.f, 0.0f, 1.0f, 0.0f); | |
// Compute the model view matrix for the object rendered with GLKit | |
GLKMatrix4 modelViewMatrix = GLKMatrix4MakeTranslation(0.0f, 0.0f, -1.5f); | |
modelViewMatrix = GLKMatrix4Rotate(modelViewMatrix, 0.f, 1.0f, 1.0f, 1.0f); | |
modelViewMatrix = GLKMatrix4Multiply(baseModelViewMatrix, modelViewMatrix); | |
self.effect.transform.modelviewMatrix = modelViewMatrix; | |
} | |
- (void)tearDownGL | |
{ | |
[EAGLContext setCurrentContext:self.context]; | |
[_cube tearDownGL]; | |
self.effect = nil; | |
if (_program) { | |
glDeleteProgram(_program); | |
_program = 0; | |
} | |
} | |
#pragma mark - GLKView and GLKViewController delegate methods | |
- (void)update | |
{ | |
[_cube rotateInPlane:Plane{0,1} withAngle:0.040f]; // xy plane | |
[_cube rotateInPlane:Plane{0,2} withAngle:0.030f]; // xz plane | |
[_cube rotateInPlane:Plane{1,2} withAngle:0.010f]; // yz plane | |
} | |
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect | |
{ | |
glClearColor(0.65f, 0.65f, 0.65f, 1.0f); | |
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | |
[_cube prepareToRender]; | |
[self.effect prepareToDraw]; | |
[_cube render]; | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment