266 lines
6.9 KiB
C++
266 lines
6.9 KiB
C++
#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>() =
|
|
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>() =
|
|
ta_global_parameter::end_of_list(para_control::para_type::end_of_list);
|
|
}
|
|
}
|