home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
DOS/V Power Report 1997 March
/
VPR9703A.ISO
/
VPR_DATA
/
DOGA
/
SOURCES
/
MEDIT.LZH
/
MOTION.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1996-06-13
|
15KB
|
584 lines
#include <stdio.h>
#include <math.h>
#include "matrix.h"
#include "parts.h"
#include "motion.h"
#include "bezier.h"
#include "mecha.h"
//#include "anim.h"
#include "log.h"
const double TargetDistance = 4;
MotionData::MotionData(Bezier *b)
{
if (b != NULL) {
bezier = b;
if (bezier->points == 0) {
bezier->AddPoint(bezier->point[0], bezier->point[0]);
} else if (bezier->points >=2) {
bezier->points = 1;
}
} else {
Vector v(0,0,0);
bezier = new Bezier();
bezier->AddPoint(v,v);
bezier->AddPoint(v,v);
}
speed[0] = speed[1] = 1.0;
scale[0] = scale[1] = Vector(1,1,1);
rotation[0] = (bezier->GetVector(0.0) ^ Vector(0,0,1)).GetRotation();
SetForward();
}
MotionData::MotionData(MotionData& md)
{
memcpy(this, &md, sizeof(MotionData));
bezier = new Bezier();
bezier->AddPoint(md.bezier->point[0], md.bezier->point[1]);
bezier->AddPoint(md.bezier->point[3], md.bezier->point[4]);
}
MotionData::~MotionData()
{
delete bezier;
}
static inline Matrix RotationAnyAxis(Vector& vx1, Vector& vx2)
{
double lx1 = vx1.length();
double lx2 = vx2.length();
if ((-minimumdouble < lx1 && lx1 < minimumdouble)
|| (-minimumdouble < lx2 && lx2 < minimumdouble)) {
return Matrix(1);
}
Vector vz = (1.0/lx1/lx2) * vx1 * vx2;
double l = vz.length();
if (-minimumdouble < l && l < minimumdouble) {
return Matrix(1);
}
vz *= (1.0/l);
Vector vy1 = (1.0/lx1) * vz * vx1;
Vector vy2 = (1.0/lx2) * vz * vx2;
return Matrix((1.0/lx2)*vx2, vy2, vz) * Matrix((1.0/lx1)*vx1,vy1,vz).inv();
}
static Vector RotationInterpolation(Vector& vx1, Vector& vx2, double t)
{
Vector vz = vx1 * vx2;
double l = vz.length();
double l1 = vx1 & vx2;
if (-minimumdouble < l && l < minimumdouble
&& -minimumdouble < l1 && l1 < minimumdouble) {
return vx1;
}
double theta = atan2(l,l1);
if (l < minimumdouble) {
vz = vx1 * Vector(0,1,0);
if ((l = vz.length()) < minimumdouble) {
vz = vx1 * Vector(1,0,0);
if ((l = vz.length()) < minimumdouble) {
return vx1;
}
}
}
vz *= (1.0/l);
Vector vy1 = vz * vx1;
return cos(theta * t) * vx1 + sin(theta * t) * vy1;
}
void MotionData::GetPosition(double t, Vector& pos, Vector& rot, Vector& scal)
{
if (t <= 0.0) {
pos = bezier->point[0];
rot = rotation[0];
scal = scale[0];
return;
} else if (t >= 1.0) {
pos = bezier->point[3];
scal = scale[1];
if (dirtype != DirForward) {
rot = rotation[1];
} else {
Vector v1 = bezier->GetVector(0.0);
Vector v2 = bezier->GetVector(1.0);
rot = (RotationAnyAxis(v1, v2) * Matrix::m_rot(rotation[0])).GetRotation();
}
return;
}
double b = speed[0] / 3.0;
double c = 1.0 - speed[1] / 3.0;
double lrate = 3 * b * t * (1.0-t) * (1.0-t)
+ 3 * c * t * t * (1.0-t)
+ t * t * t;
double length = bezier->TotalLength();
double rate = bezier->GetRate(lrate * length);
pos = bezier->GetPoint(rate);
if (dirtype == DirForward) {
Vector v1 = bezier->GetVector(0.0);
Vector v2 = bezier->GetVector(rate);
rot = (RotationAnyAxis(v1, v2) * Matrix::m_rot(rotation[0])).GetRotation();
} else {
Matrix& m1 = Matrix::m_rot(rotation[0]);
Matrix& m2 = Matrix::m_rot(rotation[1]);
Vector vx = RotationInterpolation(m1.v[0], m2.v[0], t);
Matrix m = RotationAnyAxis(m1.v[0], vx);
Vector vz = RotationInterpolation(m * m1.v[2], m2.v[2], t);
rot = Matrix(vx,vz).GetRotation();
}
scal = (1.0-t) * scale[0] + t * scale[1];
}
void MotionData::SetForward(void)
{
dirtype = DirForward;
Vector v1 = bezier->GetVector(0.0);
Vector v2 = bezier->GetVector(1.0);
Matrix mrot = Matrix::m_rot(rotation[0]);
rotation[0] = (v1 ^ mrot.v[2]).GetRotation();
rotation[1] = (RotationAnyAxis(v1, v2) * Matrix::m_rot(rotation[0])).GetRotation();
}
void MotionData::SetAnyAxis(Vector& v1, Vector& v2)
{
rotation[0] = (RotationAnyAxis(v1, v2) * Matrix::m_rot(rotation[0])).GetRotation();
}
Motion::Motion(Mechanic *mec, int bf, int ef, Bezier* bez)
{
if (bez == NULL) {
motiondata = NULL;
} else {
motiondata = new MotionData(bez);
}
beginframe = bf;
endframe = ef;
next = NULL;
nowframe = -1;
position = Vector(0,0,0);
rotation = Vector(0,0,0);
scale = Vector(1,1,1);
point_x = point_y = point_z = NULL;
view_x = view_y = view_z = NULL;
line_1 = line_2 = NULL;
boxflag = FALSE;
SetMech(mec);
}
Motion::Motion(Motion& m)
{
memcpy(this, &m, sizeof(Motion));
if (m.motiondata != NULL) {
motiondata = new MotionData(*m.motiondata);
}
if (mecha != NULL) {
point_x = new int[mecha->points];
point_y = new int[mecha->points];
point_z = new int[mecha->points];
view_x = new int[mecha->points];
view_y = new int[mecha->points];
view_z = new int[mecha->points];
line_1 = mecha->line_1;
line_2 = mecha->line_2;
lines = mecha->lines;
}
}
Motion::~Motion()
{
delete motiondata;
delete[] point_x;
delete[] point_y;
delete[] point_z;
delete[] view_x;
delete[] view_y;
delete[] view_z;
}
void Motion::GetPosition(int frame)
{
if (motiondata != NULL) {
double t = (double)(frame - beginframe) / (double)(endframe - beginframe);
motiondata->GetPosition(t, position, rotation, scale);
}
nowframe = frame;
}
void Motion::GetMatrix(Matrix& move, Matrix& rot, Matrix& scal, int frame)
{
if (frame >= -1 && nowframe != frame) {
GetPosition(frame);
}
move = Matrix::m_move(position);
rot = Matrix::m_rot(rotation);
scal = Matrix::m_scale(scale);
}
Matrix Motion::GetMatrix(int frame)
{
if (frame >= -1 && nowframe != frame) {
GetPosition(frame);
}
return Matrix::m_move(position).rot(rotation).scale(scale);
}
void Motion::SetRotation(Vector& rot, int pos)
{
if (motiondata == NULL) {
rotation = rot;
} else {
if (pos == 0) {
motiondata->rotation[0] = rot;
} else {
motiondata->rotation[1] = rot;
motiondata->dirtype = DirLinear;
}
GetPosition(nowframe);
}
}
void Motion::SetScale(Vector& scal, int pos)
{
if (motiondata == NULL) {
scale = scal;
} else {
if (pos == 0) {
motiondata->scale[0] = scal;
} else {
motiondata->scale[1] = scal;
}
GetPosition(nowframe);
}
}
void Motion::SetPosition(Vector& vec, int pos)
{
if (motiondata == NULL) {
position = vec;
} else {
if (pos < 0) pos = 0;
if (pos > 3) pos = 3;
motiondata->bezier->MovePoint(pos, vec);
motiondata->bezier->UpdateLength();
GetPosition(nowframe);
}
}
void Motion::CalcPoints(Matrix& m)
{
boxflag = FALSE;
if (mecha != NULL) {
for (int i = 0; i < mecha->points; ++i) {
Vector v1 = m * Vector(mecha->point_x[i], mecha->point_y[i], mecha->point_z[i]);
point_x[i] = int(v1.x);
point_y[i] = int(v1.y);
point_z[i] = int(v1.z);
}
}
}
void Motion::CalcView(Matrix& m)
{
#define CLIPZ 100.0
boxflag = FALSE;
if (mecha != NULL) {
for (int i = 0; i < mecha->points; ++i) {
Vector v1 = m * Vector(mecha->point_x[i], mecha->point_y[i], mecha->point_z[i]);
if (v1.z <= CLIPZ) {
view_z[i] = -1;
view_x[i] = 0;
view_y[i] = 0;
} else {
double vx = v1.x / v1.z;
double vy = v1.y / v1.z;
if (vx < -4096|| vx > 4096 || vy < -4096 || vy > 4096) {
view_x[i] = 0;
view_y[i] = 0;
view_z[i] = -1;
} else {
view_x[i] = (int)vx;
view_y[i] = (int)vy;
view_z[i] = (int)(32768.0 * CLIPZ / v1.z);
}
}
}
}
}
static inline void assign(int point_x[], int point_y[], int point_z[], int i, Vector& v)
{
point_x[i] = (int)v.x;
point_y[i] = (int)v.y;
point_z[i] = (int)v.z;
}
void Motion::CalcPointsBox(Matrix& m)
{
if (mecha == NULL || mecha->points < 8) {
CalcPoints(m);
} else {
boxflag = TRUE;
if (motiondata == NULL) {
assign(point_x, point_y, point_z, 0, m * Vector(mecha->maxx, mecha->maxy,mecha->maxz));
assign(point_x, point_y, point_z, 1, m * Vector(mecha->minx, mecha->maxy,mecha->maxz));
assign(point_x, point_y, point_z, 2, m * Vector(mecha->minx, mecha->miny,mecha->maxz));
assign(point_x, point_y, point_z, 3, m * Vector(mecha->maxx, mecha->miny,mecha->maxz));
assign(point_x, point_y, point_z, 4, m * Vector(mecha->maxx, mecha->maxy,mecha->minz));
assign(point_x, point_y, point_z, 5, m * Vector(mecha->minx, mecha->maxy,mecha->minz));
assign(point_x, point_y, point_z, 6, m * Vector(mecha->minx, mecha->miny,mecha->minz));
assign(point_x, point_y, point_z, 7, m * Vector(mecha->maxx, mecha->miny,mecha->minz));
} else {
assign(point_x, point_y, point_z, 0, m * Vector(mecha->maxx, 0,0));
assign(point_x, point_y, point_z, 1, m * Vector(mecha->minx, mecha->maxy,0));
assign(point_x, point_y, point_z, 2, m * Vector(mecha->minx, mecha->miny,0));
assign(point_x, point_y, point_z, 3, m * Vector(mecha->minx, 0,mecha->maxz));
assign(point_x, point_y, point_z, 4, m * Vector(mecha->minx, 0,mecha->minz));
}
}
}
static inline void assignv(int view_x[], int view_y[], int view_z[], int i, Vector& v1)
{
if (v1.z <= 1.0) {
view_z[0] = -1;
view_x[i] = 0;
view_y[i] = 0;
} else {
double vx = v1.x / v1.z;
double vy = v1.y / v1.z;
if (vx < -4096|| vx > 4096 || vy < -4096 || vy > 4096) {
view_x[i] = 0;
view_y[i] = 0;
view_z[0] = -1;
} else {
view_x[i] = (int)vx;
view_y[i] = (int)vy;
}
}
}
void Motion::CalcViewBox(Matrix& m)
{
if (mecha == NULL || mecha->points < 8) {
CalcView(m);
} else {
boxflag = TRUE;
view_z[0] = 1;
if (motiondata == NULL) {
assignv(view_x, view_y, view_z, 0, m * Vector(mecha->maxx, mecha->maxy,mecha->maxz));
assignv(view_x, view_y, view_z, 1, m * Vector(mecha->minx, mecha->maxy,mecha->maxz));
assignv(view_x, view_y, view_z, 2, m * Vector(mecha->minx, mecha->miny,mecha->maxz));
assignv(view_x, view_y, view_z, 3, m * Vector(mecha->maxx, mecha->miny,mecha->maxz));
assignv(view_x, view_y, view_z, 4, m * Vector(mecha->maxx, mecha->maxy,mecha->minz));
assignv(view_x, view_y, view_z, 5, m * Vector(mecha->minx, mecha->maxy,mecha->minz));
assignv(view_x, view_y, view_z, 6, m * Vector(mecha->minx, mecha->miny,mecha->minz));
assignv(view_x, view_y, view_z, 7, m * Vector(mecha->maxx, mecha->miny,mecha->minz));
} else {
assignv(view_x, view_y, view_z, 0, m * Vector(mecha->maxx, 0,0));
assignv(view_x, view_y, view_z, 1, m * Vector(mecha->minx, mecha->maxy,0));
assignv(view_x, view_y, view_z, 2, m * Vector(mecha->minx, mecha->miny,0));
assignv(view_x, view_y, view_z, 3, m * Vector(mecha->minx, 0,mecha->maxz));
assignv(view_x, view_y, view_z, 4, m * Vector(mecha->minx, 0,mecha->minz));
}
}
}
void Motion::SetMech(Mechanic *mec)
{
delete[] point_x;
delete[] point_y;
delete[] point_z;
delete[] view_x;
delete[] view_y;
delete[] view_z;
if (mec == NULL) {
mecha = NULL;
point_x = point_y = point_z = NULL;
view_x = view_y = view_z = NULL;
line_1 = line_2 = NULL;
lines = 0;
} else {
mecha = mec;
point_x = new int[mec->points];
point_y = new int[mec->points];
point_z = new int[mec->points];
view_x = new int[mec->points];
view_y = new int[mec->points];
view_z = new int[mec->points];
line_1 = mec->line_1;
line_2 = mec->line_2;
lines = mec->lines;
}
}
void Motion::Zoom(int begin, int end)
{
beginframe = begin;
endframe = end;
if (motiondata != NULL) {
GetPosition(nowframe);
}
}
void Motion::SetForward()
{
if (motiondata == NULL) {
return;
}
motiondata->SetForward();
GetPosition(nowframe);
}
void Motion::ChangeMove(Vector& dir)
{
if (motiondata != NULL) {
return;
}
Bezier *b = new Bezier();
b->AddPoint(position , position + (1.0/2.0) * dir);
b->AddPoint(position+dir, position + (4.0/2.0) * dir);
motiondata = new MotionData(b);
motiondata->rotation[0] = motiondata->rotation[1] = rotation;
motiondata->scale[0] = motiondata->scale[1] = scale;
}
void Motion::ChangeFix(void)
{
if (motiondata == NULL) {
return;
}
position = motiondata->bezier->point[0];
rotation = motiondata->rotation[0];
scale = motiondata->scale[0];
delete motiondata;
motiondata = NULL;
}
CameraMotion::CameraMotion(Motion *t, int frames): Motion(NULL, BEGIN, frames)
{
SetAngle(deg(60));
target = t;
line_1 = l1;
line_2 = l2;
for (int i = 0; i < CameraLines; ++i) {
line_1[i] = 0;
line_2[i] = i+1;
}
lines = CameraLines;;
point_x = new int[CameraPoints];
point_y = new int[CameraPoints];
point_z = new int[CameraPoints];
view_x = new int[CameraPoints];
view_y = new int[CameraPoints];
view_z = new int[CameraPoints];
}
CameraMotion::CameraMotion(Motion* m, Motion* t) : Motion(*m)
{
SetAngle(deg(60));
target = t;
line_1 = l1;
line_2 = l2;
for (int i = 0; i < CameraLines; ++i) {
line_1[i] = 0;
line_2[i] = i+1;
}
lines = CameraLines;;
point_x = new int[CameraPoints];
point_y = new int[CameraPoints];
point_z = new int[CameraPoints];
view_x = new int[CameraPoints];
view_y = new int[CameraPoints];
view_z = new int[CameraPoints];
}
void CameraMotion::SetAngle(double a)
{
angle = a;
pv[0] = Vector(0,0,0);
pv[1] = Vector(1.0, 0.0, 0.0);
for (int i = 2; i < CameraPoints; ++i) {
pv[i].x = TargetDistance;
}
pv[2].y = pv[3].y = TargetDistance * tan(angle/2.0);
pv[4].y = pv[5].y = -pv[2].y;
pv[2].z = pv[4].z = pv[2].y * 3 / 4;
pv[3].z = pv[5].z = -pv[2].z;
}
void CameraMotion::GetPosition(int frame)
{
if (motiondata != NULL) {
double t = (double)(frame - beginframe) / (double)(endframe - beginframe);
motiondata->GetPosition(t, position, rotation, scale);
target->GetPosition(frame);
}
Vector v = target->position - position;
rotation = (v ^ Vector(0,0,1)).GetRotation();
double d = v.length();
scale = Vector(d,d,d);
nowframe = frame;
}
void CameraMotion::CalcPoints(Matrix& m)
{
boxflag = FALSE;
for (int i = 0; i < CameraPoints; ++i) {
Vector v1 = m * pv[i];
point_x[i] = int(v1.x);
point_y[i] = int(v1.y);
point_z[i] = int(v1.z);
}
}
void CameraMotion::CalcView(Matrix& /*m*/)
{
for (int i = 0; i < CameraPoints; ++i) {
view_x[i] = view_y[i] = 0;
view_z[i] = -1;
}
}
void CameraMotion::CalcPointsBox(Matrix& m)
{
CalcPoints(m);
}
void CameraMotion::CalcViewBox(Matrix& m)
{
CalcView(m);
}