📄 splines.cpp
字号:
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//#include "stdafx.h"
//#include "qe3.h"
#include "q_shared.hpp"
#include "splines.h"
extern "C" {
int FS_Write( const void *buffer, int len, fileHandle_t h );
int FS_ReadFile( const char *qpath, void **buffer );
void FS_FreeFile( void *buffer );
fileHandle_t FS_FOpenFileWrite( const char *filename );
void FS_FCloseFile( fileHandle_t f );
}
float Q_fabs( float f ) {
int tmp = * ( int * ) &f;
tmp &= 0x7FFFFFFF;
return * ( float * ) &tmp;
}
//#include "../shared/windings.h"
//#include "../qcommon/qcommon.h"
//#include "../sys/sys_public.h"
//#include "../game/game_entity.h"
idCameraDef splineList;
idCameraDef *g_splineList = &splineList;
idVec3_t idSplineList::zero(0,0,0);
/*
void glLabeledPoint(idVec3_t &color, idVec3_t &point, float size, const char *label) {
qglColor3fv(color);
qglPointSize(size);
qglBegin(GL_POINTS);
qglVertex3fv(point);
qglEnd();
idVec3_t v = point;
v.x += 1;
v.y += 1;
v.z += 1;
qglRasterPos3fv (v);
qglCallLists (strlen(label), GL_UNSIGNED_BYTE, label);
}
void glBox(idVec3_t &color, idVec3_t &point, float size) {
idVec3_t mins(point);
idVec3_t maxs(point);
mins[0] -= size;
mins[1] += size;
mins[2] -= size;
maxs[0] += size;
maxs[1] -= size;
maxs[2] += size;
qglColor3fv(color);
qglBegin(GL_LINE_LOOP);
qglVertex3f(mins[0],mins[1],mins[2]);
qglVertex3f(maxs[0],mins[1],mins[2]);
qglVertex3f(maxs[0],maxs[1],mins[2]);
qglVertex3f(mins[0],maxs[1],mins[2]);
qglEnd();
qglBegin(GL_LINE_LOOP);
qglVertex3f(mins[0],mins[1],maxs[2]);
qglVertex3f(maxs[0],mins[1],maxs[2]);
qglVertex3f(maxs[0],maxs[1],maxs[2]);
qglVertex3f(mins[0],maxs[1],maxs[2]);
qglEnd();
qglBegin(GL_LINES);
qglVertex3f(mins[0],mins[1],mins[2]);
qglVertex3f(mins[0],mins[1],maxs[2]);
qglVertex3f(mins[0],maxs[1],maxs[2]);
qglVertex3f(mins[0],maxs[1],mins[2]);
qglVertex3f(maxs[0],mins[1],mins[2]);
qglVertex3f(maxs[0],mins[1],maxs[2]);
qglVertex3f(maxs[0],maxs[1],maxs[2]);
qglVertex3f(maxs[0],maxs[1],mins[2]);
qglEnd();
}
void splineTest() {
//g_splineList->load("p:/doom/base/maps/test_base1.camera");
}
void splineDraw() {
//g_splineList->addToRenderer();
}
//extern void D_DebugLine( const idVec3_t &color, const idVec3_t &start, const idVec3_t &end );
void debugLine(idVec3_t &color, float x, float y, float z, float x2, float y2, float z2) {
//idVec3_t from(x, y, z);
//idVec3_t to(x2, y2, z2);
//D_DebugLine(color, from, to);
}
void idSplineList::addToRenderer() {
if (controlPoints.Num() == 0) {
return;
}
idVec3_t mins, maxs;
idVec3_t yellow(1.0, 1.0, 0);
idVec3_t white(1.0, 1.0, 1.0);
int i;
for(i = 0; i < controlPoints.Num(); i++) {
VectorCopy(*controlPoints[i], mins);
VectorCopy(mins, maxs);
mins[0] -= 8;
mins[1] += 8;
mins[2] -= 8;
maxs[0] += 8;
maxs[1] -= 8;
maxs[2] += 8;
debugLine( yellow, mins[0], mins[1], mins[2], maxs[0], mins[1], mins[2]);
debugLine( yellow, maxs[0], mins[1], mins[2], maxs[0], maxs[1], mins[2]);
debugLine( yellow, maxs[0], maxs[1], mins[2], mins[0], maxs[1], mins[2]);
debugLine( yellow, mins[0], maxs[1], mins[2], mins[0], mins[1], mins[2]);
debugLine( yellow, mins[0], mins[1], maxs[2], maxs[0], mins[1], maxs[2]);
debugLine( yellow, maxs[0], mins[1], maxs[2], maxs[0], maxs[1], maxs[2]);
debugLine( yellow, maxs[0], maxs[1], maxs[2], mins[0], maxs[1], maxs[2]);
debugLine( yellow, mins[0], maxs[1], maxs[2], mins[0], mins[1], maxs[2]);
}
int step = 0;
idVec3_t step1;
for(i = 3; i < controlPoints.Num(); i++) {
for (float tension = 0.0f; tension < 1.001f; tension += 0.1f) {
float x = 0;
float y = 0;
float z = 0;
for (int j = 0; j < 4; j++) {
x += controlPoints[i - (3 - j)]->x * calcSpline(j, tension);
y += controlPoints[i - (3 - j)]->y * calcSpline(j, tension);
z += controlPoints[i - (3 - j)]->z * calcSpline(j, tension);
}
if (step == 0) {
step1[0] = x;
step1[1] = y;
step1[2] = z;
step = 1;
} else {
debugLine( white, step1[0], step1[1], step1[2], x, y, z);
step = 0;
}
}
}
}
*/
void idSplineList::buildSpline() {
//int start = Sys_Milliseconds();
clearSpline();
for(int i = 3; i < controlPoints.Num(); i++) {
for (float tension = 0.0f; tension < 1.001f; tension += granularity) {
float x = 0;
float y = 0;
float z = 0;
for (int j = 0; j < 4; j++) {
x += controlPoints[i - (3 - j)]->x * calcSpline(j, tension);
y += controlPoints[i - (3 - j)]->y * calcSpline(j, tension);
z += controlPoints[i - (3 - j)]->z * calcSpline(j, tension);
}
splinePoints.Append(new idVec3_t(x, y, z));
}
}
dirty = false;
//Com_Printf("Spline build took %f seconds\n", (float)(Sys_Milliseconds() - start) / 1000);
}
/*
void idSplineList::draw(bool editMode) {
int i;
vec4_t yellow(1, 1, 0, 1);
if (controlPoints.Num() == 0) {
return;
}
if (dirty) {
buildSpline();
}
qglColor3fv(controlColor);
qglPointSize(5);
qglBegin(GL_POINTS);
for (i = 0; i < controlPoints.Num(); i++) {
qglVertex3fv(*controlPoints[i]);
}
qglEnd();
if (editMode) {
for(i = 0; i < controlPoints.Num(); i++) {
glBox(activeColor, *controlPoints[i], 4);
}
}
//Draw the curve
qglColor3fv(pathColor);
qglBegin(GL_LINE_STRIP);
int count = splinePoints.Num();
for (i = 0; i < count; i++) {
qglVertex3fv(*splinePoints[i]);
}
qglEnd();
if (editMode) {
qglColor3fv(segmentColor);
qglPointSize(3);
qglBegin(GL_POINTS);
for (i = 0; i < count; i++) {
qglVertex3fv(*splinePoints[i]);
}
qglEnd();
}
if (count > 0) {
//assert(activeSegment >=0 && activeSegment < count);
if (activeSegment >=0 && activeSegment < count) {
glBox(activeColor, *splinePoints[activeSegment], 6);
glBox(yellow, *splinePoints[activeSegment], 8);
}
}
}
*/
float idSplineList::totalDistance() {
if (controlPoints.Num() == 0) {
return 0.0;
}
if (dirty) {
buildSpline();
}
float dist = 0.0;
idVec3_t temp;
int count = splinePoints.Num();
for(int i = 1; i < count; i++) {
temp = *splinePoints[i-1];
temp -= *splinePoints[i];
dist += temp.Length();
}
return dist;
}
void idSplineList::initPosition(long bt, long totalTime) {
if (dirty) {
buildSpline();
}
if (splinePoints.Num() == 0) {
return;
}
baseTime = bt;
time = totalTime;
// calc distance to travel ( this will soon be broken into time segments )
splineTime.Clear();
splineTime.Append(bt);
double dist = totalDistance();
double distSoFar = 0.0;
idVec3_t temp;
int count = splinePoints.Num();
//for(int i = 2; i < count - 1; i++) {
for(int i = 1; i < count; i++) {
temp = *splinePoints[i-1];
temp -= *splinePoints[i];
distSoFar += temp.Length();
double percent = distSoFar / dist;
percent *= totalTime;
splineTime.Append(percent + bt);
}
assert(splineTime.Num() == splinePoints.Num());
activeSegment = 0;
}
float idSplineList::calcSpline(int step, float tension) {
switch(step) {
case 0: return (pow(1 - tension, 3)) / 6;
case 1: return (3 * pow(tension, 3) - 6 * pow(tension, 2) + 4) / 6;
case 2: return (-3 * pow(tension, 3) + 3 * pow(tension, 2) + 3 * tension + 1) / 6;
case 3: return pow(tension, 3) / 6;
}
return 0.0;
}
void idSplineList::updateSelection(const idVec3_t &move) {
if (selected) {
dirty = true;
VectorAdd(*selected, move, *selected);
}
}
void idSplineList::setSelectedPoint(idVec3_t *p) {
if (p) {
p->Snap();
for(int i = 0; i < controlPoints.Num(); i++) {
if (*p == *controlPoints[i]) {
selected = controlPoints[i];
}
}
} else {
selected = NULL;
}
}
const idVec3_t *idSplineList::getPosition(long t) {
static idVec3_t interpolatedPos;
//static long lastTime = -1;
int count = splineTime.Num();
if (count == 0) {
return &zero;
}
Com_Printf("Time: %d\n", t);
assert(splineTime.Num() == splinePoints.Num());
while (activeSegment < count) {
if (splineTime[activeSegment] >= t) {
if (activeSegment > 0 && activeSegment < count - 1) {
double timeHi = splineTime[activeSegment + 1];
double timeLo = splineTime[activeSegment - 1];
double percent = (timeHi - t) / (timeHi - timeLo);
// pick two bounding points
idVec3_t v1 = *splinePoints[activeSegment-1];
idVec3_t v2 = *splinePoints[activeSegment+1];
v2 *= (1.0 - percent);
v1 *= percent;
v2 += v1;
interpolatedPos = v2;
return &interpolatedPos;
}
return splinePoints[activeSegment];
} else {
activeSegment++;
}
}
return splinePoints[count-1];
}
void idSplineList::parse(const char *(*text) ) {
const char *token;
//Com_MatchToken( text, "{" );
do {
token = Com_Parse( text );
if ( !token[0] ) {
break;
}
if ( !Q_stricmp (token, "}") ) {
break;
}
do {
// if token is not a brace, it is a key for a key/value pair
if ( !token[0] || !Q_stricmp (token, "(") || !Q_stricmp(token, "}")) {
break;
}
Com_UngetToken();
idStr key = Com_ParseOnLine(text);
const char *token = Com_Parse(text);
if (Q_stricmp(key.c_str(), "granularity") == 0) {
granularity = atof(token);
} else if (Q_stricmp(key.c_str(), "name") == 0) {
name = token;
}
token = Com_Parse(text);
} while (1);
if ( !Q_stricmp (token, "}") ) {
break;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -