summaryrefslogtreecommitdiff
path: root/sim.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'sim.cpp')
-rw-r--r--sim.cpp392
1 files changed, 14 insertions, 378 deletions
diff --git a/sim.cpp b/sim.cpp
index 0b7ecb5..c47c9d9 100644
--- a/sim.cpp
+++ b/sim.cpp
@@ -36,285 +36,8 @@ static v2 b2_to_gl(State const *state, v2 box2d_coordinates) {
return V2(v.x, v.y);
}
-
-// compile a vertex or fragment shader
-static GLuint shader_compile_from_file(GL *gl, char const *filename, GLenum shader_type) {
- FILE *fp = fopen(filename, "rb");
- if (fp) {
- char code[16384] = {0};
- char log[4096] = {0};
- char const *const_code = code;
- fread(code, 1, sizeof code, fp);
- GLuint shader = gl->CreateShader(shader_type);
- if (shader == 0) {
- logln("Couldn't create shader: %u",glGetError());
- }
- gl->ShaderSource(shader, 1, &const_code, NULL);
- gl->CompileShader(shader);
- gl->GetShaderInfoLog(shader, sizeof log - 1, NULL, log);
- if (*log) {
- logln("Error compiling shader:\n%s", log);
- gl->DeleteShader(shader);
- return 0;
- }
- return shader;
- } else {
- logln("File does not exist: %s.", filename);
- return 0;
- }
-}
-
-#if DEBUG
-static struct timespec shader_get_last_modified(ShaderBase *shader) {
- // the last modified time of the shader is whichever of the vertex/fragment shaders was modified last
- return timespec_max(
- time_last_modified(shader->vertex_filename),
- time_last_modified(shader->fragment_filename)
- );
-}
-#endif
-
-static GLuint shader_attrib_location(GL *gl, ShaderBase *shader, char const *attrib) {
- GLint loc = gl->GetAttribLocation(shader->program, attrib);
- if (loc == -1) {
- printf("Couldn't find vertex attribute %s.\n", attrib);
- return 0;
- }
- return (GLuint)loc;
-}
-
-static GLint shader_uniform_location(GL *gl, ShaderBase *shader, char const *uniform) {
- GLint loc = gl->GetUniformLocation(shader->program, uniform);
- if (loc == -1) {
- printf("Couldn't find uniform: %s.\n", uniform);
- return -1;
- }
- return loc;
-}
-
-// compile a full shader program
-static void shader_load(GL *gl, ShaderBase *shader, char const *vertex_filename, char const *fragment_filename) {
-#if DEBUG
- str_cpy(shader->vertex_filename, sizeof shader->vertex_filename, vertex_filename);
- str_cpy(shader->fragment_filename, sizeof shader->fragment_filename, fragment_filename);
- shader->last_modified = shader_get_last_modified(shader);
-
- if (shader->program) gl->DeleteProgram(shader->program);
-#endif
-
-
- GLuint vertex_shader = shader_compile_from_file(gl, vertex_filename, GL_VERTEX_SHADER);
- GLuint fragment_shader = shader_compile_from_file(gl, fragment_filename, GL_FRAGMENT_SHADER);
- GLuint program = gl->CreateProgram();
- gl->AttachShader(program, vertex_shader);
- gl->AttachShader(program, fragment_shader);
- gl->LinkProgram(program);
- char log[4096] = {0};
- gl->GetProgramInfoLog(program, sizeof log - 1, NULL, log);
- if (*log) {
- logln("Error linking shader:\n%s", log);
- gl->DeleteProgram(program);
- program = 0;
- }
- gl->DeleteShader(vertex_shader);
- gl->DeleteShader(fragment_shader);
- shader->program = program;
-
- GLenum err = glGetError();
- if (err) {
- logln("Error loading shader %s/%s: %u.", vertex_filename, fragment_filename, err);
- } else {
- logln("Loaded shader %s/%s as %u.", vertex_filename, fragment_filename, program);
- }
-}
-
-static void shader_start_using(GL *gl, ShaderBase *shader) {
- gl->UseProgram(shader->program);
-}
-
-static void shader_stop_using(GL *gl) {
- gl->UseProgram(0);
-}
-
-#if DEBUG
-static bool shader_needs_reloading(ShaderBase *shader) {
- return !timespec_eq(shader->last_modified, shader_get_last_modified(shader));
-}
-#endif
-
-static void shader_platform_load(GL *gl, ShaderPlatform *shader) {
- ShaderBase *base = &shader->base;
- shader_load(gl, base, "assets/platform_v.glsl", "assets/platform_f.glsl");
- shader->vertex_p1 = shader_attrib_location(gl, base, "vertex_p1");
- shader->vertex_p2 = shader_attrib_location(gl, base, "vertex_p2");
- shader->uniform_thickness = shader_uniform_location(gl, base, "thickness");
- shader->uniform_transform = shader_uniform_location(gl, base, "transform");
-}
-
-static void shader_ball_load(GL *gl, ShaderBall *shader) {
- ShaderBase *base = &shader->base;
- shader_load(gl, base, "assets/ball_v.glsl", "assets/ball_f.glsl");
- shader->uniform_transform = shader_uniform_location(gl, base, "transform");
- shader->uniform_center = shader_uniform_location(gl, base, "center");
- shader->uniform_radius = shader_uniform_location(gl, base, "radius");
-}
-
-static void shaders_load(State *state) {
- GL *gl = &state->gl;
- shader_platform_load(gl, &state->shader_platform);
- shader_ball_load(gl, &state->shader_ball);
-}
-
-#if DEBUG
-static void shaders_reload_if_necessary(State *state) {
- GL *gl = &state->gl;
- if (shader_needs_reloading(&state->shader_platform.base))
- shader_platform_load(gl, &state->shader_platform);
- if (shader_needs_reloading(&state->shader_ball.base))
- shader_ball_load(gl, &state->shader_ball);
-}
-#endif
-
-// how far right could any part of this platform possibly go?
-static float platform_rightmost_x(Platform const *platform) {
- float angle;
- if (platform->rotates)
- angle = 0; // for rotating platforms, the maximum x coordinate is achieved when the platform has an angle of 0
- else
- angle = platform->angle;
- float x_past_center = platform->radius * fabsf(cosf(angle)); // width of platform to the right of the center
- v2 center;
- if (platform->moves) {
- v2 p1 = platform->move_p1, p2 = platform->move_p2;
- // pick the point with the higher x coordinate
- if (p1.x > p2.x)
- center = p1;
- else
- center = p2;
- } else {
- center = platform->center;
- }
- return center.x + x_past_center;
-}
-
-// where the ball's distance traveled should be measured from
-static float platforms_starting_line(Platform const *platforms, u32 nplatforms) {
- float rightmost_x = BALL_STARTING_X; // the starting line can't be to the left of the ball
- for (u32 i = 0; i < nplatforms; ++i) {
- float x = platform_rightmost_x(&platforms[i]);
- if (x > rightmost_x)
- rightmost_x = x;
- }
- return rightmost_x;
-}
-
-// render the given platforms
-static void platforms_render(State *state, Platform *platforms, u32 nplatforms) {
- GL *gl = &state->gl;
- ShaderPlatform *shader = &state->shader_platform;
- float platform_render_thickness = state->platform_thickness;
-
- shader_start_using(gl, &shader->base);
-
- gl->Uniform1f(shader->uniform_thickness, platform_render_thickness);
- gl->UniformMatrix4fv(shader->uniform_transform, 1, GL_FALSE, state->transform.e);
-
-
- glBegin(GL_QUADS);
- glColor3f(1,0,1);
- for (Platform *platform = platforms, *end = platform + nplatforms; platform != end; ++platform) {
- float radius = platform->radius;
- v2 center = platform->center;
- v2 thickness_r = v2_polar(platform_render_thickness, platform->angle - HALF_PIf);
- v2 platform_r = v2_polar(radius, platform->angle);
- v2 endpoint1 = v2_add(center, platform_r);
- v2 endpoint2 = v2_sub(center, platform_r);
-
- gl_rgbacolor(platform->color);
-
- #if 1
- gl->VertexAttrib2f(shader->vertex_p1, endpoint1.x, endpoint1.y);
- gl->VertexAttrib2f(shader->vertex_p2, endpoint2.x, endpoint2.y);
- v2_gl_vertex(v2_sub(endpoint1, thickness_r));
- v2_gl_vertex(v2_sub(endpoint2, thickness_r));
- v2_gl_vertex(v2_add(endpoint2, thickness_r));
- v2_gl_vertex(v2_add(endpoint1, thickness_r));
- #else
- v2_gl_vertex(endpoint1);
- v2_gl_vertex(endpoint2);
- #endif
- }
- glEnd();
- shader_stop_using(gl);
-
- if (state->building) {
- // show arrows for platforms
- glBegin(GL_LINES);
- for (Platform *platform = platforms, *end = platform + nplatforms; platform != end; ++platform) {
- gl_rgbacolor(platform->color);
- if (platform->rotates) {
- float speed = platform->rotate_speed;
- float angle = speed * 0.5f;
- if (angle) {
- // draw arc-shaped arrow to show rotation
- float theta1 = HALF_PIf;
- float theta2 = theta1 + angle;
- float dtheta = 0.03f * sgnf(angle);
- float radius = platform->radius;
- v2 last_point;
- for (float theta = theta1; angle > 0 ? (theta < theta2) : (theta > theta2); theta += dtheta) {
- v2 point = b2_to_gl(state, v2_add(platform->center, v2_polar(radius, theta)));
- if (theta != theta1) {
- v2_gl_vertex(last_point);
- v2_gl_vertex(point);
- }
- last_point = point;
- }
-
- v2 p1 = b2_to_gl(state, v2_add(platform->center, v2_polar(radius-0.2f, theta2-0.1f * sgnf(angle))));
- v2 p2 = b2_to_gl(state, v2_add(platform->center, v2_polar(radius, theta2)));
- v2 p3 = b2_to_gl(state, v2_add(platform->center, v2_polar(radius+0.2f, theta2-0.1f * sgnf(angle))));
-
- v2_gl_vertex(p1); v2_gl_vertex(p2);
- v2_gl_vertex(p2); v2_gl_vertex(p3);
- }
- }
-
- if (platform->moves) {
- // draw double-headed arrow to show back & forth motion
- v2 p1 = platform->move_p1;
- v2 p2 = platform->move_p2;
- v2 p2_to_p1 = v2_scale(v2_normalize(v2_sub(p1, p2)), platform->move_speed * 0.5f);
- v2 p1_to_p2 = v2_scale(p2_to_p1, -1);
- v2 arrowhead_a1 = v2_add(p1, v2_rotate(p1_to_p2, +0.5f));
- v2 arrowhead_b1 = v2_add(p1, v2_rotate(p1_to_p2, -0.5f));
- v2 arrowhead_a2 = v2_add(p2, v2_rotate(p2_to_p1, +0.5f));
- v2 arrowhead_b2 = v2_add(p2, v2_rotate(p2_to_p1, -0.5f));
-
- v2 p1_gl = b2_to_gl(state, p1);
- v2 p2_gl = b2_to_gl(state, p2);
- v2 aa1_gl = b2_to_gl(state, arrowhead_a1);
- v2 ab1_gl = b2_to_gl(state, arrowhead_b1);
- v2 aa2_gl = b2_to_gl(state, arrowhead_a2);
- v2 ab2_gl = b2_to_gl(state, arrowhead_b2);
-
- v2_gl_vertex(p1_gl);
- v2_gl_vertex(p2_gl);
-
- v2_gl_vertex(aa1_gl);
- v2_gl_vertex(p1_gl);
- v2_gl_vertex(p1_gl);
- v2_gl_vertex(ab1_gl);
-
- v2_gl_vertex(aa2_gl);
- v2_gl_vertex(p2_gl);
- v2_gl_vertex(p2_gl);
- v2_gl_vertex(ab2_gl);
- }
- }
- glEnd();
- }
-}
+#include "shaders.cpp"
+#include "platforms.cpp"
// render the ball
static void ball_render(State *state) {
@@ -340,83 +63,6 @@ static void ball_render(State *state) {
shader_stop_using(gl);
}
-static uintptr_t platform_to_user_data(State *state, Platform *platform) {
- return USER_DATA_PLATFORM | (uintptr_t)(platform - state->platforms);
-}
-
-static Platform *platform_from_user_data(State *state, uintptr_t user_data) {
- if ((user_data & USER_DATA_TYPE) == USER_DATA_PLATFORM) {
- uintptr_t index = user_data & USER_DATA_INDEX;
- return &state->platforms[index];
- } else {
- return NULL;
- }
-}
-
-// sets platform->body to a new Box2D body.
-static void platform_make_body(State *state, Platform *platform) {
- b2World *world = state->world;
-
- float radius = platform->radius;
-
- if (platform->moves)
- platform->center = platform->move_p1;
-
- v2 center = platform->center;
-
- b2BodyDef body_def;
- body_def.type = b2_kinematicBody;
- body_def.position.Set(center.x, center.y);
- body_def.angle = platform->angle;
- b2Body *body = world->CreateBody(&body_def);
-
- b2PolygonShape shape;
- shape.SetAsBox(radius, state->platform_thickness);
-
- b2FixtureDef fixture;
- fixture.shape = &shape;
- fixture.friction = 0.5f;
- fixture.userData.pointer = platform_to_user_data(state, platform);
-
- body->CreateFixture(&fixture);
- if (platform->moves) {
- float speed = platform->move_speed;
- v2 p1 = platform->move_p1, p2 = platform->move_p2;
- v2 direction = v2_normalize(v2_sub(p2, p1));
- v2 velocity = v2_scale(direction, speed);
- body->SetLinearVelocity(v2_to_b2(velocity));
- }
- body->SetAngularVelocity(platform->rotate_speed);
-
- platform->body = body;
-}
-
-class PlatformQueryCallback : public b2QueryCallback {
-public:
- PlatformQueryCallback(State *state_) {
- this->state = state_;
- }
- bool ReportFixture(b2Fixture *fixture) {
- platform = platform_from_user_data(state, fixture->GetUserData().pointer);
- return !platform; // if we haven't found a platform, keep going
- }
- Platform *platform = NULL;
- State *state = NULL;
-};
-
-static Platform *platform_at_mouse_pos(State *state) {
- v2 mouse_pos = state->mouse_pos;
- v2 mouse_radius = V2(0.1f, 0.1f); // you don't have to hover exactly over a platform to select it. this is the tolerance.
- v2 a = v2_sub(mouse_pos, mouse_radius);
- v2 b = v2_add(mouse_pos, mouse_radius);
- PlatformQueryCallback callback(state);
- b2AABB aabb;
- aabb.lowerBound = v2_to_b2(a);
- aabb.upperBound = v2_to_b2(b);
- state->world->QueryAABB(&callback, aabb);
- return callback.platform;
-}
-
static void simulate_time(State *state, float dt) {
float time_step = 0.01f; // fixed time step
dt += state->time_residue;
@@ -491,26 +137,6 @@ static void simulate_time(State *state, float dt) {
state->time_residue = dt;
}
-static void platform_delete(State *state, Platform *platform) {
- Platform *platforms = state->platforms;
- u32 nplatforms = state->nplatforms;
- u32 index = (u32)(platform - platforms);
-
- state->world->DestroyBody(platforms[index].body);
-
- if (index+1 < nplatforms) {
- // set this platform to last platform
- platforms[index] = platforms[nplatforms-1];
- memset(&platforms[nplatforms-1], 0, sizeof(Platform));
- platforms[index].body->GetFixtureList()->GetUserData().pointer = platform_to_user_data(state, &platforms[index]);
- } else {
- // platform is at end of array; don't need to do anything special
- memset(&platforms[index], 0, sizeof(Platform));
- }
- --state->nplatforms;
-
-}
-
static void correct_mouse_button(State *state, u8 *button) {
if (*button == MOUSE_LEFT) {
if (state->shift) {
@@ -782,6 +408,8 @@ void sim_frame(Frame *frame) {
platform_building->move_p1 = platform_building->center;
platform_building->move_speed = 1.0f;
state->setting_move_p2 = true;
+ } else {
+ state->setting_move_p2 = false;
}
}
@@ -982,13 +610,22 @@ void sim_frame(Frame *frame) {
}
- { // position of ball
+ { // cost
+ char text[64];
+ snprintf(text, sizeof text - 1, "Cost: %.1f", platforms_cost(state->platforms, state->nplatforms));
+ glColor3f(1, 1, 0.5f);
+ text_render(state, font, text, V2(-0.95f, -0.95f));
+ }
+
+ { // details in the bottom right
char text[64] = {0};
glColor3f(0.5f,0.5f,0.5f);
+ // position of ball
snprintf(text, sizeof text - 1, "(%.2f, %.2f)", ball->pos.x, ball->pos.y);
v2 size = text_get_size(state, small_font, text);
v2 pos = V2(1 - size.x, -1 + size.y);
text_render(state, small_font, text, pos);
+ // stuck time
snprintf(text, sizeof text - 1, "Last record: %.1fs ago", state->stuck_time);
size = text_get_size(state, small_font, text);
pos.x = 1 - size.x;
@@ -996,7 +633,6 @@ void sim_frame(Frame *frame) {
text_render(state, small_font, text, pos);
}
-
#if DEBUG
GLuint error = glGetError();
if (error) {