rendered paste body#include "model.h"
#include <malloc.h>
#include <math.h>
#include <GL/gl.h> // Header File For The OpenGL32 Library
/************************ INITIALIZATION ************************/
void initObject(Object* object, Point3D position);
void initSpring(Spring* spring, Object* a, Object* b);
Model* initModel()
{
Model* model = (Model*) malloc(sizeof(Model));
Point3D position;
int i, j, k = 0;
for (i = 0; i < GRID_WIDTH; i++)
{
for (j = 0; j < GRID_HEIGHT; j++)
{
position.x = 2 * i * POSITION_RANGE / (GRID_WIDTH - 1) - POSITION_RANGE;
position.y = 2 * j * POSITION_RANGE / (GRID_HEIGHT - 1) - POSITION_RANGE;
position.z = 0.0f;
initObject(&model->object[i][j], position);
if (j - 1 >= 0)
{
initSpring(&model->spring[k], &model->object[i][j - 1], &model->object[i][j]);
k++;
}
if (i - 1 >= 0)
{
initSpring(&model->spring[k], &model->object[i - 1][j], &model->object[i][j]);
k++;
}
}
}
initAnimation(model);
return model;
}
void initObject(Object* object, Point3D position)
{
object->position = object->prevPosition = position;
object->anchor = FALSE;
}
void initSpring(Spring* spring, Object* a, Object* b)
{
spring->a = a;
spring->b = b;
spring->offset.x = b->position.x - a->position.x;
spring->offset.y = b->position.y - a->position.y;
spring->offset.z = b->position.z - a->position.z;
}
/************************ STEPPING ************************/
void cleanForces(Model* model);
void applySpringForce(Spring* spring);
void stepObject(Object* object);
void stepModel(Model* model)
{
int i, j;
cleanForces(model);
for (i = 0; i < NUM_SPRINGS; i++)
applySpringForce(&model->spring[i]);
for (i = 0; i < GRID_WIDTH; i++)
{
for (j = 0; j < GRID_HEIGHT; j++)
stepObject(&model->object[i][j]);
}
stepAnimation(model);
}
void cleanForces(Model* model)
{
int i, j;
for (i = 0; i < GRID_WIDTH; i++)
{
for (j = 0; j < GRID_HEIGHT; j++)
{
model->object[i][j].force.x = 0.0f;
model->object[i][j].force.y = 0.0f;
model->object[i][j].force.z = 0.0f;
}
}
}
void applySpringForce(Spring* spring)
{
/* TODO: spring_k, double force when the other object is anchor.
another spring model: the spring can change it's dx / dy / dz as long
as the spring's length doesn't change. the spring will act according to
the spring length and not according to dx / dy / dz.
*/
Object* a = spring->a;
Object* b = spring->b;
Vector3D force;
force.x = b->position.x - a->position.x - spring->offset.x;
force.y = b->position.y - a->position.y - spring->offset.y;
force.z = b->position.z - a->position.z - spring->offset.z;
force.x *= SPRING_K / 40.0f;
force.y *= SPRING_K / 40.0f;
force.z *= SPRING_K / 40.0f;
a->force.x += force.x / 2.0f;
a->force.y += force.y / 2.0f;
a->force.z += force.z / 2.0f;
b->force.x -= force.x / 2.0f;
b->force.y -= force.y / 2.0f;
b->force.z -= force.z / 2.0f;
}
void stepObject(Object* object)
{
/* TODO: friction, dt (for now it is considered 1. we will need to do position = 2 * position - prevPosition + force * (dt ^ 2))
*/
if (!object->anchor)
{
Vector3D velocity;
velocity.x = object->position.x - object->prevPosition.x;
velocity.y = object->position.y - object->prevPosition.y;
velocity.z = object->position.z - object->prevPosition.z;
object->force.x -= FRICTION * velocity.x / 30.0f;
object->force.y -= FRICTION * velocity.y / 30.0f;
object->force.z -= FRICTION * velocity.z / 30.0f;
object->prevPosition = object->position;
object->position.x += velocity.x + object->force.x;
object->position.y += velocity.y + object->force.y;
object->position.z += velocity.z + object->force.z;
}
else
{
object->prevPosition = object->position;
}
}
/************************ DRAWING ************************/
Point3D bezierEvaluate(Model* model, float u, float v);
void scalePoint(Point3D* point);
void drawModel(Model* model)
{
int i, j;
float u1, u2, v1, v2;
Point3D vertex1, vertex2, vertex3, vertex4;
glBegin(GL_QUADS);
for (i = 0; i < PAINT_GRID_WIDTH - 1; i++)
{
for (j = 0; j < PAINT_GRID_HEIGHT - 1; j++)
{
u1 = (float) i / (PAINT_GRID_WIDTH - 1);
u2 = (float) (i + 1) / (PAINT_GRID_WIDTH - 1);
v1 = (float) j / (PAINT_GRID_HEIGHT - 1);
v2 = (float) (j + 1) / (PAINT_GRID_HEIGHT - 1);
vertex1 = bezierEvaluate(model, u1, v1);
vertex2 = bezierEvaluate(model, u1, v2);
vertex3 = bezierEvaluate(model, u2, v2);
vertex4 = bezierEvaluate(model, u2, v1);
scalePoint(&vertex1);
scalePoint(&vertex2);
scalePoint(&vertex3);
scalePoint(&vertex4);
glTexCoord2f(u1, v1); glVertex3f(vertex1.x, vertex1.y, vertex1.z);
glTexCoord2f(u1, v2); glVertex3f(vertex2.x, vertex2.y, vertex2.z);
glTexCoord2f(u2, v2); glVertex3f(vertex3.x, vertex3.y, vertex3.z);
glTexCoord2f(u2, v1); glVertex3f(vertex4.x, vertex4.y, vertex4.z);
}
}
glEnd();
}
Point3D bezierEvaluate(Model* model, float u, float v)
{
float coeffsU[GRID_WIDTH], coeffsV[GRID_HEIGHT];
int i, j;
Point3D point;
if (u != 1.0f)
{
coeffsU[0] = pow(1 - u, GRID_WIDTH - 1);
for (i = 1; i < GRID_WIDTH; i++)
{
coeffsU[i] = coeffsU[i - 1] * u / (1 - u);
coeffsU[i] *= (float)(GRID_WIDTH - i) / i;
}
}
else
{
for (i = 0; i < GRID_WIDTH - 1; i++)
coeffsU[i] = 0.0f;
coeffsU[i] = 1.0f;
}
if (v != 1.0f)
{
coeffsV[0] = pow(1 - v, GRID_HEIGHT - 1);
for (j = 1; j < GRID_HEIGHT; j++)
{
coeffsV[j] = coeffsV[j - 1] * v / (1 - v);
coeffsV[j] *= (float)(GRID_HEIGHT - j) / j;
}
}
else
{
for (j = 0; j < GRID_HEIGHT - 1; j++)
coeffsV[j] = 0.0f;
coeffsV[j] = 1.0f;
}
point.x = point.y = point.z = 0.0f;
for (i = 0; i < GRID_WIDTH; i++)
{
for (j = 0; j < GRID_HEIGHT; j++)
{
point.x += coeffsU[i] * coeffsV[j] * model->object[i][j].position.x;
point.y += coeffsU[i] * coeffsV[j] * model->object[i][j].position.y;
point.z += coeffsU[i] * coeffsV[j] * model->object[i][j].position.z;
}
}
return point;
}
void scalePoint(Point3D* point)
{
point->x *= PAINT_POSITION_RANGE_X / POSITION_RANGE;
point->y *= PAINT_POSITION_RANGE_Y / POSITION_RANGE;
point->z *= PAINT_POSITION_RANGE_Z / POSITION_RANGE;
}