diff options
author | Leo Tenenbaum <pommicket@gmail.com> | 2020-12-11 14:47:51 -0500 |
---|---|---|
committer | Leo Tenenbaum <pommicket@gmail.com> | 2020-12-11 14:47:51 -0500 |
commit | 9a1c65dd2328d3da94cdaac6b1f170481222fabe (patch) | |
tree | 0195ec057f8a841d6402e7ead0ce9be9c51b487a | |
parent | b9721dc1fe7975ab8015ac240981dbe426c073b3 (diff) |
cost
-rw-r--r-- | platforms.cpp | 254 | ||||
-rw-r--r-- | shaders.cpp | 138 | ||||
-rw-r--r-- | sim.cpp | 392 |
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 + @@ -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) { |