#include "math/float_types.hpp" #include "math/transform.hpp" #include "platform/graphics_primitive.hpp" #include "platform/font.hpp" #include "physics/particle_contact.hpp" #include "demo/bridge.hpp" #include "assert.h" namespace demo { void bridge::cable_interpolator::interp_add(float n) { const int points = particles_length / 2; interp += n; if (interp < 0) { cable_ix -= 1; assert(n < 0 && n >= -1); interp = 1.0 + n; } if (interp > 1) { cable_ix += 1; assert(n > 0 && n <= 1); interp = n; } if (cable_ix >= (points - 1)) { interp = 1.0; cable_ix = points - 2; } if (cable_ix < 0) { interp = 0; cable_ix = 0; } } mat4x4 bridge::init() { interpolator.interp = 0.0; interpolator.cable_ix = 0; // particles for (int i = 0; i < particles_length; i++) { float x = float(i / 2) * 2.0f - 5.0f; float z = float(i % 2) * 2.0f - 1.0f; particles[i].position = vec3(x, 4, z); particles[i].velocity = vec3(0, 0, 0); particles[i].damping = 0.95f; particles[i].acceleration = vec3(0, -9.81, 0); //particles[i].acceleration = vec3(0, -0.5, 0); particles[i].force_accum = vec3(0, 0, 0); } // cables for (int i = 0; i < cables_length; i++) { cables[i].particle[0] = &particles[i]; cables[i].particle[1] = &particles[i+2]; cables[i].max_length = 1.9f; cables[i].restitution = 0.5f; } // anchors for (int i = 0; i < anchors_length; i++) { anchors[i].particle = &particles[i]; float x = float(i / 2) * 2.2f - 5.5f; float z = float(i % 2) * 1.6f - 0.8f; anchors[i].anchor = vec3(x, 6, z); if (i < 6) anchors[i].max_length = float(i / 2) * 0.5f + 3.0f; else anchors[i].max_length = 5.5f - float(i / 2) * 0.5f; anchors[i].restitution = 0.5f; } // rods for (int i = 0; i < rods_length; i++) { rods[i].particle[0] = &particles[i * 2]; rods[i].particle[1] = &particles[i * 2 + 1]; rods[i].length = 2; } mat4x4 view_trans = translate(vec3(0.0, 0.0, 0.5)) * rotate_x(pi / 4) * rotate_y(pi / 12) * scale(vec3(-1, -1, 1)); return view_trans; } static int en_cables = 1; void bridge::a() //void bridge::update() { en_cables = !en_cables; printf("en cables %d\n", en_cables); } void bridge::analog(float dl, float dr, float dx, float dy) { interpolator.interp_add(dx * 0.5f); } void bridge::_update() { for (int i = 0; i < particles_length; i++) { particles[i].force_accum = vec3(0, 0, 0); if ((i / 2) == interpolator.cable_ix) { float mul = 1.0 - interpolator.interp; assert(mul >= 0.0 && mul <= 1.0); particles[i].inverse_mass = 1.0f / (1.0 + 10.0 * mul); } else if ((i / 2) == (interpolator.cable_ix + 1)) { float mul = interpolator.interp; assert(mul >= 0.0 && mul <= 1.0); particles[i].inverse_mass = 1.0f / (1.0 + 10.0 * mul); } else { particles[i].inverse_mass = 1.0f / 1.0f; } } float duration = 1.f / (60.0f * 3); for (int i = 0; i < particles_length; i++) { particles[i].integrate(duration); } // contact generators const int max_contacts = 128; static physics::particle_contact contacts[max_contacts]; int contact_ix = 0; for (int i = 0; i < anchors_length; i++) { int len = anchors[i].fill_contact(&contacts[contact_ix], 1); contact_ix += len; assert(contact_ix <= 128); } if (en_cables) { for (int i = 0; i < cables_length; i++) { int len = cables[i].fill_contact(&contacts[contact_ix], 1); contact_ix += len; assert(contact_ix <= 128); } for (int i = 0; i < rods_length; i++) { int len = rods[i].fill_contact(&contacts[contact_ix], 1); contact_ix += len; assert(contact_ix <= 128); } } static physics::particle_contact_resolver resolver; resolver.max_iterations = contact_ix * 2; resolver.resolve_contacts(contacts, contact_ix, duration); } void bridge::update() //void bridge::a() { _update(); _update(); _update(); _update(); _update(); } void bridge::draw_hud(ta_parameter_writer& writer) { const int title_length = 16; const int title_width_2 = (font::ter_u12n.hori_advance * title_length) >> 1; const int framebuffer_width_2 = framebuffer::framebuffer.px_width >> 1; const int x = framebuffer_width_2 - title_width_2; vec3 center_p = vec3(x, 5, 10); font::ter_u12n.global(writer); font::ter_u12n.draw_string(writer, center_p, "demo: bridge", 0xffffffff); } static inline vec3 lerp(const vec3& a, const vec3& b, float f) { float dx = b.x - a.x; float dy = b.y - a.y; float dz = b.z - a.z; return { a.x + dx * f, a.y + dy * f, a.z + dz * f, }; } void bridge::draw_weight(ta_parameter_writer& writer, const mat4x4& trans) { vec3 p1 = particles[(interpolator.cable_ix * 2)].position; vec3 p2 = particles[((interpolator.cable_ix + 1) * 2)].position; vec3 p = lerp(p1, p2, interpolator.interp); p.z = 0.0; const vec3 color(1.0, 0.5, 0.0); draw_cube(writer, trans * translate(p) * scale(0.3f), color); } void bridge::draw(ta_parameter_writer& writer, const mat4x4& trans) { // punch through draw_hud(writer); writer.append() = ta_global_parameter::end_of_list(para_control::para_type::end_of_list); // opaque draw_axis(writer, trans * scale(2.f)); draw_weight(writer, trans); // draw particles for (int i = 0; i < particles_length; i++) { const vec3 color(1.0, 1.0, 1.0); draw_cube(writer, trans * translate(particles[i].position) * scale(0.1f), color); } // draw cables global_polygon_intensity(writer, vec3(1.0, 1.0, 0.0)); for (int i = 0; i < cables_length; i++) { vec3 p1 = screen_transform(trans * cables[i].particle[0]->position); vec3 p2 = screen_transform(trans * cables[i].particle[1]->position); draw_line(writer, p1, p2); } // draw anchors global_polygon_intensity(writer, vec3(0.0, 1.0, 1.0)); for (int i = 0; i < anchors_length; i++) { vec3 p1 = screen_transform(trans * anchors[i].particle->position); vec3 p2 = screen_transform(trans * anchors[i].anchor); draw_line(writer, p1, p2); } // draw rods global_polygon_intensity(writer, vec3(1.0, 0.0, 1.0)); for (int i = 0; i < anchors_length; i++) { vec3 p1 = screen_transform(trans * rods[i].particle[0]->position); vec3 p2 = screen_transform(trans * rods[i].particle[1]->position); draw_line(writer, p1, p2); } writer.append() = ta_global_parameter::end_of_list(para_control::para_type::end_of_list); } }