MuckyFoot-UrbanChaos/fallen/Source/sm.cpp
2017-05-20 11:14:17 +10:00

503 lines
7.9 KiB
C++

//
// Sphere-matter.
//
#include "game.h"
#include <MFStdLib.h>
#include "pap.h"
#include "sm.h"
#include "inline.h"
#ifndef PSX
#include "c:\fallen\ddengine\headers\aeng.h"
#else
#include "c:\fallen\psxeng\headers\psxeng.h"
#endif
//
// The spheres that make up an object.
//
typedef struct
{
SLONG x;
SLONG y;
SLONG z;
SLONG dx; // 8-bit fixed point
SLONG dy;
SLONG dz;
SLONG radius;
SLONG mass;
} SM_Sphere;
#define SM_MAX_SPHERES 1024
SM_Sphere SM_sphere[SM_MAX_SPHERES];
SLONG SM_sphere_upto;
//
// The elastic connections between spheres.
//
typedef struct
{
UWORD sphere1;
UWORD sphere2;
SLONG dist; // Distance squared...
} SM_Link;
#define SM_MAX_LINKS 1024
SM_Link SM_link[SM_MAX_LINKS];
SLONG SM_link_upto;
//
// An object.
//
typedef struct
{
UWORD sphere_index;
UWORD sphere_num;
UWORD link_index;
UWORD link_num;
SLONG jellyness;
SLONG resolution;
SLONG density;
} SM_Object;
#define SM_MAX_OBJECTS 16
SM_Object SM_object[SM_MAX_OBJECTS];
SLONG SM_object_upto;
void SM_init(void)
{
SM_sphere_upto = 0;
SM_link_upto = 0;
SM_object_upto = 0;
}
//
// The minimum and maximum ranges of the cube variables.
//
#define SM_CUBE_RES_MIN 2
#define SM_CUBE_RES_MAX 5
#define SM_CUBE_DENSITY_MIN 0x01000
#define SM_CUBE_DENSITY_MAX 0x10000
#define SM_CUBE_JELLYNESS_MIN 0x10000
#define SM_CUBE_JELLYNESS_MAX 0x00400
void SM_create_cube(
SLONG cx1, SLONG cy1, SLONG cz1,
SLONG cx2, SLONG cy2, SLONG cz2,
SLONG amount_resolution, // 0 - 256
SLONG amount_density, // 0 - 256
SLONG amount_jellyness) // 0 - 256
{
SLONG i;
SLONG j;
SLONG k;
SLONG i2;
SLONG j2;
SLONG k2;
SLONG di;
SLONG dj;
SLONG dk;
SLONG sx;
SLONG sy;
SLONG sz;
SLONG sx2;
SLONG sy2;
SLONG sz2;
SLONG dsx;
SLONG dsy;
SLONG dsz;
SLONG dx;
SLONG dy;
SLONG dz;
SLONG dist;
SLONG index1;
SLONG index2;
SLONG radius;
SLONG volume;
SLONG mass;
SM_Object *so;
SM_Sphere *ss;
SM_Link *sl;
//
// We work in 16-bit fixed point, not 8-bit.
//
cx1 <<= 8;
cy1 <<= 8;
cz1 <<= 8;
cx2 <<= 8;
cy2 <<= 8;
cz2 <<= 8;
//
// The values we use to create the object.
//
SLONG resolution = SM_CUBE_RES_MIN + (amount_resolution * (SM_CUBE_RES_MAX - SM_CUBE_RES_MIN ) >> 8);
SLONG density = SM_CUBE_DENSITY_MIN + (amount_density * (SM_CUBE_DENSITY_MAX - SM_CUBE_DENSITY_MIN ) >> 8);
SLONG jellyness = SM_CUBE_JELLYNESS_MIN + (amount_jellyness * (SM_CUBE_JELLYNESS_MAX - SM_CUBE_JELLYNESS_MIN) >> 8);
resolution = amount_resolution;
density = amount_density;
jellyness = amount_jellyness;
//
// The mass of the object is divided evenly among all the spheres.
//
dx = cx2 - cx1;
dy = cy2 - cy1;
dz = cz2 - cz1;
volume = MUL64(MUL64(dx, dy), dz);
mass = MUL64(volume, density);
mass /= resolution * resolution * resolution;
dx = (cx2 - cx1) / resolution;
dy = (cy2 - cy1) / resolution;
dz = (cz2 - cz1) / resolution;
radius = QDIST3(abs(dx >> 1),abs(dy >> 1), abs(dz >> 1));
//
// Create the object.
//
ASSERT(WITHIN(SM_object_upto, 0, SM_MAX_OBJECTS - 1));
so = &SM_object[SM_object_upto++];
so->sphere_index = SM_sphere_upto;
so->sphere_num = 0;
so->link_index = SM_link_upto;
so->link_num = 0;
so->jellyness = jellyness;
so->resolution = resolution;
so->density = density;
//
// Add the spheres and links to the object.
//
for (i = 0; i < resolution; i++)
for (j = 0; j < resolution; j++)
for (k = 0; k < resolution; k++)
{
//
// The position of this sphere.
//
sx = cx1 + i * dx + (dx >> 1);
sy = cy1 + j * dy + (dy >> 1);
sz = cz1 + k * dx + (dx >> 1);
//
// Create a sphere.
//
ASSERT(WITHIN(SM_sphere_upto, 0, SM_MAX_SPHERES - 1));
ss = &SM_sphere[SM_sphere_upto++];
ss->x = sx;
ss->y = sy;
ss->z = sz;
ss->dx = 0;
ss->dy = 0;
ss->dz = 0;
ss->radius = radius;
ss->mass = mass;
so->sphere_num += 1;
//
// Adds links from this sphere to spheres with a higher index.
//
index1 = k + (j * resolution) + (i * resolution * resolution);
for (di = 0; di < 2; di++)
for (dj = 0; dj < 2; dj++)
for (dk = 0; dk < 2; dk++)
{
i2 = i + di;
j2 = j + dj;
k2 = k + dk;
if (i2 >= resolution ||
j2 >= resolution ||
k2 >= resolution)
{
continue;
}
index2 = k2 + (j2 * resolution) + (i2 * resolution * resolution);
sx2 = cx1 + i2 * dx + (dx >> 1);
sy2 = cy1 + j2 * dy + (dy >> 1);
sz2 = cz1 + k2 * dx + (dx >> 1);
dsx = sx2 - sx;
dsy = sy2 - sy;
dsz = sz2 - sz;
dist = MUL64(dsx, dsx);
dist += MUL64(dsy, dsy);
dist += MUL64(dsz, dsz);
//
// Create the new link.
//
ASSERT(WITHIN(SM_link_upto, 0, SM_MAX_LINKS - 1));
sl = &SM_link[SM_link_upto++];
sl->sphere1 = index1;
sl->sphere2 = index2;
sl->dist = dist;
so->link_num += 1;
}
}
}
void SM_process()
{
SLONG i;
SLONG j;
SLONG height;
SLONG ax;
SLONG ay;
SLONG az;
SLONG dx;
SLONG dy;
SLONG dz;
SLONG dist;
SLONG ddist;
SLONG force;
SLONG accel;
SM_Object *so;
SM_Sphere *ss;
SM_Sphere *ss1;
SM_Sphere *ss2;
SM_Link *sl;
//
// Process all the spheres.
//
for (i = 0; i < SM_sphere_upto; i++)
{
ss = &SM_sphere[i];
//
// Gravity.
//
#define SM_GRAVITY (-0x200)
ss->dy += SM_GRAVITY;
//
// Movement.
//
ss->x += ss->dx / 256;
ss->y += ss->dy / 256;
ss->z += ss->dz / 256;
//
// Collision with the ground.
//
height = PAP_calc_height_at(ss->x >> 8, ss->z >> 8) << 8;
if (ss->y - ss->radius < height)
{
ss->y = ss->radius + height;
ss->dy = -abs(ss->dy);
ss->dy -= ss->dy >> 9;
ss->dx /= 2;
ss->dz /= 2;
}
//
// Friction.
//
ss->dx -= ss->dx / 256;
ss->dy -= ss->dy / 256;
ss->dz -= ss->dz / 256;
ss->dx -= ss->dx / 512;
ss->dy -= ss->dy / 512;
ss->dz -= ss->dz / 512;
ss->dx -= SIGN(ss->dx);
ss->dy -= SIGN(ss->dy);
ss->dz -= SIGN(ss->dz);
}
//
// Process each object.
//
for (i = 0; i < SM_object_upto; i++)
{
so = &SM_object[i];
//
// Process all the links.
//
for (j = 0; j < SM_link_upto; j++)
{
sl = &SM_link[j];
ASSERT(WITHIN(sl->sphere1, 0, SM_sphere_upto - 1));
ASSERT(WITHIN(sl->sphere2, 0, SM_sphere_upto - 1));
ss1 = &SM_sphere[sl->sphere1];
ss2 = &SM_sphere[sl->sphere2];
dx = ss2->x - ss1->x;
dy = ss2->y - ss1->y;
dz = ss2->z - ss1->z;
dist = MUL64(dx,dx);
dist += MUL64(dy,dy);
dist += MUL64(dz,dz);
ddist = dist - sl->dist;
if (ddist)
{
force = MUL64(ddist, so->jellyness);
//
// Equal and opposite force on both spheres.
//
accel = DIV64(force, ss1->mass);
ss1->dx += MUL64(dx, accel);
ss1->dy += MUL64(dy, accel);
ss1->dz += MUL64(dz, accel);
accel = DIV64(force, ss2->mass);
ss2->dx -= MUL64(dx, accel);
ss2->dy -= MUL64(dy, accel);
ss2->dz -= MUL64(dz, accel);
}
}
}
if (Keys[KB_P5])
{
SM_sphere[8].dy -= SM_GRAVITY * 50;
}
}
//
// Getting the spheres.
//
SLONG SM_get_upto;
SM_Info SM_get_info;
void SM_get_start()
{
SM_get_upto = 0;
if (ControlFlag)
{
SLONG i;
SM_Link *sl;
SM_Sphere *ss1;
SM_Sphere *ss2;
//
// Draw all the links.
//
for (i = 0; i < SM_link_upto; i++)
{
sl = &SM_link[i];
ASSERT(WITHIN(sl->sphere1, 0, SM_sphere_upto - 1));
ASSERT(WITHIN(sl->sphere2, 0, SM_sphere_upto - 1));
ss1 = &SM_sphere[sl->sphere1];
ss2 = &SM_sphere[sl->sphere2];
AENG_world_line(
ss1->x >> 8, ss1->y >> 8, ss1->z >> 8, 16, 0x00ff0000,
ss2->x >> 8, ss2->y >> 8, ss2->z >> 8, 1, 0x0000ff00,
TRUE);
}
}
}
SM_Info *SM_get_next()
{
SM_Sphere *ss;
if (!WITHIN(SM_get_upto, 0, SM_sphere_upto - 1))
{
return NULL;
}
ss = &SM_sphere[SM_get_upto++];
SM_get_info.x = ss->x >> 8;
SM_get_info.y = ss->y >> 8;
SM_get_info.z = ss->z >> 8;
SM_get_info.radius = ss->radius >> 8;
SM_get_info.colour = 123456789 * SM_get_upto + 3141592653;
return &SM_get_info;
}