summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2020-12-11 14:47:51 -0500
committerLeo Tenenbaum <pommicket@gmail.com>2020-12-11 14:47:51 -0500
commit9a1c65dd2328d3da94cdaac6b1f170481222fabe (patch)
tree0195ec057f8a841d6402e7ead0ce9be9c51b487a
parentb9721dc1fe7975ab8015ac240981dbe426c073b3 (diff)
cost
-rw-r--r--platforms.cpp254
-rw-r--r--shaders.cpp138
-rw-r--r--sim.cpp392
3 files changed, 406 insertions, 378 deletions
diff --git a/platforms.cpp b/platforms.cpp
new file mode 100644
index 0000000..d208e50
--- /dev/null
+++ b/platforms.cpp
@@ -0,0 +1,254 @@
+// 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();
+ }
+}
+
+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 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 float platform_cost(Platform const *platform) {
+ float cost = platform->radius;
+ if (platform->moves)
+ cost += platform->move_speed;
+ if (platform->rotates)
+ cost += platform->rotate_speed;
+ return cost;
+}
+
+static float platforms_cost(Platform const *platforms, u32 nplatforms) {
+ float total_cost = 0;
+ for (u32 i = 0; i < nplatforms; ++i) {
+ total_cost += platform_cost(&platforms[i]);
+ }
+ return total_cost;
+}
diff --git a/shaders.cpp b/shaders.cpp
new file mode 100644
index 0000000..95c0bac
--- /dev/null
+++ b/shaders.cpp
@@ -0,0 +1,138 @@
+// 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
+
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) {