#include "model.h" #include #include #include // 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; }