home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 2001 February
/
Chip_2001-02_cd1.bin
/
bonus
/
demos
/
CS
/
exp
/
SOURCES
/
GLENGINE
/
api3ds.cpp
next >
Wrap
C/C++ Source or Header
|
2000-08-20
|
68KB
|
2,429 lines
/*
* 3DS API
*
* Includes the support needed to render 3D Studio r4 mesh files with
* OpenGL. Depends on the ObjGL2 class hierarchy.
*/
#include <io.h>
#include <stdio.h>
#include <malloc.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include "api3ds.h"
#include "macros.h"
#include <zlib.h>
#define API3DS_TEXT_OUT 1
bool Texture3DS::voodoo = false;
bool Texture3DS::lowtextures = false;
char* Loader3DS::buffer = 0;
const char* getlastext(const char* s) {
const char* lastext = 0;
char c;
while(c=*s, c) {
if(c=='.')
lastext = s+1;
s++;
}
return lastext;
}
template <class __type> inline Vector3<__type>
Normalize (const Vector3<__type>& V) {
__type len = __type(1.0/sqrt(V.x*V.x + V.y*V.y + V.z*V.z));
return Vector3<__type> (V.x*len, V.y*len, V.z*len);
}
template <class __type> inline Vector3<__type>
CrossProduct (const Vector3<__type>& u, const Vector3<__type>& v) {
return Vector3<__type> (u.y*v.z - u.z*v.y,
v.x*u.z - u.x*v.z,
u.x*v.y - u.y*v.x);
}
template <class __type> inline __type
VectorLength(const Vector3<__type>& u) {
return (__type)sqrt(u.x*u.x + u.y*u.y + u.z*u.z);
}
template <class __type> inline const __type&
Minimum(const __type& a, const __type& b) {
return (a<b ? a : b);
}
void Texture3DS::GL ()
{
if(Name()==0) {
glBindTexture(GL_TEXTURE_2D, 0);
return;
}
if(texture==0)
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
if(altered) {
altered = false;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_s);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_t);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter);
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_PRIORITY, priority);
}
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, env_mode);
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, env_color);
if(!transferred) {
Image img;
String S = String("DATA\\") + Name();
if (!img.Load(S())) img.Load(Name()());
/*
String S(Name());
FILE* file;
file = fopen(S(), "rb");
if(!file) {
S = String("data\\")+S;
file = fopen(S(), "rb");
if(!file) {
transferred = true;
return;
}
}
fclose(file);
*/
if(lowtextures) {
img.Scale(img.width()>>1, img.height()>>1);
}
if(voodoo) {
int nwidth = img.width()>256 ? 256 : img.width();
int nheight = img.height()>256 ? 256 : img.height();
if(nwidth!=img.width()||nheight!=img.height())
img.Scale(nwidth, nheight);
}
switch(img.format()) {
case OGL_IMAGE_RGB888:
img.FlipVertical();
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8,
img.width(), img.height(), 0,
GL_RGB, GL_UNSIGNED_BYTE, img.data());
if (API3DS_TEXT_OUT) cout << "texture " << Name() << " transferred" << endl;
break;
case OGL_IMAGE_RGBA8888:
img.FlipVertical();
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8,
img.width(), img.height(), 0,
GL_RGBA, GL_UNSIGNED_BYTE, img.data());
if (API3DS_TEXT_OUT) cout << "texture " << Name() << " transferred" << endl;
break;
default:
if (API3DS_TEXT_OUT) cout << "Bad image type " << img.format() << endl;
break;
}
transferred = true;
}
}
void Textures3DS::GL () {
__entity_list.rewind();
for(int i=__entity_list.size(); i; i--) {
(*__entity_list)->GL();
++__entity_list;
}
}
Texture3DS* Textures3DS::GetOrCreate (const char* s) {
Texture3DS* p = Get(s);
if(!p) {
p = new Texture3DS;
p->Name(s);
p->MinFilter(GL_LINEAR);
p->MagFilter(GL_LINEAR);
Add(p);
}
return p;
}
Material3DS::Material3DS () {
Reset();
}
void Material3DS::Reset () {
ambient[0] = ambient[1] = ambient[2] = 0.0F; ambient[3] = 1.0F;
diffuse[0] = diffuse[1] = diffuse[2] = 1.0F; diffuse[3] = 1.0F;
specular[0] = specular[1] = specular[2] = 0.0F; specular[3] = 1.0F;
shininess_percent = 0;
shininess_strenght_percent = 0;
transparency_percent = 0;
transparency_falloff_percent = 0;
self_illumination_percent = 0;
reflect_blur_percent = 0;
texture1 = 0;
texture2 = 0;
opacity_map = 0;
bump_map = 0;
specular_map = 0;
shininess_map = 0;
self_illum_map = 0;
reflection_map = 0;
}
void Material3DS::GL(GLenum face = GL_FRONT_AND_BACK)
{
diffuse[3] = 0.6F; // (GLfloat)transparency_percent/100.0
glMaterialfv(face, GL_AMBIENT, ambient);
glMaterialfv(face, GL_DIFFUSE, diffuse);
glMaterialfv(face, GL_SPECULAR, specular);
// glMaterialf(face, GL_SHININESS, (GLfloat) shininess_percent);
glShadeModel(GL_SMOOTH);
glEnable(GL_DEPTH_TEST);
if(texture1==0) {
glDisable(GL_TEXTURE_2D);
}
else {
glEnable(GL_TEXTURE_2D);
texture1->GL();
}
}
void Material3DS::Ambient (GLfloat r, GLfloat g, GLfloat b) {
SetVector4(ambient, r, g, b, 1.0F);
}
void Material3DS::Diffuse (GLfloat r, GLfloat g, GLfloat b) {
SetVector4(diffuse, r, g, b, 1.0F);
}
void Material3DS::Specular (GLfloat r, GLfloat g, GLfloat b) {
SetVector4(specular, r, g, b, 1.0F);
}
void Material3DS::Ambient (GLfloat* v) {
SetVector4(ambient, *v, *(v+1), *(v+2), 1.0F);
}
void Material3DS::Diffuse (GLfloat* v) {
SetVector4(diffuse, *v, *(v+1), *(v+2), 1.0F);
}
void Material3DS::Specular (GLfloat* v) {
SetVector4(specular, *v, *(v+1), *(v+2), 1.0F);
}
void Material3DS::Ambient (GLubyte r, GLubyte g, GLubyte b) {
SetVector4(ambient, r, g, b, 255);
}
void Material3DS::Diffuse (GLubyte r, GLubyte g, GLubyte b) {
SetVector4(diffuse, r, g, b, 255);
}
void Material3DS::Specular (GLubyte r, GLubyte g, GLubyte b) {
SetVector4(specular, r, g, b, 255);
}
void Material3DS::Ambient (GLubyte* v) {
SetVector4(ambient, *v, *(v+1), *(v+2), 255);
}
void Material3DS::Diffuse (GLubyte* v) {
SetVector4(diffuse, *v, *(v+1), *(v+2), 255);
}
void Material3DS::Specular (GLubyte* v) {
SetVector4(specular, *v, *(v+1), *(v+2), 255);
}
void Material3DS::Shininess (GLint i) {
shininess_percent = i;
}
void Material3DS::ShininessStrenght (GLint i) {
shininess_strenght_percent = i;
}
void Material3DS::Transparency (GLint i) {
transparency_percent = i;
}
void Material3DS::TransparencyFalloff (GLint i) {
transparency_falloff_percent = i;
}
void Material3DS::SelfIllumination (GLint i) {
self_illumination_percent = i;
}
void Material3DS::ReflectBlur (GLint i) {
reflect_blur_percent = i;
}
void Material3DS::Texture1 (Texture3DS* t) {
texture1 = t;
}
void Material3DS::Texture2 (Texture3DS* t) {
texture2 = t;
}
void Material3DS::OpacityMap (Texture3DS* t) {
opacity_map = t;
}
void Material3DS::BumpMap (Texture3DS* t) {
bump_map = t;
}
void Material3DS::SpecularMap (Texture3DS* t) {
specular_map = t;
}
void Material3DS::ShininessMap (Texture3DS* t) {
shininess_map = t;
}
void Material3DS::SelfIlluminationMap (Texture3DS* t) {
self_illum_map = t;
}
void Material3DS::ReflectionMap (Texture3DS* t) {
reflection_map = t;
}
const GLfloat* Material3DS::Ambient () {
return ambient;
}
const GLfloat* Material3DS::Diffuse () {
return diffuse;
}
const GLfloat* Material3DS::Specular () {
return specular;
}
GLint Material3DS::Shininess () {
return shininess_percent;
}
GLint Material3DS::ShininessStrenght () {
return shininess_strenght_percent;
}
GLint Material3DS::Transparency () {
return transparency_percent;
}
GLint Material3DS::TransparencyFalloff () {
return transparency_falloff_percent;
}
GLint Material3DS::SelfIllumination () {
return self_illumination_percent;
}
GLint Material3DS::ReflectBlur () {
return reflect_blur_percent;
}
Texture3DS* Material3DS::Texture1 () {
return texture1;
}
Texture3DS* Material3DS::Texture2 () {
return texture2;
}
Texture3DS* Material3DS::OpacityMap () {
return opacity_map;
}
Texture3DS* Material3DS::BumpMap () {
return bump_map;
}
Texture3DS* Material3DS::SpecularMap () {
return specular_map;
}
Texture3DS* Material3DS::ShininessMap () {
return shininess_map;
}
Texture3DS* Material3DS::SelfIlluminationMap () {
return self_illum_map;
}
Texture3DS* Material3DS::ReflectionMap () {
return reflection_map;
}
OmniLight3DS::OmniLight3DS () {
Reset();
}
void OmniLight3DS::Reset ()
{
Diffuse(0.0F, 0.0F, 0.0F);
Position(0.0F, 0.0F, 0.0F);
constant_attenuation = 1.0F;
linear_attenuation = 0.0F;
quadratic_attenuation = 0.0F;
}
void OmniLight3DS::GL (GLenum light, double time = 0.0)
{
GLfloat a[4];
a[3] = 1.0F;
Vector3f v = diffuse.Val(time);
v.Unpack(a);
glLightfv(light, GL_DIFFUSE, a);
v = position.Val(time);
v.Unpack(a);
glLightfv(light, GL_POSITION, a);
a[0] = a[1] = a[2] = 0.0F;
glLightfv(light, GL_SPECULAR, a);
glLightfv(light, GL_AMBIENT, a);
glLightf(light, GL_CONSTANT_ATTENUATION, constant_attenuation);
glLightf(light, GL_LINEAR_ATTENUATION, linear_attenuation);
glLightf(light, GL_QUADRATIC_ATTENUATION, quadratic_attenuation);
}
void OmniLight3DS::Diffuse (GLfloat r, GLfloat g, GLfloat b) {
diffuse(Vector3f(r, g, b));
}
void OmniLight3DS::Diffuse (GLubyte r, GLubyte g, GLubyte b) {
diffuse(Vector3f(UBYTE_TO_FLOAT(r), UBYTE_TO_FLOAT(g), UBYTE_TO_FLOAT(b)));
}
void OmniLight3DS::Diffuse (const Vector3f& V) {
diffuse(V);
}
void OmniLight3DS::Diffuse (Dynamic<Vector3f, GLfloat> *ptr, bool strong = false) {
diffuse(ptr, strong);
}
void OmniLight3DS::Position (GLfloat x, GLfloat y, GLfloat z) {
position(Vector3f(x, y, z));
}
void OmniLight3DS::Position (const Vector3f& V) {
position(V);
}
void OmniLight3DS::Position (Dynamic<Vector3f, GLfloat> *ptr, bool strong = false) {
position(ptr, strong);
}
void OmniLight3DS::ConstantAttenuation (GLfloat f) {
constant_attenuation = f;
}
void OmniLight3DS::LinearAttenuation (GLfloat f) {
linear_attenuation = f;
}
void OmniLight3DS::QuadraticAttenuation (GLfloat f) {
quadratic_attenuation = f;
}
Vector3f OmniLight3DS::Position (double time = 0.0) {
return position.Val(time);
}
Vector3f OmniLight3DS::Diffuse (double time = 0.0) {
return diffuse.Val(time);
}
GLfloat OmniLight3DS::ConstantAttenuation () {
return constant_attenuation;
}
GLfloat OmniLight3DS::LinearAttenuation () {
return linear_attenuation;
}
GLfloat OmniLight3DS::QuadraticAttenuation () {
return quadratic_attenuation;
}
Object3DS::~Object3DS () {
delete[] vertices;
facegroups.rewind();
for(int i=facegroups.size(); i; i--) {
delete (*facegroups).indices;
++facegroups;
}
}
BoundingBox BoundVertices (int n, Vertex3DS* p) {
BoundingBox B;
GLfloat mx, my, mz, Mx, My, Mz, a1, a2;
mx = Mx = p->x;
my = My = p->y;
mz = Mz = p->z;
Vertex3DS* p1 = p+1;
for(int i=n-1; i; i--, p++, p1++)
{
a1 = p->x;
a2 = p1->x;
if(a1<=a2) {
if(a1<mx) mx=a1;
if(a2>Mx) Mx=a2;
}
else {
if(a2<mx) mx=a2;
if(a1>Mx) Mx=a1;
}
a1 = p->y;
a2 = p1->y;
if(a1<=a2) {
if(a1<my) my=a1;
if(a2>My) My=a2;
}
else {
if(a2<my) my=a2;
if(a1>My) My=a1;
}
a1 = p->z;
a2 = p1->z;
if(a1<=a2) {
if(a1<mz) mz=a1;
if(a2>Mz) Mz=a2;
}
else {
if(a2<mz) mz=a2;
if(a1>Mz) Mz=a1;
}
}
B.Corner1(mx, my, mz);
B.Corner2(Mx, My, Mz);
return B;
}
/*
void Object3DS::Rays (Vector3f C, Vector3f S, GLfloat I) {
glDisable(GL_LIGHTING);
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_ZERO);
glDisable(GL_CULL_FACE);
glBlendFunc(GL_ONE, GL_ONE);
glEnable(GL_BLEND);
glDisable(GL_TEXTURE_2D);
Vector3f V1, V2, V3, V4;
glBegin(GL_QUADS);
Edge3DS* p = edges;
Vertex3DS* v1;
Vertex3DS* v2;
p = edges;
for(int z=0; z<numedges; z++, p++) {
v1 = evertices + p->a;
v2 = evertices + p->b;
V1 = Vector3f(v1->x-C.x, v1->y-C.y, v1->z-C.z);
GLfloat a1 = V1.x*p->N1_x + V1.y*p->N1_y + V1.z*p->N1_z;
GLfloat a2 = V1.x*p->N2_x + V1.y*p->N2_y + V1.z*p->N2_z;
if((a1*a2)<0.0) {
V1 = Vector3f(v1->x-S.x, v1->y-S.y, v1->z-S.z);
V2 = Vector3f(v2->x-S.x, v2->y-S.y, v2->z-S.z);
GLfloat len1 = VectorLength(V1);
GLfloat len2 = VectorLength(V2);
GLfloat r1 = 1.0/len1;
GLfloat r2 = 1.0/len2;
a1*=r1;
a2*=r2;
GLfloat obrysovost = Minimum(fabs(a1), fabs(a2));
#define PI2 (PI/2)
obrysovost=sin(sin(sin(sin(obrysovost*PI2)*PI2)*PI2)*PI2);
GLfloat i1 = (1.0-len1/I)*obrysovost;
GLfloat i2 = (1.0-len2/I)*obrysovost;
if(i1<0.0||i2<0.0) continue;
len1 = I*r1;
len2 = I*r2;
V1 *= len1;
V2 *= len2;
V1 += S;
V2 += S;
glColor3f(i1, i1, i1);
glVertex3f(v1->x, v1->y, v1->z);
glColor3f(i2, i2, i2);
glVertex3f(v2->x, v2->y, v2->z);
glColor3f(0.0F, 0.0F, 0.0F);
glVertex3f(V2.x, V2.y, V2.z);
glVertex3f(V1.x, V1.y, V1.z);
}
}
glEnd();
glDisable(GL_CULL_FACE);
glDisable(GL_BLEND);
glDepthMask(GL_ONE);
glEnable(GL_LIGHTING);
glEnable(GL_DEPTH_TEST);
}
*/
void Object3DS::Rays (Vector3f C, Vector3f S, GLfloat I, GLenum sfactor, GLenum dfactor) {
glDisable(GL_LIGHTING);
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_ZERO);
glDisable(GL_CULL_FACE);
glBlendFunc(sfactor, dfactor);
glEnable(GL_BLEND);
glDisable(GL_TEXTURE_2D);
Vector3f V1, V2, V3, V4;
glBegin(GL_QUADS);
Edge3DS* p = edges;
Vertex3DS* v1;
Vertex3DS* v2;
p = edges;
for(int z=0; z<numedges; z++, p++) {
v1 = evertices + p->a;
v2 = evertices + p->b;
V1 = Vector3f(v1->x-C.x, v1->y-C.y, v1->z-C.z);
GLfloat a1 = V1.x*p->N1_x + V1.y*p->N1_y + V1.z*p->N1_z;
GLfloat a2 = V1.x*p->N2_x + V1.y*p->N2_y + V1.z*p->N2_z;
if((a1*a2)<0.0) {
V2 = Vector3f(v2->x-C.x, v2->y-C.y, v2->z-C.z);
V3 = Normalize((V1+V2)*0.5F);
V4 = Normalize(C-S);
GLfloat d34= Dot(V3, V4);
V1 = Vector3f(v1->x-S.x, v1->y-S.y, v1->z-S.z);
V2 = Vector3f(v2->x-S.x, v2->y-S.y, v2->z-S.z);
GLfloat len1 = VectorLength(V1);
GLfloat len2 = VectorLength(V2);
GLfloat r1 = 1.0/len1;
GLfloat r2 = 1.0/len2;
a1*=r1;
a2*=r2;
#define PI2 (PI/2)
GLfloat obrysovost = Minimum(fabs(a1), fabs(a2));
obrysovost=sin(sin(sin(sin(obrysovost*PI2)*PI2)*PI2)*PI2);
obrysovost*=sin(sin(sin(sin(sin(sin(cos(fabs(d34)*PI2)*PI2)*PI2)*PI2)*PI2)*PI2)*PI2);
GLfloat i1 = (1.0-len1/I)*obrysovost;
GLfloat i2 = (1.0-len2/I)*obrysovost;
if(i1<0.0||i2<0.0) continue;
len1 = I*r1;
len2 = I*r2;
V1 *= len1;
V2 *= len2;
V1 += S;
V2 += S;
i1*=0.3;
i2*=0.3;
glColor3f(i1, i1, i1);
glVertex3f(v1->x, v1->y, v1->z);
glColor3f(i2, i2, i2);
glVertex3f(v2->x, v2->y, v2->z);
glColor3f(0.0F, 0.0F, 0.0F);
glVertex3f(V2.x, V2.y, V2.z);
glVertex3f(V1.x, V1.y, V1.z);
}
}
glEnd();
glDisable(GL_CULL_FACE);
glDisable(GL_BLEND);
glDepthMask(GL_ONE);
glEnable(GL_LIGHTING);
glEnable(GL_DEPTH_TEST);
}
void Object3DS::ShadowVolume (Vector3f S, Vector3f C, GLfloat I, int j) {
glDisable(GL_LIGHTING);
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_ZERO);
// glEnable(GL_CULL_FACE);
glDisable(GL_CULL_FACE);
glDisable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE);
glEnable(GL_BLEND);
float cler=0.0;
glDisable(GL_TEXTURE_2D);
Vector3f V1, V2, V3;
glBegin(GL_QUADS);
Edge3DS* p = edges;
Vertex3DS* v1;
Vertex3DS* v2;
p = edges;
for(int z=0; z<numedges; z++, p++) {
v1 = evertices + p->a;
v2 = evertices + p->b;
V1 = Vector3f(v1->x-S.x, v1->y-S.y, v1->z-S.z);
V3 = Vector3f(v1->x-C.x, v1->y-C.y, v1->z-C.z);
GLfloat a1 = V1.x*p->N1_x + V1.y*p->N1_y + V1.z*p->N1_z;
GLfloat a2 = V1.x*p->N2_x + V1.y*p->N2_y + V1.z*p->N2_z;
Vector3f n1=Vector3f( p->N1_x+p->N2_x, p->N1_y+p->N2_y, p->N1_z+p->N2_z)*0.5F;
Vector3f n2=Vector3f( v1->x-v2->x, v1->y-v2->y, v1->z-v2->z);
Vector3f n3=Cross(n2,V1);
if ( Dot(n3,n1)<0.0 ) n3=-n3;
GLfloat a3= (V3.x*n3.x + V3.y*n3.y + V3.z*n3.z)*j;
if (a3>0.0)
if((a1*a2)<0.0) {
V2 = Vector3f(v2->x-S.x, v2->y-S.y, v2->z-S.z);
float len1 = (I/sqrt(V1.x*V1.x + V1.y*V1.y + V1.z*V1.z));
V1.x=V1.x*len1 + v1->x;
V1.y=V1.y*len1 + v1->y;
V1.z=V1.z*len1 + v1->z;
float len2 = (I/sqrt(V2.x*V2.x + V2.y*V2.y + V2.z*V2.z));
V2.x=V2.x*len2 + v2->x;
V2.y=V2.y*len2 + v2->y;
V2.z=V2.z*len2 + v2->z;
glColor3f(cler,cler,cler);
glVertex3f(v1->x, v1->y, v1->z);
glVertex3f(v2->x, v2->y, v2->z);
glVertex3f(V2.x, V2.y, V2.z);
glVertex3f(V1.x, V1.y, V1.z);
}
}
glEnd();
glDisable(GL_CULL_FACE);
glDisable(GL_BLEND);
glDepthMask(GL_ONE);
glEnable(GL_LIGHTING);
glEnable(GL_DEPTH_TEST);
}
void Object3DS::ShortLine ( Vector3f C, GLfloat W, GLfloat r, GLfloat g, GLfloat b) {
glDisable(GL_LIGHTING);
glDisable(GL_CULL_FACE);
// glDisable(GL_BLEND);
glDisable(GL_TEXTURE_2D);
glLineWidth(W);
Vector3f V1;
glBegin(GL_LINES);
glColor3f(r,g,b);
Edge3DS* p = edges;
Vertex3DS* v1;
Vertex3DS* v2;
p = edges;
float total=0.0;
for(int z=0; z<numedges; z++, p++) {
v1 = evertices + p->a;
v2 = evertices + p->b;
V1 = Normalize( Vector3f(v1->x-C.x, v1->y-C.y, v1->z-C.z) );
GLfloat a1 = V1.x*p->N1_x + V1.y*p->N1_y + V1.z*p->N1_z;
GLfloat a2 = V1.x*p->N2_x + V1.y*p->N2_y + V1.z*p->N2_z;
// if((a1>=0.0)&&(a2>=0.0))
// if((a1<=0.0)&&(a2<=0.0))
{
glVertex3f(v1->x, v1->y, v1->z);
glVertex3f(v2->x, v2->y, v2->z);
}
//cout << "Vertex " << z << ": " << p->a << "," << p->b << endl;
total++;
}
glEnd();
//cout << "Shortline total: " << total << endl;
glEnable(GL_CULL_FACE);
glDepthMask(GL_ONE);
glEnable(GL_LIGHTING);
glEnable(GL_DEPTH_TEST);
}
void DrawLongLine(float x1,float y1, float x2, float y2)
{
float xl,yl;
float xr,yr;
float xu,yu;
float xd,yd;
int l,r,u,d;
float a;
l=r=u=d=0;
float dx=x2-x1;
float dy=y2-y1;
if (dx!=0)
{
a=( 1.0-x2)/dx;
xr=1.0;
yr=y2+a*dy;
if ((yr<1.0)&&(yr>=-1.0)) r=1;
a=(-1.0-x2)/dx;
xl=-1.0;
yl=y2+a*dy;
if ((yl<=1.0)&&(yl>-1.0)) l=1;
}
if (dy!=0)
{
a=( 1.0-y2)/dy;
yu=1.0;
xu=x2+a*dx;
if ((xu<=1.0)&&(xu>-1.0)) u=1;
a=(-1.0-y2)/dy;
yd=-1.0;
xd=x2+a*dx;
if ((xd<1.0)&&(xd>=-1.0)) d=1;
}
if (l) glVertex2f(xl,yl);
if (r) glVertex2f(xr,yr);
if (u) glVertex2f(xu,yu);
if (d) glVertex2f(xd,yd);
}
void Object3DS::LongLine ( Vector3f ang, Vector3f pos, GLfloat scale, GLfloat w, GLfloat r, GLfloat g, GLfloat b)
{
glLineWidth(w);
GLmatrix m=Euler2Matrix(ang.x,ang.y,ang.z);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glBegin(GL_LINES);
glColor3f(r,g,b);
Edge3DS* p = edges;
Vertex3DS* v1;
Vertex3DS* v2;
Vector2f sc1,sc2;
p = edges;
for(int z=0; z<numedges; z++, p++) {
v1 = evertices + p->a;
v2 = evertices + p->b;
Vector4f t1(v1->x,v1->y,v1->z,1.0F);
Vector4f t2(v2->x,v2->y,v2->z,1.0F);
m.MultVertex4f(t1.x,t1.y,t1.z,t1.w);
m.MultVertex4f(t2.x,t2.y,t2.z,t2.w);
sc1= Vector2f(pos.x+ scale*t1.x/ (t1.z+pos.z), pos.y+ scale*t1.y/ (t1.z+pos.z));
sc2= Vector2f(pos.x+ scale*t2.x/ (t2.z+pos.z), pos.y+ scale*t2.y/ (t2.z+pos.z));
DrawLongLine(sc1.x,sc1.y,sc2.x,sc2.y);
}
glEnd();
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
}
void Object3DS::ShortLine ( Vector3f ang, Vector3f pos, GLfloat scale, GLfloat w, GLfloat r, GLfloat g, GLfloat b)
{
glLineWidth(w);
GLmatrix m=Euler2Matrix(ang.x,ang.y,ang.z);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glBegin(GL_LINES);
glColor3f(r,g,b);
Edge3DS* p = edges;
Vertex3DS* v1;
Vertex3DS* v2;
Vector2f sc1,sc2;
p = edges;
for(int z=0; z<numedges; z++, p++) {
v1 = evertices + p->a;
v2 = evertices + p->b;
Vector4f t1(v1->x,v1->y,v1->z,1.0F);
Vector4f t2(v2->x,v2->y,v2->z,1.0F);
m.MultVertex4f(t1.x,t1.y,t1.z,t1.w);
m.MultVertex4f(t2.x,t2.y,t2.z,t2.w);
sc1= Vector2f(pos.x+ scale*t1.x/ (t1.z+pos.z), pos.y+ scale*t1.y/ (t1.z+pos.z));
sc2= Vector2f(pos.x+ scale*t2.x/ (t2.z+pos.z), pos.y+ scale*t2.y/ (t2.z+pos.z));
glVertex2f(sc1.x, sc1.y);
glVertex2f(sc2.x, sc2.y);
}
glEnd();
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
}
void Object3DS::Outline ( Vector3f C, GLfloat W, GLfloat r, GLfloat g, GLfloat b) {
glDisable(GL_LIGHTING);
glDisable(GL_DEPTH_TEST);
// glDepthMask(GL_ZERO);
glDisable(GL_CULL_FACE);
// glDisable(GL_BLEND);
glDisable(GL_TEXTURE_2D);
glLineWidth(W);
Vector3f V1;
glBegin(GL_LINES);
glColor3f(r,g,b);
Edge3DS* p = edges;
Vertex3DS* v1;
Vertex3DS* v2;
p = edges;
float total=0.0;
float outl=0.0;
float other=0.0;
for(int z=0; z<numedges; z++) {
v1 = evertices + p->a;
v2 = evertices + p->b;
V1 = Normalize( Vector3f(v1->x-C.x, v1->y-C.y, v1->z-C.z) );
GLfloat a1 = V1.x*p->N1_x + V1.y*p->N1_y + V1.z*p->N1_z;
GLfloat a2 = V1.x*p->N2_x + V1.y*p->N2_y + V1.z*p->N2_z;
if((a1*a2)<0.0)
{
// GLfloat obr = Minimum(fabs(a1), fabs(a2));
// obr=sin(sin(sin(sin(obr*PI2)*PI2)*PI2)*PI2);
// glColor3f(obr,obr,obr);
glVertex3f(v1->x, v1->y, v1->z);
glVertex3f(v2->x, v2->y, v2->z);
outl++;
} else other++;
total++;
p++;
}
glEnd();
//cout << "Longline total: " << total << " good: " << outl << " bad: " << other << endl;
//if (total>numedges) cout << "error 1" << endl;
//if (total!=outl+other) cout << "error 2" << endl;
glEnable(GL_CULL_FACE);
glDepthMask(GL_ONE);
glEnable(GL_LIGHTING);
glEnable(GL_DEPTH_TEST);
}
void Object3DS::Inline ( Vector3f C, GLfloat W, GLfloat r, GLfloat g, GLfloat b) {
glDisable(GL_LIGHTING);
glDisable(GL_DEPTH_TEST);
// glDepthMask(GL_ZERO);
glDisable(GL_CULL_FACE);
// glDisable(GL_BLEND);
glDisable(GL_TEXTURE_2D);
glLineWidth(W);
Vector3f V1;
glBegin(GL_LINES);
glColor3f(r,g,b);
Edge3DS* p = edges;
Vertex3DS* v1;
Vertex3DS* v2;
p = edges;
float total=0.0;
float outl=0.0;
float other=0.0;
for(int z=0; z<numedges; z++) {
v1 = evertices + p->a;
v2 = evertices + p->b;
V1 = Normalize( Vector3f(v1->x-C.x, v1->y-C.y, v1->z-C.z) );
GLfloat a1 = V1.x*p->N1_x + V1.y*p->N1_y + V1.z*p->N1_z;
GLfloat a2 = V1.x*p->N2_x + V1.y*p->N2_y + V1.z*p->N2_z;
if((a1*a2)>=0.0)
{
// GLfloat obr = Minimum(fabs(a1), fabs(a2));
// obr=sin(sin(sin(sin(obr*PI2)*PI2)*PI2)*PI2);
// glColor3f(obr,obr,obr);
glVertex3f(v1->x, v1->y, v1->z);
glVertex3f(v2->x, v2->y, v2->z);
outl++;
} else other++;
total++;
p++;
}
glEnd();
if (total>numedges) cout << "error 3" << endl;
if (total!=outl+other) cout << "error 4" << endl;
glEnable(GL_CULL_FACE);
glDepthMask(GL_ONE);
glEnable(GL_LIGHTING);
glEnable(GL_DEPTH_TEST);
}
void Object3DS::Render (double time = 0.0) {
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
GLmatrix M = lcs.Val(time);
glMultMatrixf(M());
if(!(bbox.IsVisible())) {
glPopMatrix();
return;
}
glInterleavedArrays(GL_T4F_C4F_N3F_V4F, 0, (void*)vertices);
glLockArraysEXT(0, numvertices);
facegroups.rewind();
for(int i=facegroups.size(); i; i--) {
FaceGroup3DS& fg = *facegroups;
Material3DS* mat = fg.material;
mat->GL();
switch(mat->Transparency()) {
case 50:
glDepthMask(GL_ZERO);
glDisable(GL_CULL_FACE);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE);
break;
case 49:
case 51:
glDepthMask(GL_ZERO);
glDisable(GL_CULL_FACE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
break;
default:
glDepthMask(GL_ONE);
glEnable(GL_CULL_FACE);
glDisable(GL_BLEND);
break;
}
glDrawElements(GL_TRIANGLES, 3*(fg.numfaces), GL_UNSIGNED_INT, (void*)(fg.indices));
++facegroups;
}
glUnlockArraysEXT();
glDisable(GL_CULL_FACE);
glDisable(GL_BLEND);
glDepthMask(GL_ONE);
glPopMatrix();
}
void Object3DS::Vertices (int n, Vertex3DS* p) {
numvertices = n;
vertices = p;
bbox = BoundVertices(n, p);
}
void Object3DS::AddFaceGroup (Material3DS* mat, int n, GLuint* ind) {
facegroups.push_back(FaceGroup3DS(mat, n, ind));
}
void Object3DS::EdgeVertices (int n, Vertex3DS* p) {
numevertices = n;
evertices = p;
}
void Object3DS::Edges (int n, Edge3DS* p) {
numedges = n;
edges = p;
}
void Object3DS::Facenormals (int n, Vector3f* p) {
numfaces = n;
facenormals = p;
}
void Object3DS::CoordinateSystem (const GLmatrix& V) {
lcs(V);
}
void Object3DS::CoordinateSystem (Dynamic<GLmatrix, GLfloat> *ptr, bool strong = false) {
lcs(ptr, strong);
}
Scene3DS::Scene3DS () {
allframes = 0;
Material3DS* default_material = new Material3DS;
default_material->Name("____DEFAULT_MATERIAL");
Add(default_material);
return;
}
Scene3DS::~Scene3DS () {
lights.DeleteEntities();
materials.DeleteEntities();
textures.DeleteEntities();
cameras.DeleteEntities();
objects.DeleteEntities();
}
void Scene3DS::Render (double time = 0.0) {
lights.GL(time);
objects.Render(time);
}
void Scene3DS::Add (Light* p) {
lights+=p;
}
void Scene3DS::Add (Texture3DS* p) {
textures+=p;
}
void Scene3DS::Add (Material3DS* p) {
materials+=p;
}
void Scene3DS::Add (CameraTarget3DS* p) {
cameras+=p;
}
void Scene3DS::Add (RenderableEntity* p) {
objects+=p;
}
void Scene3DS::Add (const RenderableEntities & os) {
objects.Add(os);
}
Light* Scene3DS::GetLight (String s) {
return lights.Get(s);
}
Texture3DS* Scene3DS::GetTexture (String s) {
return textures.Get(s);
}
Material3DS* Scene3DS::GetMaterial (String s) {
return materials.Get(s);
}
CameraTarget3DS* Scene3DS::GetCamera (String s) {
return cameras.Get(s);
}
RenderableEntity* Scene3DS::GetObject (String s) {
return objects.Get(s);
}
Lights Scene3DS::GetLights () {
return lights;
}
Textures3DS Scene3DS::GetTextures () {
return textures;
}
Materials3DS Scene3DS::GetMaterials () {
return materials;
}
Cameras3DS Scene3DS::GetCameras () {
return cameras;
}
RenderableEntities Scene3DS::GetObjects () {
return objects;
}
void Scene3DS::Ambient (GLfloat r, GLfloat g, GLfloat b, GLfloat a=1.0) {
SetVector4(ambient, r, g, b, a);
}
char* Loader3DS::find_chunk(char *father, unsigned short chunk_type, char *act)
{
char *chunk_end = father + getlong(father+2);
while((act<chunk_end) && (getshort(act)!=chunk_type))
act += getlong(act+2);
if(act<chunk_end)
return act;
else
return 0;
}
List<chunk3ds> Loader3DS::subchunks(char *father, char *act)
{
List<chunk3ds> l;
chunk3ds c;
char *chunk_end = father + getlong(father+2);
while(act<chunk_end)
{
c.type=getshort(act);
c.ptr=act;
l.push_back(c);
act+=getlong(act+2);
}
return l;
}
List<chunk3ds> Loader3DS::subchunks_by_type(char *father, unsigned short chunk_type, char *act)
{
List<chunk3ds> l;
chunk3ds c;
char *chunk_end = father + getlong(father+2);
while(act<chunk_end)
{
if(getshort(act) == chunk_type)
{
c.type = getshort(act);
c.ptr = act;
l.push_back(c);
}
act+=getlong(act+2);
}
return l;
}
void Loader3DS::tcb_info(unsigned short flag)
{
// if (API3DS_TEXT_OUT) cout << flag << " ";
if(flag&1)
if (API3DS_TEXT_OUT) cout << "tension ";
if(flag&2)
if (API3DS_TEXT_OUT) cout << "continuity ";
if(flag&4)
if (API3DS_TEXT_OUT) cout << "bias ";
if(flag&8)
if (API3DS_TEXT_OUT) cout << "ease-to ";
if(flag&16)
if (API3DS_TEXT_OUT) cout << "ease-from ";
}
char* Loader3DS::fill_tcbee(unsigned short flag, char *p, TCBEE *tcb)
{
tcb->tension = 0.0;
tcb->continuity = 0.0;
tcb->bias = 0.0;
tcb->easeto = 0.0;
tcb->easefrom = 0.0;
if(flag&1) {
tcb->tension = getfloat(p);
p+=4;
}
if(flag&2) {
tcb->continuity = getfloat(p);
p+=4;
}
if(flag&4) {
tcb->bias = getfloat(p);
p+=4;
}
if(flag&8) {
tcb->easeto = getfloat(p);
p+=4;
}
if(flag&16) {
tcb->easefrom = getfloat(p);
p+=4;
}
return p;
}
void Loader3DS::track_type_info(unsigned short flag)
{
switch(flag&3) {
case 0:
if (API3DS_TEXT_OUT) cout << "single";
break;
case 2:
if (API3DS_TEXT_OUT) cout << "repeat";
break;
case 3:
if (API3DS_TEXT_OUT) cout << "loop";
break;
}
switch((flag&52)>>3) {
case 1:
if (API3DS_TEXT_OUT) cout << ", lock X";
break;
case 2:
if (API3DS_TEXT_OUT) cout << ", lock Y";
break;
case 4:
if (API3DS_TEXT_OUT) cout << ", lock Z";
break;
}
switch((flag&896)>>7) {
case 1:
if (API3DS_TEXT_OUT) cout << ", unlink X";
break;
case 2:
if (API3DS_TEXT_OUT) cout << ", unlink Y";
break;
case 4:
if (API3DS_TEXT_OUT) cout << ", unlink Z";
break;
}
}
Scene3DS* Loader3DS::Load(const char *inputfile, Textures3DS* texturelib = 0)
{
Scene3DS* scene = 0;
bool take_care_of_buf_alloc = buffer ? false : true;
try {
if(take_care_of_buf_alloc)
buffer = new char[BUFFER_SIZE_3DS];
gzFile file;
file = gzopen(inputfile,"rb");
if(file == 0) {
if (API3DS_TEXT_OUT) cout << "3DS Loader: Error: Can't open """ << inputfile << """." << endl;
throw 1;
}
gzread(file, buffer, BUFFER_SIZE_3DS);
gzclose(file);
/*
int f = open(inputfile, O_BINARY|O_RDONLY);
if (f==-1) {
if (API3DS_TEXT_OUT) cout << "3DS Loader: Error: File not found." << endl;
throw 1;
}
struct stat st;
fstat(f,&st);
buffer = new char[st.st_size];
read(f,buffer,st.st_size);
close(f);
*/
if (API3DS_TEXT_OUT) cout << "3DS Loader: Processing \""<< inputfile << "\":" << endl;
if (getshort(buffer)!=MAIN_3DS_CHUNK)
{
if (API3DS_TEXT_OUT) cout << "3DS Loader: Error: Invalid inputfile." << endl;
throw 1;
}
// start processing
char *pmesh = buffer;
scene = new Scene3DS;
scene->Name(inputfile);
// find the editor chunk
char *peditor = find_chunk(pmesh, EDITOR_CHUNK, pmesh+6);
// look for ambient color
char *p = find_chunk(peditor, AMBIENT_COLOR, peditor+6);
if(p!=0)
{
p = find_chunk(p, RGBfloat, p+6);
if(p!=0)
{
p+=6;
if (API3DS_TEXT_OUT) cout<<" Ambient color: ("
<<(int)(256*getfloat(p))<<", "
<<(int)(256*getfloat(p+4))<<", "
<<(int)(256*getfloat(p+8))<< ")" << endl;
scene->Ambient(getfloat(p), getfloat(p+4), getfloat(p+8));
}
}
List<chunk3ds> pmats(subchunks_by_type(peditor, MATERIAL_BLOCK, peditor+6));
if (API3DS_TEXT_OUT) cout << " Materials: " << endl;
char *pmat;
pmats.rewind();
for(int nm=pmats.size(); nm; nm--)
{
pmat = (*pmats).ptr;
p = find_chunk(pmat, MATERIAL_NAME, pmat+6);
if (API3DS_TEXT_OUT) cout << " \"" << (const char *)(p+6) << "\":" << endl;
Material3DS *mat = new Material3DS;
mat->Name((const char *)(p+6));
scene->Add(mat);
p = find_chunk(pmat, MATERIAL_AMBIENT_COLOR, pmat+6);
if(p!=0)
{
GLubyte *rgbcolor = (GLubyte *)find_chunk(p, RGBbyte, p+6)+6;
if (API3DS_TEXT_OUT) cout << " Ambient color: ("
<< (int) *rgbcolor << ", "
<< (int) *(rgbcolor+1) << ", "
<< (int) *(rgbcolor+2) << ")" << endl;
mat->Ambient(*rgbcolor, *(rgbcolor+1), *(rgbcolor+2));
}
p = find_chunk(pmat, MATERIAL_DIFFUSE_COLOR, pmat+6);
if(p!=0)
{
GLubyte *rgbcolor = (GLubyte *)find_chunk(p, RGBbyte, p+6)+6;
if (API3DS_TEXT_OUT) cout << " Diffuse color: ("
<< (int) *rgbcolor << ", "
<< (int) *(rgbcolor+1) << ", "
<< (int) *(rgbcolor+2) << ")" << endl;
mat->Diffuse(*rgbcolor, *(rgbcolor+1), *(rgbcolor+2));
}
p = find_chunk(pmat, MATERIAL_SPECULAR_COLOR, pmat+6);
if(p!=0)
{
GLubyte *rgbcolor = (GLubyte *)find_chunk(p, RGBbyte, p+6)+6;
if (API3DS_TEXT_OUT) cout << " Specular color: ("
<< (int) *rgbcolor << ", "
<< (int) *(rgbcolor+1) << ", "
<< (int) *(rgbcolor+2) << ")" << endl;
mat->Specular(*rgbcolor, *(rgbcolor+1), *(rgbcolor+2));
}
p = find_chunk(pmat, TRANSPARENCY_PERCENT, pmat+6);
if(p!=0)
{
char *percent = find_chunk(p, PERCENTword, p+6)+6;
if (API3DS_TEXT_OUT) cout << " Transparency: " << getshort(percent) << "%" << endl;
int xp = getshort(percent);
mat->Transparency(xp);
}
p = find_chunk(pmat, MAP1, pmat+6);
if(p!=0)
{
char *ptname = find_chunk(p, MAPPING_FILENAME, p+6)+6;
// *-> data directory access
// char tm_p[30]="data\\";
// strcat(tm_p,ptname);
// strcpy(ptname,tm_p);
if (API3DS_TEXT_OUT) cout << " Diffuse map: \"" << (const char *)ptname << "\"" << endl;
/*
* An external texture library can be passed as a second argument
* to Load(...)
*/
Texture3DS* tex;
if(texturelib) {
tex = texturelib->GetOrCreate((const char*)ptname);
}
else {
tex = new Texture3DS;
tex->Name((const char *)ptname);
tex->MinFilter(GL_LINEAR);
tex->MagFilter(GL_LINEAR);
scene->Add(tex);
}
mat->Texture1(tex);
}
++pmats;
}
// list obj blocks within editor
List<chunk3ds> pl(subchunks_by_type(peditor, OBJECT_BLOCK, peditor+6));
pl.rewind();
char *po, *pi, *ptri;
RenderableEntities transparent_objects;
bool istransparent;
if (API3DS_TEXT_OUT) cout << " Object blocks:" << endl;
const char *pname;
for(int no=pl.size(); no; no--)
{
po = (*pl).ptr;
++pl;
pi = po + 6;
pname = (const char *)pi;
if (API3DS_TEXT_OUT) cout << " \"" << pname << "\" ";
while(*pi) pi++; pi++;
if(find_chunk(po, TRIANGULAR_MESH, pi))
{
if (API3DS_TEXT_OUT) cout << "A mesh. ";
ptri = find_chunk(po, TRIANGULAR_MESH, pi);
// find vertices
int vertex_count = 0;
Vector3DS *pvertices = 0;
p = find_chunk(ptri, VERTICES, ptri+6);
if(p!=0)
{
vertex_count = getshort(p+6);
pvertices = (Vector3DS *)(p+8);
}
// find faces
int face_count = 0;
Face3DS *pfaces = 0;
p = find_chunk(ptri, FACES, ptri+6);
char *pfaceschunk = p;
if(p!=0)
{
face_count = getshort(p+6);
pfaces = (Face3DS *)(p+8);
}
// find mapping info
int map_vertex_count = 0;
Mapping3DS *pmapping = 0;
p = find_chunk(ptri, MAPPING_COORDS, ptri+6);
if(p!=0)
{
map_vertex_count = getshort(p+6);
pmapping = (Mapping3DS *)(p+8);
}
if(pvertices && pfaces)
{
if (API3DS_TEXT_OUT) cout <<"("<<vertex_count<<" vertices, "<<face_count<<" faces"<<")";
if(pmapping)
if (API3DS_TEXT_OUT) cout << " mapped.";
if (API3DS_TEXT_OUT) cout << endl;
Object3DS *object = new Object3DS;
object->Name(pname);
istransparent = false;
// for every i-th face smooths[i] is the smoothing groups info
unsigned long *smooths = 0;
if(find_chunk(pfaceschunk, SMOOTHINGS, (char *)(pfaces+face_count))) {
smooths = (unsigned long *)(6+find_chunk(pfaceschunk, SMOOTHINGS, (char *)(pfaces+face_count)));
}
iface Iface[face_count];
Vector3f P1, P2, P3;
for(int z=0; z<face_count; z++) {
Iface[z].a = pfaces[z].a;
Iface[z].b = pfaces[z].b;
Iface[z].c = pfaces[z].c;
if(smooths)
Iface[z].sgroup = smooths[z];
else
Iface[z].sgroup = 1;
Vector3DS* pv;
pv = pvertices + pfaces[z].a;
P1 = Vector3f(pv->x, pv->y, pv->z);
pv = pvertices + pfaces[z].b;
P2 = Vector3f(pv->x, pv->y, pv->z);
pv = pvertices + pfaces[z].c;
P3 = Vector3f(pv->x, pv->y, pv->z);
Iface[z].N = Normalize(CrossProduct(P2-P1, P3-P1));
Iface[z].hasmaterial = false;
Iface[z].ab_done = !(pfaces[z].flags&4);
Iface[z].ac_done = !(pfaces[z].flags&1);
Iface[z].bc_done = !(pfaces[z].flags&2);
// Iface[z].ab_done = false;
// Iface[z].ac_done = false;
// Iface[z].bc_done = false;
}
Vertex3DS* vert = new Vertex3DS[vertex_count*2];
for(int z=0; z<vertex_count; z++) {
vert[z].x = pvertices[z].x;
vert[z].y = pvertices[z].y;
vert[z].z = pvertices[z].z;
vert[z].w = 1.0F;
vert[z].R = vert[z].G = vert[z].B = vert[z].A = 1.0F;
vert[z].r = 0.0F;
vert[z].q = 1.0F;
if(pmapping) {
vert[z].s = pmapping[z].u;
vert[z].t = pmapping[z].v;
}
else {
vert[z].s = 0.0F;
vert[z].t = 0.0F;
}
vert[z].i = 0.0F;
vert[z].j = 0.0F;
vert[z].k = 0.0F;
}
/*
* Here we create a copy of the vertices, which is suitable for
* creating volumetric effects.
*/
for(int z=0; z<vertex_count; z++) {
vert[z+vertex_count] = vert[z];
}
object->EdgeVertices(vertex_count*2, vert);
/*
* We build an array of normals at each face, suitable for effects.
*/
Vector3f* fnormals = new Vector3f[face_count];
for(int z=0; z<face_count; z++) {
fnormals[z] = Iface[z].N;
}
object->Facenormals(face_count, fnormals);
/*
* For each vertex we build a table of pointers to faces
* that share it.
*/
shinfo sharings[vertex_count];
for(int z=0; z<vertex_count; z++) {
sharings[z].numfaces = 0;
sharings[z].used = 0;
sharings[z].splits = 0;
sharings[z].p = 0;
sharings[z].v = 0;
sharings[z].iv = 0;
}
for(int z=0; z<face_count; z++) {
sharings[Iface[z].a].numfaces++;
sharings[Iface[z].b].numfaces++;
sharings[Iface[z].c].numfaces++;
}
ftable fgroups[face_count*3];
for(int z=0; z<(face_count*3); z++) {
fgroups[z].group = 0;
}
ftable* fptr = fgroups;
for(int z=0; z<vertex_count; z++) {
sharings[z].p = fptr;
fptr+=sharings[z].numfaces;
}
for(int z=0; z<face_count; z++) {
(sharings[Iface[z].a].p + sharings[Iface[z].a].used)->fi = z;
sharings[Iface[z].a].used++;
(sharings[Iface[z].b].p + sharings[Iface[z].b].used)->fi = z;
sharings[Iface[z].b].used++;
(sharings[Iface[z].c].p + sharings[Iface[z].c].used)->fi = z;
sharings[Iface[z].c].used++;
}
/*
* Build an array of this objects polygon edges
*/
Edge3DS* edges = new Edge3DS[face_count*3];
int edge_count = 0;
for(int z=0; z<face_count; z++) {
GLuint aa = Iface[z].a;
GLuint bb = Iface[z].b;
GLuint cc = Iface[z].c;
// AB edge
if(!Iface[z].ab_done) {
Iface[z].ab_done = true;
edges[edge_count].a = aa;
edges[edge_count].b = bb;
edges[edge_count].N1_x = Iface[z].N.x;
edges[edge_count].N1_y = Iface[z].N.y;
edges[edge_count].N1_z = Iface[z].N.z;
ftable* fp = sharings[aa].p;
int d = 0;
for(; d<sharings[aa].numfaces; d++, fp++) {
if(z==fp->fi) continue;
iface& face = Iface[fp->fi];
if((face.a==aa&&face.b==bb)||(face.a==bb&&face.b==aa)) {
face.ab_done = true;
edges[edge_count].N2_x = face.N.x;
edges[edge_count].N2_y = face.N.y;
edges[edge_count].N2_z = face.N.z;
break;
}
if((face.a==aa&&face.c==bb)||(face.a==bb&&face.c==aa)) {
face.ac_done = true;
edges[edge_count].N2_x = face.N.x;
edges[edge_count].N2_y = face.N.y;
edges[edge_count].N2_z = face.N.z;
break;
}
if((face.b==aa&&face.c==bb)||(face.b==bb&&face.c==aa)) {
face.bc_done = true;
edges[edge_count].N2_x = face.N.x;
edges[edge_count].N2_y = face.N.y;
edges[edge_count].N2_z = face.N.z;
break;
}
}
if(d==sharings[aa].numfaces) {
edges[edge_count].N2_x = -Iface[z].N.x;
edges[edge_count].N2_y = -Iface[z].N.y;
edges[edge_count].N2_z = -Iface[z].N.z;
}
edge_count++;
}
// AC edge
if(!Iface[z].ac_done) {
Iface[z].ac_done = true;
edges[edge_count].a = aa;
edges[edge_count].b = cc;
edges[edge_count].N1_x = Iface[z].N.x;
edges[edge_count].N1_y = Iface[z].N.y;
edges[edge_count].N1_z = Iface[z].N.z;
ftable* fp = sharings[aa].p;
int d = 0;
for(; d<sharings[aa].numfaces; d++, fp++) {
if(z==fp->fi) continue;
iface& face = Iface[fp->fi];
if((face.a==aa&&face.b==cc)||(face.a==cc&&face.b==aa)) {
face.ab_done = true;
edges[edge_count].N2_x = face.N.x;
edges[edge_count].N2_y = face.N.y;
edges[edge_count].N2_z = face.N.z;
break;
}
if((face.a==aa&&face.c==cc)||(face.a==cc&&face.c==aa)) {
face.ac_done = true;
edges[edge_count].N2_x = face.N.x;
edges[edge_count].N2_y = face.N.y;
edges[edge_count].N2_z = face.N.z;
break;
}
if((face.b==aa&&face.c==cc)||(face.b==cc&&face.c==aa)) {
face.bc_done = true;
edges[edge_count].N2_x = face.N.x;
edges[edge_count].N2_y = face.N.y;
edges[edge_count].N2_z = face.N.z;
break;
}
}
if(d==sharings[aa].numfaces) {
edges[edge_count].N2_x = -Iface[z].N.x;
edges[edge_count].N2_y = -Iface[z].N.y;
edges[edge_count].N2_z = -Iface[z].N.z;
}
edge_count++;
}
// BC edge
if(!Iface[z].bc_done) {
Iface[z].bc_done = true;
edges[edge_count].a = bb;
edges[edge_count].b = cc;
edges[edge_count].N1_x = Iface[z].N.x;
edges[edge_count].N1_y = Iface[z].N.y;
edges[edge_count].N1_z = Iface[z].N.z;
ftable* fp = sharings[bb].p;
int d = 0;
for(; d<sharings[bb].numfaces; d++, fp++) {
if(z==fp->fi) continue;
iface& face = Iface[fp->fi];
if((face.a==bb&&face.b==cc)||(face.a==cc&&face.b==bb)) {
face.ab_done = true;
edges[edge_count].N2_x = face.N.x;
edges[edge_count].N2_y = face.N.y;
edges[edge_count].N2_z = face.N.z;
break;
}
if((face.a==bb&&face.c==cc)||(face.a==cc&&face.c==bb)) {
face.ac_done = true;
edges[edge_count].N2_x = face.N.x;
edges[edge_count].N2_y = face.N.y;
edges[edge_count].N2_z = face.N.z;
break;
}
if((face.b==bb&&face.c==cc)||(face.b==cc&&face.c==bb)) {
face.bc_done = true;
edges[edge_count].N2_x = face.N.x;
edges[edge_count].N2_y = face.N.y;
edges[edge_count].N2_z = face.N.z;
break;
}
}
if(d==sharings[bb].numfaces) {
edges[edge_count].N2_x = -Iface[z].N.x;
edges[edge_count].N2_y = -Iface[z].N.y;
edges[edge_count].N2_z = -Iface[z].N.z;
}
edge_count++;
}
}
object->Edges(edge_count, edges);
if (API3DS_TEXT_OUT) cout<< " Edges: " << edge_count << endl;
/*
* For each vertex we divide the faces sharing it into groups
* according to the smoothing info. The algorithm used assumes
* some "good" structure of smoothing data, and cannot handle
* all the possible (although unprobable) cases.
*/
int vertex_count2 = 0;
if(smooths) {
for(int z=0; z<vertex_count; z++) {
GLuint g = 0;
ftable* fp = sharings[z].p;
/*
* here we try to handle out the faces w/o smoothing info
*/
for(int d=0; d<sharings[z].numfaces; d++) {
if(Iface[fp->fi].sgroup==0) {
g++;
fp->group = g;
}
fp++;
}
while(true) {
/*
* and from now on just the nice behaving faces
*/
int r = 0;
fp = sharings[z].p;
r = 0;
for(; r<sharings[z].numfaces; r++) {
if(!fp->group) break;
fp++;
}
if(r==sharings[z].numfaces) break;
g++;
unsigned long cgroup = Iface[fp->fi].sgroup;
for(; r<sharings[z].numfaces; r++) {
if(!fp->group)
if(Iface[fp->fi].sgroup&cgroup)
fp->group = g;
fp++;
}
}
sharings[z].splits = g;
vertex_count2 += g;
}
}
else {
/*
* This is for the case when the object is not smoothed at all.
*/
for(int z=0; z<vertex_count; z++) {
ftable* fp = sharings[z].p;
for(int q=1; q<=sharings[z].numfaces; q++) {
fp->group = q;
fp++;
}
sharings[z].splits = sharings[z].numfaces;
vertex_count2 += sharings[z].numfaces;
}
}
Vertex3DS* vert2 = new Vertex3DS[vertex_count2];
Vertex3DS* pvert2 = vert2;
GLuint iiv = 0;
for(int z=0; z<vertex_count; z++) {
sharings[z].v = pvert2;
sharings[z].iv = iiv;
for(int q=sharings[z].splits; q; q--) {
*pvert2 = vert[z];
pvert2++;
iiv++;
}
}
iface Iface2[face_count];
for(int z=0; z<face_count; z++)
Iface2[z] = Iface[z];
for(int z=0; z<vertex_count; z++) {
ftable* fp = sharings[z].p;
for(int q=0; q<sharings[z].numfaces; q++) {
iface* pi_src = &Iface2[fp->fi];
iface* pi_dst = &Iface[fp->fi];
GLuint sv = sharings[z].iv + fp->group - 1;
if(z==pi_src->a) pi_dst->a = sv;
if(z==pi_src->b) pi_dst->b = sv;
if(z==pi_src->c) pi_dst->c = sv;
fp++;
}
}
if (API3DS_TEXT_OUT) cout<< " Before: "<<vertex_count*3<<" After: "<<vertex_count2<<endl;
iface* pif = Iface;
for(int z=0; z<face_count; z++, pif++) {
GLfloat nx = (pif->N).x;
GLfloat ny = (pif->N).y;
GLfloat nz = (pif->N).z;
GLuint aa = pif->a;
GLuint bb = pif->b;
GLuint cc = pif->c;
vert2[aa].i += nx;
vert2[aa].j += ny;
vert2[aa].k += nz;
vert2[bb].i += nx;
vert2[bb].j += ny;
vert2[bb].k += nz;
vert2[cc].i += nx;
vert2[cc].j += ny;
vert2[cc].k += nz;
}
for(int z=0; z<vertex_count2; z++) {
GLfloat len = 1.0/sqrt(vert2[z].i*vert2[z].i +
vert2[z].j*vert2[z].j +
vert2[z].k*vert2[z].k);
vert2[z].i *= len;
vert2[z].j *= len;
vert2[z].k *= len;
}
object->Vertices(vertex_count2, vert2);
List<chunk3ds> pmlist(subchunks_by_type(pfaceschunk, FACES_MATERIALS, (char *)(pfaces+face_count)));
if(pmlist.size()!=0) if (API3DS_TEXT_OUT) cout<<" Materials: ";
pmlist.rewind();
GLuint* pind;
for(int q=pmlist.size(); q; q--)
{
p = (*pmlist).ptr;
++pmlist;
if (API3DS_TEXT_OUT) cout<<(const char *)(p+6);
Material3DS *matpointer = scene->GetMaterial((const char *)(p+6));
if(matpointer->Transparency()==50)
istransparent = true;
p+=6;
while(*p) p++; p++;
int mapped = getshort(p);
if(!mapped)
// this really happens
continue;
if (API3DS_TEXT_OUT) cout<<" ("<<mapped<<"), ";
p+=2;
pind = new GLuint[mapped*3];
object->AddFaceGroup(matpointer, mapped, pind);
for(int w=mapped; w; w--, p+=2) {
iface* pif = Iface+getshort(p);
pif->hasmaterial = true;
*pind = pif->a; pind++;
*pind = pif->b; pind++;
*pind = pif->c; pind++;
}
}
if(pmlist.size()!=0)
if (API3DS_TEXT_OUT) cout<<endl;
// DEFAULT material (for faces without assigned material)
int wo_material = 0;
for(int w=0; w<face_count; w++)
if(!(Iface[w].hasmaterial))
wo_material++;
if(wo_material) {
pind = new GLuint[wo_material*3];
Material3DS *defmat = scene->GetMaterial("____DEFAULT_MATERIAL");
object->AddFaceGroup(defmat, wo_material, pind);
for(int w=0; w<face_count; w++) {
iface* pif = Iface+w;
if(!(pif->hasmaterial)) {
*pind = pif->a; pind++;
*pind = pif->b; pind++;
*pind = pif->c; pind++;
}
}
}
if(istransparent)
transparent_objects+=object;
else
scene->Add(object);
}
continue;
}
// light
if(find_chunk(po, LIGHT, pi))
{
if (API3DS_TEXT_OUT) cout << "A light." << endl;
p = find_chunk(po, LIGHT, pi);
char *vec = p+6;
char *prgb = find_chunk(p, RGBfloat, p+18)+6;
if (API3DS_TEXT_OUT) cout<<" Position: ("
<< getfloat(vec) <<", "
<< getfloat(vec+4) <<", "
<< getfloat(vec+8) << ")" << endl;
if (API3DS_TEXT_OUT) cout<<" Color: ("
<<(int)(256*getfloat(prgb))<<", "
<<(int)(256*getfloat(prgb+4))<<", "
<<(int)(256*getfloat(prgb+8))<< ")" << endl;
OmniLight3DS* light = new OmniLight3DS;
light->Name(pname);
scene->Add(light);
light->Position(getfloat(vec), getfloat(vec+4), getfloat(vec+8));
light->Diffuse(getfloat(prgb), getfloat(prgb+4), getfloat(prgb+8));
/*
if(FindChunk(plights, LIGHT_OFF, plights+18))
{
newlight->state = 0;
printf(" OFF");
}
*/
continue;
}
// object identified as a camera
if(find_chunk(po, CAMERA, pi))
{
if (API3DS_TEXT_OUT) cout << "A camera." << endl;
CameraTarget3DS *camera = new CameraTarget3DS;
camera->Name(pname);
scene->Add(camera);
p = find_chunk(po, CAMERA, pi);
char *vec = p+6;
if (API3DS_TEXT_OUT) cout<<" Origin: ("
<< getfloat(vec) <<", "
<< getfloat(vec+4) <<", "
<< getfloat(vec+8) << ")" << endl;
camera->Origin(getfloat(vec), getfloat(vec+4), getfloat(vec+8));
vec+=12;
if (API3DS_TEXT_OUT) cout<<" Target: ("
<< getfloat(vec) <<", "
<< getfloat(vec+4) <<", "
<< getfloat(vec+8) << ")" << endl;
camera->Target(getfloat(vec), getfloat(vec+4), getfloat(vec+8));
vec+=12;
if (API3DS_TEXT_OUT) cout<<" Bank: "<<getfloat(vec)<<endl;
vec+=4;
if (API3DS_TEXT_OUT) cout<<" Lens: "<<getfloat(vec)<<endl;
continue;
}
}
scene->Add(transparent_objects);
if (API3DS_TEXT_OUT) cout << endl;
// Keyframer chunk
// ------------------------------------------------------------------
char *keyframer = find_chunk(pmesh, KEYFRAMER_CHUNK, pmesh+6);
if(!keyframer) {
throw 1;
}
if (API3DS_TEXT_OUT) cout << "Keyframer data:" << endl << endl;
p = find_chunk(keyframer, FRAMES, keyframer+6);
if(!p) {
throw 1;
}
if (API3DS_TEXT_OUT) cout << "Animation frames: "<<(int)getlong(p+6)<<" to "<<(int)getlong(p+10)<<"."<<endl;
int frames_start = (int)getlong(p+6);
int frames_end = (int)getlong(p+10);
int frames = frames_end-frames_start + 1;
scene->Frames(frames);
List<chunk3ds> camo(subchunks_by_type(keyframer, CAMERA_INFORMATION_BLOCK, keyframer+6));
camo.rewind();
for(int nc=camo.size(); nc; nc--)
{
if (API3DS_TEXT_OUT) cout << "Camera origin info block:" << endl;
char *info = (*camo).ptr;
++camo;
char *objinfo = find_chunk(info, OBJECT_INFO, info+6);
pname = (const char *)(objinfo+6);
if (API3DS_TEXT_OUT) cout << " Camera: " << pname << endl;
CameraTarget3DS *camera = dynamic_cast<CameraTarget3DS*>(scene->GetCamera(pname));
unsigned short flag, tracktype;
unsigned long keys;
char *track = find_chunk(info, POSITION_TRACK, info+6);
if(track) {
track+=6;
flag = getshort(track);
if (API3DS_TEXT_OUT) cout << " track type: ";
track_type_info(flag);
if (API3DS_TEXT_OUT) cout << endl;
tracktype = flag;
track+=10;
if (API3DS_TEXT_OUT) cout << " Position keys: " << (int)getlong(track) << endl;
keys = (int)getlong(track);
track+=4;
Dynamic<Vector3f, GLfloat> *newtrack = process_position_track(frames, keys, track, tracktype);
if(newtrack)
camera->Origin(newtrack, true);
}
track = find_chunk(info, ROLL_TRACK, info+6);
if(track) {
track+=6;
flag = getshort(track);
if (API3DS_TEXT_OUT) cout << " track type: ";
track_type_info(flag);
if (API3DS_TEXT_OUT) cout << endl;
tracktype = flag;
track+=10;
if (API3DS_TEXT_OUT) cout << " Roll keys: " << (int)getlong(track) << endl;
keys = (int)getlong(track);
track+=4;
Dynamic<GLfloat, GLfloat> *newtrack = process_roll_track(frames, keys, track, tracktype);
if(newtrack)
camera->Roll(newtrack, true);
}
}
List<chunk3ds> camt(subchunks_by_type(keyframer, CAMERA_TARGET_INFORMATION_BLOCK, keyframer+6));
camt.rewind();
for(int nc=camt.size(); nc; nc--)
{
if (API3DS_TEXT_OUT) cout << "Camera target info block:" << endl;
char *info = (*camt).ptr;
++camt;
char *objinfo = find_chunk(info, OBJECT_INFO, info+6);
pname = (const char *)(objinfo+6);
if (API3DS_TEXT_OUT) cout << " Camera: " << pname << endl;
char *track = find_chunk(info, POSITION_TRACK, info+6);
if(!track)
continue;
track+=6;
unsigned short flag = getshort(track);
if (API3DS_TEXT_OUT) cout << " track type: ";
track_type_info(flag);
if (API3DS_TEXT_OUT) cout << endl;
unsigned short tracktype = flag;
track+=10;
if (API3DS_TEXT_OUT) cout << " Position keys: " << (int)getlong(track) << endl;
unsigned long keys = (int)getlong(track);
track+=4;
Dynamic<Vector3f, GLfloat> *newtrack = process_position_track(frames, keys, track, tracktype);
if(!newtrack)
continue;
CameraTarget3DS *camera = dynamic_cast<CameraTarget3DS*>(scene->GetCamera(pname));
if(!camera)
continue;
camera->Target(newtrack, true);
}
List<chunk3ds> caml(subchunks_by_type(keyframer, OMNI_LIGHT_INFORMATION_BLOCK, keyframer+6));
caml.rewind();
for(int nc=caml.size(); nc; nc--)
{
if (API3DS_TEXT_OUT) cout << "Omnilight info block:" << endl;
char *info = (*caml).ptr;
++caml;
char *objinfo = find_chunk(info, OBJECT_INFO, info+6);
pname = (const char *)(objinfo+6);
if (API3DS_TEXT_OUT) cout << " Omnilight: " << pname << endl;
Dynamic<Vector3f, GLfloat> *newtrack;
unsigned short flag, tracktype;
unsigned long keys;
OmniLight3DS *light = dynamic_cast<OmniLight3DS*>(scene->GetLight(pname));
char *track = find_chunk(info, POSITION_TRACK, info+6);
if(track) {
track+=6;
flag = getshort(track);
if (API3DS_TEXT_OUT) cout << " track type: ";
track_type_info(flag);
if (API3DS_TEXT_OUT) cout << endl;
tracktype = flag;
track+=10;
if (API3DS_TEXT_OUT) cout << " Position keys: " << (int)getlong(track) << endl;
keys = (unsigned long)getlong(track);
track+=4;
newtrack = process_position_track(frames, keys, track, tracktype);
if(newtrack)
light->Position(newtrack, true);
}
track = find_chunk(info, COLOR_TRACK, info+6);
if(track) {
track+=6;
flag = getshort(track);
if (API3DS_TEXT_OUT) cout << " track type: ";
track_type_info(flag);
if (API3DS_TEXT_OUT) cout << endl;
tracktype = flag;
track+=10;
if (API3DS_TEXT_OUT) cout << " Color keys: " << (int)getlong(track) << endl;
keys = (unsigned long)getlong(track);
track+=4;
newtrack = process_position_track(frames, keys, track, tracktype);
if(newtrack)
light->Diffuse(newtrack, true);
}
}
throw 1;
}
catch(int value) {
if(take_care_of_buf_alloc) {
delete[] buffer;
buffer = 0;
}
return scene;
}
}
inline float
hermite_spline(float t, float P1, float R1, float P2, float R2) {
return P1*(2*t*t*t - 3*t*t + 1) +
R1*(t*t*t - 2*t*t + t) +
P2*(-2*t*t*t + 3*t*t) +
R2*(t*t*t - t*t);
}
Vector3f Loader3DS::position_track::getv(int sel, int n) {
position_key *kn_1, *kn, *kn1;
Vector3f *pn_1, *pn, *pn1;
int d1, d2;
kn = &keys[n];
pn = &kn->p;
if (sel == point) return *pn;
if (n == 0) {
//first key
kn1 = &keys[1];
pn1 = &kn1->p;
if (count == 2) {
//2 keys
return (*pn1 - *pn)*(1.0F - kn->tension);
};
if (mode != 3) {
//first key, no loop
return ((*pn1 - *pn)*1.5F - getv(an,1)*0.5F)*(1.0F - kn->tension);
} else {
//first key, loop
kn_1= &keys[count-2];
d1 = keys[count-1].frame - kn_1->frame;
d2 = kn1->frame - kn->frame;
};
} else if (n == count-1) {
//last key
kn_1 = &keys[n-1];
pn_1 = &kn_1->p;
if (count == 2) {
//2 keys
return (*pn - *pn_1)*(1.0F - kn->tension);
};
if (mode != 3) {
//last key, no loop
return ((*pn - *pn_1)*1.5F - getv(bn,n-1)*0.5F)*(1.0F - kn->tension);
} else {
//last key, loop
kn1 = &keys[1];
d1 = kn->frame - kn_1->frame;
d2 = kn1->frame - keys[0].frame;
};
} else {
//middle keys
kn_1= &keys[n-1];
kn1 = &keys[n+1];
d1 = kn->frame - kn_1->frame;
d2 = kn1->frame - kn->frame;
};
pn_1= &kn_1->p;
pn1 = &kn1->p;
float C;
float adjust;
if (sel == an) {
C = kn->continuity;
adjust = d1;
} else {
C = -kn->continuity;
adjust = d2;
};
adjust /= d1 + d2;
adjust = 0.5 + (1.0 - fabs(C))*(adjust - 0.5);
return ( (*pn - *pn_1) * ((1.0F + kn->bias)*(1.0F - C))
+ (*pn1 - *pn ) * ((1.0F - kn->bias)*(1.0F + C))
) * ((1.0F - kn->tension)*adjust);
};
Dynamic<Vector3f, GLfloat>* Loader3DS::process_position_track(int allframes, int keys, char *track, unsigned short tracktype)
{
if(keys<2)
return 0;
position_track keyinfo(keys, tracktype&3);
for(int g=0; g<keys; g++)
{
if (API3DS_TEXT_OUT) cout << " Key " << g << ": Frame " << (int)getlong(track) << ".: ";
keyinfo[g].frame = (int)getlong(track);
track+=4;
unsigned short flag = getshort(track);
tcb_info(flag);
track = fill_tcbee(flag, track+2, &keyinfo[g]);
float x = getfloat(track);
float y = getfloat(track+4);
float z = getfloat(track+8);
keyinfo[g].p = Vector3f(x, y, z);
if (API3DS_TEXT_OUT) cout << " (" << x << ", " << y << ", " << z << ")" << endl;
track+=12;
}
int first_frame = keyinfo[0].frame;
int last_frame = keyinfo[keys-1].frame;
int frames = last_frame-first_frame + 1;
Vector3f *curve = new Vector3f[frames];
Vector3f t1, t2;
int k = 0;
for(int g=first_frame; g<=last_frame; g++)
{
if(g>(keyinfo[k+1].frame)) {
k++;
}
int d = keyinfo[k+1].frame - keyinfo[k].frame;
double t = (double)(g-keyinfo[k].frame)/(double)d;
t1 = keyinfo.getv(bn, k);
t2 = keyinfo.getv(an, k+1);
float xx = hermite_spline(t, (keyinfo[k].p).x, t1.x, (keyinfo[k+1].p).x, t2.x);
float yy = hermite_spline(t, (keyinfo[k].p).y, t1.y, (keyinfo[k+1].p).y, t2.y);
float zz = hermite_spline(t, (keyinfo[k].p).z, t1.z, (keyinfo[k+1].p).z, t2.z);
curve[g-first_frame] = Vector3f(xx, yy, zz);
}
DvectorLinearFramed<Vector3f, GLfloat> *newtrack = new DvectorLinearFramed<Vector3f, GLfloat>;
newtrack->Frames(allframes, frames, first_frame, last_frame, curve);
return newtrack;
}
GLfloat Loader3DS::roll_track::getv(int sel, int n) {
roll_key *kn_1, *kn, *kn1;
GLfloat *pn_1, *pn, *pn1;
int d1, d2;
kn = &keys[n];
pn = &kn->p;
if (sel == point) return *pn;
if (n == 0) {
//first key
kn1 = &keys[1];
pn1 = &kn1->p;
if (count == 2) {
//2 keys
return (*pn1 - *pn)*(1.0F - kn->tension);
};
if (mode != 3) {
//first key, no loop
return ((*pn1 - *pn)*1.5F - getv(an,1)*0.5F)*(1.0F - kn->tension);
} else {
//first key, loop
kn_1= &keys[count-2];
d1 = keys[count-1].frame - kn_1->frame;
d2 = kn1->frame - kn->frame;
};
} else if (n == count-1) {
//last key
kn_1 = &keys[n-1];
pn_1 = &kn_1->p;
if (count == 2) {
//2 keys
return (*pn - *pn_1)*(1.0F - kn->tension);
};
if (mode != 3) {
//last key, no loop
return ((*pn - *pn_1)*1.5F - getv(bn,n-1)*0.5F)*(1.0F - kn->tension);
} else {
//last key, loop
kn1 = &keys[1];
d1 = kn->frame - kn_1->frame;
d2 = kn1->frame - keys[0].frame;
};
} else {
//middle keys
kn_1= &keys[n-1];
kn1 = &keys[n+1];
d1 = kn->frame - kn_1->frame;
d2 = kn1->frame - kn->frame;
};
pn_1= &kn_1->p;
pn1 = &kn1->p;
float C;
float adjust;
if (sel == an) {
C = kn->continuity;
adjust = d1;
} else {
C = -kn->continuity;
adjust = d2;
};
adjust /= d1 + d2;
adjust = 0.5 + (1.0 - fabs(C))*(adjust - 0.5);
return ( (*pn - *pn_1) * ((1.0F + kn->bias)*(1.0F - C))
+ (*pn1 - *pn ) * ((1.0F - kn->bias)*(1.0F + C))
) * ((1.0F - kn->tension)*adjust);
};
Dynamic<GLfloat, GLfloat>* Loader3DS::process_roll_track(int allframes, int keys, char *track, unsigned short tracktype)
{
if(keys<2)
return 0;
roll_track keyinfo(keys, tracktype&3);
for(int g=0; g<keys; g++)
{
if (API3DS_TEXT_OUT) cout << " Key " << g << ": Frame " << (int)getlong(track) << ".: ";
keyinfo[g].frame = (int)getlong(track);
track+=4;
unsigned short flag = getshort(track);
tcb_info(flag);
track = fill_tcbee(flag, track+2, &keyinfo[g]);
float x = getfloat(track);
keyinfo[g].p = x;
if (API3DS_TEXT_OUT) cout << " " << x << endl;
track+=4;
}
int first_frame = keyinfo[0].frame;
int last_frame = keyinfo[keys-1].frame;
int frames = last_frame-first_frame + 1;
GLfloat *curve = new GLfloat[frames];
GLfloat t1, t2;
int k = 0;
for(int g=first_frame; g<=last_frame; g++)
{
if(g>(keyinfo[k+1].frame)) {
k++;
}
int d = keyinfo[k+1].frame - keyinfo[k].frame;
double t = (double)(g-keyinfo[k].frame)/(double)d;
t1 = keyinfo.getv(bn, k);
t2 = keyinfo.getv(an, k+1);
float xx = hermite_spline(t, keyinfo[k].p, t1, keyinfo[k+1].p, t2);
curve[g-first_frame] = xx;
}
DvectorLinearFramed<GLfloat, GLfloat> *newtrack = new DvectorLinearFramed<GLfloat, GLfloat>;
newtrack->Frames(allframes, frames, first_frame, last_frame, curve);
return newtrack;
}