//
// Dice.m
// DiceRoller
//
// Created by Jacques Questiaux on 2012/04/17.
// Copyright (c) 2012 j.questiaux@gmail.com. All rights reserved.
//
#import "Dice.h"
#import "d4.h"
#import "d6.h"
#import "d8.h"
#import "d10.h"
#import "d12.h"
#import "d20.h"
#import "d100.h"
#include "btBulletDynamicsCommon.h"
typedef struct {
float r;
float g;
float b;
} Color;
Color faceColors [] ={
{1, 0, 0},
{0, 0, 1},
{0, 1, 0},
{1, 1, 0},
{1, 0, 1},
{0, 1, 1},
{1, 1, 1},
{0.1, 0.1, 0.1}
};
Color numbers [] ={
{1, 1, 1},
{1, 1, 1},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{1, 1, 1}
};
@interface Dice () {
GLuint _vertexArray;
GLuint _vertexBuffer;
GLuint _indexBuffer;
GLuint _colorBuffer;
GLuint _normalBuffer;
GLuint _textureBuffer;
GLuint toon_vertexArray;
GLuint toon_vertexBuffer;
GLuint toon_indexBuffer;
GLfloat *vertices;
GLushort *indices;
GLfloat *normals;
GLfloat *colors;
GLfloat *tex;
int numVertices;
int numIndices;
int numNormals;
int numColors;
int numTex;
btDynamicsWorld *dynamicsWorld;
btRigidBody *diceRigidBody;
btConvexHullShape *fallShape;
btDefaultMotionState *fallMotionState;
}
@end
@implementation Dice
@synthesize up = _up;
@synthesize front = _front;
@synthesize right = _right;
@synthesize position =_position;
@synthesize direction = _direction;
@synthesize modelViewMatrix = _modelViewMatrix;
- (id) initWithSides:(NSUInteger)s Color: (int) c{
if(self = [super init]){
Sides = s;
colorSelected = c;
return self;
}
return nil;
}
- (id)initWithCoder:(NSCoder *)coder {
if (self = [super init]) {
Sides = [coder decodeIntegerForKey:@"Sides"];
colorSelected = [coder decodeFloatForKey:@"Color"];
return self;
}
return nil;
}
- (void)encodeWithCoder:(NSCoder *)coder {
[coder encodeInteger:Sides forKey:@"Sides"];
[coder encodeFloat:colorSelected forKey:@"Color"];
}
- (void) Context: (EAGLContext *) c Effect: (Effects *) e DynamicsWorld: (btDynamicsWorld *) d View: (GLKView *) v {
self.right = GLKVector3Make(1, 0, 0);
self.up = GLKVector3Make(0, 1, 0);
self.front = GLKVector3Make(0, 0, 1);
context = c;
effect = e;
dynamicsWorld = d;
view = v;
friction = 0.95f;
selected = false;
matrix = new btScalar[15];
[self setup];
}
- (void) setup{
fallShape = new btConvexHullShape();
//too lazy to swap to a switch statement
if(Sides == 4){
vertices = d4vertices;
numVertices = sizeof(d4vertices)/sizeof(GLfloat);
indices = d4indices;
numIndices = sizeof(d4indices)/sizeof(GLushort);
normals = d4normals;
numNormals = sizeof(d4normals)/sizeof(GLfloat);
tex = d4tex;
numTex = sizeof(d4tex)/sizeof(GLfloat);
for(int i = 0; i < numVertices; i+=3){
btVector3 vert = btVector3(d4PhysicsVertices[i], d4PhysicsVertices[i+1], d4PhysicsVertices[i+2]);
fallShape->addPoint(vert);
}
}
else if(Sides == 6){
vertices = d6vertices;
numVertices = sizeof(d6vertices)/sizeof(GLfloat);
indices = d6indices;
numIndices = sizeof(d6indices)/sizeof(GLushort);
normals = d6normals;
numNormals = sizeof(d6normals)/sizeof(GLfloat);
tex = d6tex;
numTex = sizeof(d6tex)/sizeof(GLfloat);
for(int i = 0; i < numVertices; i+=3){
btVector3 vert = btVector3(d6PhysicsVertices[i], d6PhysicsVertices[i+1], d6PhysicsVertices[i+2]);
fallShape->addPoint(vert);
}
}
else if(Sides == 8){
vertices = d8vertices;
numVertices = sizeof(d8vertices)/sizeof(GLfloat);
indices = d8indices;
numIndices = sizeof(d8indices)/sizeof(GLushort);
normals = d8normals;
numNormals = sizeof(d8normals)/sizeof(GLfloat);
tex = d8tex;
numTex = sizeof(d8tex)/sizeof(GLfloat);
for(int i = 0; i < numVertices; i+=3){
btVector3 vert = btVector3(d8PhysicsVertices[i], d8PhysicsVertices[i+1], d8PhysicsVertices[i+2]);
fallShape->addPoint(vert);
}
}
else if(Sides == 10){
vertices = d10vertices;
numVertices = sizeof(d10vertices)/sizeof(GLfloat);
indices = d10indices;
numIndices = sizeof(d10indices)/sizeof(GLushort);
normals = d10normals;
numNormals = sizeof(d10normals)/sizeof(GLfloat);
tex = d10tex;
numTex = sizeof(d10tex)/sizeof(GLfloat);
for(int i = 0; i < numVertices; i+=3){
btVector3 vert = btVector3(d10PhysicsVertices[i], d10PhysicsVertices[i+1], d10PhysicsVertices[i+2]);
fallShape->addPoint(vert);
}
}
else if(Sides == 100){
vertices = d100vertices;
numVertices = sizeof(d100vertices)/sizeof(GLfloat);
indices = d100indices;
numIndices = sizeof(d100indices)/sizeof(GLushort);
normals = d100normals;
numNormals = sizeof(d100normals)/sizeof(GLfloat);
tex = d100tex;
numTex = sizeof(d100tex)/sizeof(GLfloat);
for(int i = 0; i < numVertices; i+=3){
btVector3 vert = btVector3(d100PhysicsVertices[i], d100PhysicsVertices[i+1], d100PhysicsVertices[i+2]);
fallShape->addPoint(vert);
}
}
else if(Sides == 12){
vertices = d12vertices;
numVertices = sizeof(d12vertices)/sizeof(GLfloat);
indices = d12indices;
numIndices = sizeof(d12indices)/sizeof(GLushort);
normals = d12normals;
numNormals = sizeof(d12normals)/sizeof(GLfloat);
tex = d12tex;
numTex = sizeof(d12tex)/sizeof(GLfloat);
for(int i = 0; i < numVertices; i+=3){
btVector3 vert = btVector3(d12PhysicsVertices[i], d12PhysicsVertices[i+1], d12PhysicsVertices[i+2]);
fallShape->addPoint(vert);
}
}
else {
vertices = d20vertices;
numVertices = sizeof(d20vertices)/sizeof(GLfloat);
indices = d20indices;
numIndices = sizeof(d20indices)/sizeof(GLushort);
normals = d20normals;
numNormals = sizeof(d20normals)/sizeof(GLfloat);
tex = d20tex;
numTex = sizeof(d20tex)/sizeof(GLfloat);
for(int i = 0; i < numVertices; i+=3){
btVector3 vert = btVector3(d20PhysicsVertices[i], d20PhysicsVertices[i+1], d20PhysicsVertices[i+2]);
fallShape->addPoint(vert);
}
}
glGenVertexArraysOES(1, &_vertexArray);
glBindVertexArrayOES(_vertexArray);
glGenBuffers(1, &_indexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, numIndices*sizeof(GLushort), indices, GL_STATIC_DRAW);
glGenBuffers(1, &_vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, numVertices*sizeof(GLfloat), vertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(effect->vertCoord);
glVertexAttribPointer(effect->vertCoord, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(effect->toon_vertCoord);
glVertexAttribPointer(effect->toon_vertCoord, 3, GL_FLOAT, GL_FALSE, 0, 0);
glGenBuffers(1, &_normalBuffer);
glBindBuffer(GL_ARRAY_BUFFER, _normalBuffer);
glBufferData(GL_ARRAY_BUFFER, numNormals*sizeof(GLfloat), normals, GL_STATIC_DRAW);
glEnableVertexAttribArray(effect->normal);
glVertexAttribPointer(effect->normal, 3, GL_FLOAT, GL_FALSE, 0, 0);
glGenBuffers(1, &_textureBuffer);
glBindBuffer(GL_ARRAY_BUFFER, _textureBuffer);
glBufferData(GL_ARRAY_BUFFER, numTex*sizeof(GLfloat), tex, GL_STATIC_DRAW);
glEnableVertexAttribArray(effect->texCoord);
glVertexAttribPointer(effect->texCoord, 2, GL_FLOAT, GL_FALSE, 0, 0);
glBindVertexArrayOES(0);
/*----- PHYSICS SETUP -----*/
fallMotionState = new btDefaultMotionState(btTransform(btQuaternion(0,0,0,1), btVector3(self.position.x,self.position.y,self.position.z))); //original position
btScalar mass = 0.1;
btVector3 fallInertia(0,0,0);
fallShape->calculateLocalInertia(mass, fallInertia);
btRigidBody::btRigidBodyConstructionInfo fallRigidBodyCI(mass,fallMotionState,fallShape,fallInertia);
fallRigidBodyCI.m_restitution = 0.3;
diceRigidBody = new btRigidBody(fallRigidBodyCI);
diceRigidBody->setDamping(0.9,0.3);
//diceRigidBody->setLinearFactor(btVector3(1,1,1));
diceRigidBody->setAngularFactor(btVector3(1,1,1));
dynamicsWorld->addRigidBody(diceRigidBody);
}
- (void) tearDown {
dynamicsWorld->removeRigidBody(diceRigidBody);
delete diceRigidBody;
delete fallShape;
delete fallMotionState;
glDeleteBuffers(1, &_vertexBuffer);
glDeleteBuffers(1, &_indexBuffer);
glDeleteBuffers(1, &_colorBuffer);
glDeleteBuffers(1, &_normalBuffer);
glDeleteBuffers(1, &_textureBuffer);
delete matrix;
}
- (void) update: (float) timeSinceLastUpdate{
tslu = timeSinceLastUpdate;
btTransform trans;
diceRigidBody->getMotionState()->getWorldTransform(trans);
diceRigidBody->activate();
self.position = GLKVector3Make(trans.getOrigin().getX(), trans.getOrigin().getY(), trans.getOrigin().getZ());
trans.getOpenGLMatrix(matrix);
self.right = GLKVector3Make(matrix[0], matrix[1], matrix[2]);
self.up = GLKVector3Make(matrix[4], matrix[5], matrix[6]);
self.front = GLKVector3Make(matrix[8], matrix[9], matrix[10]);
mvm = GLKMatrix4Make(self.right.x, self.right.y, self.right.z, 0,
self.up.x, self.up.y, self.up.z, 0,
self.front.x, self.front.y, self.front.z, 0,
self.position.x, self.position.y, self.position.z, 1);
}
- (void) draw {
[EAGLContext setCurrentContext:context];
glBindVertexArrayOES(_vertexArray);
effect->modelViewMatrix = mvm;
effect->numberColour = GLKVector4Make(numbers[colorSelected].r, numbers[colorSelected].g, numbers[colorSelected].b, 1);
effect->faceColour = GLKVector4Make(faceColors[colorSelected].r, faceColors[colorSelected].g, faceColors[colorSelected].b, 1);
if(selected){
[effect drawOutline];
glDrawElements(GL_TRIANGLES, numIndices, GL_UNSIGNED_SHORT, 0);
}
[effect prepareToDraw];
glDrawElements(GL_TRIANGLES, numIndices, GL_UNSIGNED_SHORT, 0);
}
- (void) applyForceInDirection: (GLKVector3) dir {
btVector3 v = btVector3(dir.x/3, dir.y/3, dir.z/3);
diceRigidBody->applyForce(v, btVector3(0, 0, 0));
btVector3 t = v.cross(btVector3(0, 0, -1));
t.normalized();
t *= 0.45f;
diceRigidBody->applyTorque(t);
}
GLKVector3 gluProject(GLKVector3 position,
GLKMatrix4 projMatrix,
GLKMatrix4 modelMatrix,
CGRect viewport
)
{
GLKVector4 in;
GLKVector4 out;
in = GLKVector4Make(position.x, position.y, position.z, 1.0);
out = GLKMatrix4MultiplyVector4(modelMatrix, in);
in = GLKMatrix4MultiplyVector4(projMatrix, out);
if (in.w == 0.0) NSLog(@"W = 0 in project function\n");
in.x /= in.w;
in.y /= in.w;
in.z /= in.w;
/* Map x, y and z to range 0-1 */
in.x = in.x * 0.5 + 0.5;
in.y = in.y * 0.5 + 0.5;
in.z = in.z * 0.5 + 0.5;
/* Map x,y to viewport */
in.x = in.x * viewport.size.width + viewport.origin.x;
in.y = in.y * viewport.size.height + viewport.origin.y;
return GLKVector3Make(in.x, in.y, in.z);
}
- (GLKVector2) getScreenCoordOfDice {
GLKVector3 out = gluProject(self.position, effect->projectionMatrix, effect->cameraMatrix, view.frame);
return GLKVector2Make(out.x,view.frame.size.height - out.y);
}
@end