Rev 1 | Blame | Compare with Previous | Last modification | View Log | RSS feed
#include "bob_dom_bob.h"
#include "bob_stream_operators.h"
//---------------------------------------------------------------------------------
// BOB file
bool bob_dom_bob::load(ibinaryfilestream& is)
{
int hdr;
is >> hdr;
if(hdr!=HDR_BEGIN){
error(e_badHeader);
return false;
}
if(peek(is)==bob_info::HDR_BEGIN){
if(!info.load(is)){
for(ErrorIterator &it=info.errors.begin(); it!=info.errors.end(); ++it){
error(it->code, "info: %s", it->text);
}
return false;
}
}
if(materials.load(is)==false){
for(ErrorIterator &it=materials.errors.begin(); it!=materials.errors.end(); ++it){
error(it->code, "materials->%s", it->text);
return false;
}
}
if(bodies.load(is)==false){
for(ErrorIterator &it=bodies.errors.begin(); it!=bodies.errors.end(); ++it){
error(it->code, "bodies->%s", it->text);
}
return false;
}
is >> hdr;
if(hdr!=HDR_END)
error(e_badEndHeader);
return(hdr==HDR_END && !is.fail());
}
//---------------------------------------------------------------------------------
bool bob_dom_bob::toFile(obinaryfilestream& os)
{
os << HDR_BEGIN;
info.toFile(os);
materials.toFile(os);
bodies.toFile(os);
os << HDR_END;
return os.good();
}
//---------------------------------------------------------------------------------
bool bob_dom_bob::toFile(otextfilestream& os)
{
info.toFile(os);
os << endl;
materials.toFile(os);
if(materials.size())
os << endl;
if(bodies.toFile(os, *m_settings, &materials)==false){
for(bob_bodies::ErrorIterator &e_it=bodies.errors.begin(); e_it!=bodies.errors.end(); ++e_it){
error(e_it->severity, e_it->code, "Bodies->%s", e_it->text);
}
return false;
}
return os.good();
}
//---------------------------------------------------------------------------------
// MATERIAL - object
bool bob_material1::load(ibinaryfilestream& is)
{
is >> index;
is >> textureID; // int?
is >> ambient;
is >> diffuse;
is >> specular;
errorCode=is.fail() ? e_notEnoughData : e_noError;
return !is.fail();
}
//---------------------------------------------------------------------------------
bool bob_material1::toFile(obinaryfilestream& os)
{
os << index << textureID << ambient << diffuse << specular;
return os.good();
}
//---------------------------------------------------------------------------------
bool bob_material1::toFile(otextfilestream& os)
{
os << noSemicolons << "MATERIAL";
switch(type){
case mat3:
os << '3';
break;
case mat5:
os << '5';
break;
}
os << ": " << autoSemicolons;
os << index << textureID;
os << ambient << diffuse << specular;
return os.good();
}
//---------------------------------------------------------------------------------
// MATERIAL 3 - object
bool bob_material3::load(ibinaryfilestream& is)
{
base::load(is);
if(type > mat1){
is >> transparency; // int?
is >> selfIllumination;
is >> shininess;
short s;
is >> s;
destinationBlend = (s & 0x2) > 0;
twoSided = (s & 0x10) > 0;
wireframe = (s & 0x8) > 0;
is >> textureValue;
is >> enviromentMap;
is >> bumpMap;
}
errorCode=is.fail() ? e_notEnoughData : e_noError;
return !is.fail();
}
//---------------------------------------------------------------------------------
bool bob_material3::toFile(obinaryfilestream& os)
{
base::toFile(os);
os << transparency << selfIllumination << shininess;
short s=0;
if(destinationBlend) s|=0x2;
if(twoSided) s|=0x10;
if(wireframe) s|=0x8;
os << s;
os << textureValue << enviromentMap << bumpMap;
return os.good();
}
//---------------------------------------------------------------------------------
bool bob_material3::toFile(otextfilestream& os)
{
base::toFile(os);
os << autoSemicolons;
os << transparency << selfIllumination << shininess;
os << noSemicolons << destinationBlend << ';' << twoSided << ';' << autoSemicolons << wireframe;
os << textureValue;
os << enviromentMap << bumpMap;
return os.good();
}
//---------------------------------------------------------------------------------
// MATERIAL5
bool bob_material5::load(ibinaryfilestream& is)
{
base::load(is);
if(type > mat3)
is >> lightMap;
errorCode=is.fail() ? e_notEnoughData : e_noError;
return !is.fail();
}
//---------------------------------------------------------------------------------
bool bob_material5::toFile(obinaryfilestream& os)
{
base::toFile(os);
os << lightMap;
return os.good();
}
//---------------------------------------------------------------------------------
bool bob_material5::toFile(otextfilestream& os)
{
base::toFile(os);
if(type > mat3)
os << autoSemicolons << lightMap;
return os.good();
}
//---------------------------------------------------------------------------------
char * material6_value::m_stringTypes[]={
"SPTYPE_LONG",
"SPTYPE_BOOL",
"SPTYPE_FLOAT",
"",
"",
"SPTYPE_FLOAT4",
"",
"",
"SPTYPE_STRING"
};
int material6_value::m_stringTypesCount=9;
bob_error_codes material6_value::load(ibinaryfilestream &is)
{
is >> name;
if(is.fail()) return e_error;
short t;
is >> t;
type=(Type)t;
switch(type){
case typeBool: // no break
case typeLong:
is >> val.i;
break;
case typeFloat:
is >> val.f;
break;
case typeFloat4:
is >> val.f4;
break;
case typeString:
is >> val.psz;
break;
default:
return e_unkMaterialValueType;
}
return is.fail() ? e_error : e_noError;
}
//---------------------------------------------------------------------------------
bool material6_value::toFile(obinaryfilestream& os)
{
os << name << (short) type;
switch(type){
case typeBool: // no break
case typeLong:
os << val.i;
break;
case typeFloat:
os << val.f;
break;
case typeFloat4:
os << val.f4;
break;
case typeString:
os << val.psz;
break;
default:
return false;
}
return os.good();
}
//---------------------------------------------------------------------------------
bool material6_value::toFile(otextfilestream& os)
{
int old=os.flags();
os << noSemicolons << name << ';';
os << typeName() << ';';
switch(type){
case typeLong:
os << val.i << ';';
break;
case typeBool:
os << val.i << ';';
break;
case typeFloat:
os << val.f << ';';
break;
case typeFloat4:
for(int i=0; i < 4; i++){
os << val.f4.f[i] << ';';
}
break;
case typeString:
os << val.psz << ';';
break;
default:
return false;
}
os << ' ';
os.flags(old);
return os.good();
}
//---------------------------------------------------------------------------------
// MATERIAL6_VALUES
bob_error_codes bob_material6_values::load(ibinaryfilestream& is)
{
short count;
material6_value *v;
bob_error_codes res;
is >> count;
for(int i=0; i < count; i++){
v=new material6_value();
if((res=v->load(is))!=e_noError) {
delete v;
return res;
}
push_back(v);
}
return is.fail() ? e_error : e_noError;
}
//---------------------------------------------------------------------------------
bool bob_material6_values::toFile(obinaryfilestream& os)
{
os << (short)size();
for(iterator &it=begin(); it!=end(); ++it){
it->toFile(os);
}
return os.good();
}
//---------------------------------------------------------------------------------
bool bob_material6_values::toFile(otextfilestream& os)
{
os << (int)size();
for(iterator &it=begin(); it!=end(); ++it){
it->toFile(os);
}
return os.good();
}
//---------------------------------------------------------------------------------
// MATERIAL6 - big
bob_error_codes bob_material6::Big::load(ibinaryfilestream& is)
{
bob_error_codes errorCode;
is >> technique >> effect;
errorCode=values.load(is);
return errorCode;
}
//---------------------------------------------------------------------------------
bool bob_material6::Big::toFile(obinaryfilestream& os)
{
os << technique << effect;
values.toFile(os);
return os.good();
}
//---------------------------------------------------------------------------------
bool bob_material6::Big::toFile(otextfilestream& os)
{
int old=os.flags();
os << autoSemicolons << technique << effect;
values.toFile(os);
os.flags(old);
return os.good();
}
//---------------------------------------------------------------------------------
// MATERIAL 6 - small
bob_error_codes bob_material6::Small::load(ibinaryfilestream& is, int flags)
{
is >> textureFile;
is >> ambient >> diffuse >> specular;
is >> transparency >> selfIllumination >> shininess;
short s=flags;
//is >> s;
destinationBlend = (s & 0x2) > 0;
twoSided = (s & 0x10) > 0;
wireframe = (s & 0x8) > 0;
is >> textureValue >> enviromentMap >> bumpMap >> lightMap;
is >> map4 >> map5;
return !is.fail() ? e_noError : e_notEnoughData;
}
//---------------------------------------------------------------------------------
bool bob_material6::Small::toFile(obinaryfilestream& os)
{
static char *empty="";
os << (textureFile ? textureFile : empty);
os << ambient << diffuse << specular;
os << transparency << selfIllumination << shininess;
os << textureValue << enviromentMap << bumpMap << lightMap;
os << map4 << map5;
return os.good();
}
//---------------------------------------------------------------------------------
bool bob_material6::Small::toFile(otextfilestream& os)
{
os << (*textureFile==0 ? "NULL" : textureFile);
os << ambient << diffuse << specular;
os << transparency << selfIllumination << shininess;
os << noSemicolons << destinationBlend << ';' << twoSided << ';' << autoSemicolons << wireframe;
os << textureValue;
os << enviromentMap << bumpMap << lightMap << map4 << map5;
return os.good();
}
//---------------------------------------------------------------------------------
// MATERIAL 6
bool bob_material6::load(ibinaryfilestream& is)
{
is >> index;
is >> flags;
if(flags==Big::flag) {
big=new Big();
errorCode=big->load(is);
}
else{
/*FILE *f=fopen("d:\\mat56.log", "a+");
fprintf(f, "%s - flags: %d, offset 0x%x\n", is.name(), flags, is.tell());
fclose(f);
*/
small=new Small();
errorCode=small->load(is, flags);
}
return errorCode==e_noError;
}
//---------------------------------------------------------------------------------
bool bob_material6::toFile(obinaryfilestream& os)
{
bool bRes;
os << index << flags;
if(big)
bRes=big->toFile(os);
else
bRes=small->toFile(os);
return bRes;
}
//---------------------------------------------------------------------------------
bool bob_material6::toFile(otextfilestream& os)
{
int old=os.flags();
os << noSemicolons << "MATERIAL6: "
<< autoSemicolons << index << noSemicolons << "0x" << hex << autoSemicolons << flags << dec;
if(big)
big->toFile(os);
else if(small)
small->toFile(os);
os.flags(old);
return os.good();
}
//---------------------------------------------------------------------------------
// MATERIAL - section
bool bob_materials::load(ibinaryfilestream& is)
{
int hdr;
bob_material::materialType type;
is >> hdr;
switch(hdr){
case HDR_MAT5_BEGIN:
type=bob_material::mat5;
break;
case HDR_MAT6_BEGIN:
type=bob_material::mat6;
break;
default:
error(e_badHeader);
return false;
}
int matCount;
is >> matCount;
bob_material *m;
for(int i=0; i < matCount; i++){
switch(type) {
case bob_material::mat5:
m=new bob_material5();
break;
case bob_material::mat6:
m=new bob_material6();
break;
}
if(m->load(is)==false){
error(m->errorCode, "material[%d]: %s", i, bob_traslate_error(m->errorCode));
delete m;
return false;
}
else
push_back(m);
}
is >> hdr;
if(hdr!=HDR_END)
error(e_badEndHeader);
return (hdr==HDR_END && !is.fail());
}
//---------------------------------------------------------------------------------
bool bob_materials::toFile(obinaryfilestream& os)
{
int hdr;
if(size() && front()->type==bob_material::mat6)
hdr=HDR_MAT6_BEGIN;
else
hdr=HDR_MAT5_BEGIN;
os << hdr << (int)size();
for(iterator &it=begin(); it!=end(); ++it){
it->toFile(os);
}
os << HDR_END;
return os.good();
}
//---------------------------------------------------------------------------------
bool bob_materials::toFile(otextfilestream& os)
{
for(iterator &it=begin(); it!=end(); ++it){
it->toFile(os);
os << endl;
}
return os.good();
}
//---------------------------------------------------------------------------------
// BODIES - section
bool bob_bodies::load(ibinaryfilestream& is)
{
int hdr;
is >> hdr;
if(hdr!=HDR_BEGIN){
error(e_badHeader);
return false;
}
short bodyCount;
is >> bodyCount;
child_type *ch;
for(int i=0; i < bodyCount; i++){
ch=createChild();
if(ch->load(is)==false){
for(ErrorIterator &it=ch->errors.begin(); it!=ch->errors.end(); ++it){
error(it->code, "body[%d]->%s", i, it->text);
}
return false;
}
}
is >> hdr;
if(is.fail())
error(e_notEnoughData);
if(hdr!=HDR_END)
error(e_badEndHeader);
return hdr==HDR_END;
}
//---------------------------------------------------------------------------------
bool bob_bodies::toFile(obinaryfilestream& os)
{
os << HDR_BEGIN << (short)size();
for(iterator &it=begin(); it!=end(); ++it){
it->toFile(os);
}
os << HDR_END;
return os.good();
}
//---------------------------------------------------------------------------------
bool bob_bodies::toFile(otextfilestream& os, const Settings& settings, const bob_materials *materials)
{
int i=1;
os << noSemicolons << "// beginning of bodies (" << (int)size() << ')' << endl;
for(iterator &it=begin(); it!=end(); ++it, ++i){
if(it->toFile(os, settings, materials, i)==false){
for(bob_body::ErrorIterator &e_it=it->errors.begin(); e_it!=it->errors.end(); ++e_it){
error(e_it->severity, e_it->code, "Body[%d]->%s", i, e_it->text);
}
return false;
}
os << endl;
}
os << "// end of bodies" << endl;
return os.good();
}
//---------------------------------------------------------------------------------
// POINTS - section
bool bob_vertices::load(ibinaryfilestream& is)
{
int hdr;
is >> hdr;
if(hdr!=HDR_BEGIN){
error(e_badHeader);
return false;
}
int pointCount;
is >> pointCount;
map.create(pointCount);
bob_vertex *ch;
for(int i=0; i < pointCount; i++){
ch=new bob_vertex();
if(ch->load(is)==false){
error(ch->errorCode, "point[%d]: %s", i, bob_traslate_error(ch->errorCode));
delete ch;
return false;
}
map.addPoint(ch);
}
is >> hdr;
if(hdr!=HDR_END)
error(e_badEndHeader);
return hdr==HDR_END && !is.fail();
}
//---------------------------------------------------------------------------------
bool bob_vertices::toFile(obinaryfilestream& os)
{
os << HDR_BEGIN;
if(new_vertices.size()){
os << (int)new_vertices.size();
for(VertexIterator &it=new_vertices.begin(); it!=new_vertices.end(); ++it){
it->toFile(os);
}
}
else{
os << (int)map.pointsSize();
for(bob_point_map::iterator &it=map.begin(); it!=map.end(); ++it){
it->toFile(os);
}
}
os << HDR_END;
return os.good();
}
//---------------------------------------------------------------------------------
bool bob_vertices::toFile(otextfilestream& os, const Settings& settings)
{
if(settings.rawMode())
return outputRaw(os);
else
return outputBOD(os);
}
//---------------------------------------------------------------------------------
bool bob_vertices::outputBOD(otextfilestream& os)
{
int oldf=os.flags();
int i=0;
os << noSemicolons << "// beginning of points (" << (int)map.uniquePointsSize() << ')' << endl << autoSemicolons;
bob_vertex *p;
while(p=map.nextUniquePoint()){
p->toFile(os, i++);
}
os << noSemicolons << "-1; -1; -1; // points end" << endl << endl;
os.flags(oldf);
return os.good();
}
//---------------------------------------------------------------------------------
bool bob_vertices::outputRaw(otextfilestream& os)
{
int oldf=os.flags();
int i=0;
os << noSemicolons << "// Vertices begin (" << (int)map.pointsSize() << " - " << (int)map.uniquePointsSize() << " unique)" << endl << autoSemicolons;
for(bob_point_map::iterator &it=map.begin(); it!=map.end(); ++it, i++){
os << autoSemicolons
<< it->x << it->y << it->z;
if(it->hasTextureCoords()){
os << noSemicolons << "\t\tUV: " << autoSemicolons
<< it->textureCoords.x << it->textureCoords.y;
}
if(it->flags & bob_vertex::FLAG_WEIRD_STUFF){
os << noSemicolons << "\tWeird coords: " << autoSemicolons
<< it->weirdCoords.x << it->weirdCoords.y;
}
os << noSemicolons << "\tNormal: " << autoSemicolons
<< it->normalVector.x << it->normalVector.y << it->normalVector.z
<< noSemicolons << "\tSGBits: " << it->sgbits;
os << noSemicolons << " // " << i << endl;
}
os << noSemicolons << "-1; -1; -1; // Vertices end" << endl << endl;
os.flags(oldf);
return os.good();
}
//---------------------------------------------------------------------------------
// POINT - object
bool bob_vertex::load(ibinaryfilestream& is)
{
/*
possible types
0x1F - normal + UV + 2 unk values
0x1B - normal + UV
0x19 - normal
*/
is >> flags >> *(vertex*)this;
if((flags & FLAG_DEFAULT)!=FLAG_DEFAULT){
errorCode=e_unkPointFlags;
return false;
}
if(hasTextureCoords())
is >> textureCoords;
if(flags & FLAG_WEIRD_STUFF)
is >> weirdCoords;
is >> normalVector >> sgbits;
if(is.fail())
errorCode=e_notEnoughData;
return !is.fail();
}
//---------------------------------------------------------------------------------
bool bob_vertex::toFile(obinaryfilestream& os)
{
// set the default bits before outputting
flags|=FLAG_DEFAULT;
os << flags << *(dynamic_cast<vertex*>(this));
if(hasTextureCoords())
os << textureCoords;
if(flags & FLAG_WEIRD_STUFF)
os << weirdCoords;
os << normalVector << sgbits;
return os.good();
}
//---------------------------------------------------------------------------------
bool bob_vertex::toFile(otextfilestream& os, int idx)
{
// autoSemicolons is set by parent (points)
int coords[3];
getBodCoords(coords);
os << coords[0] << coords[1] << coords[2];
os << noSemicolons << "// " << idx << endl << autoSemicolons;
return os.good();
}
//---------------------------------------------------------------------------------
// X3 vertex_data_record
bool bob_x3vertex_data_record::load(ibinaryfilestream& is)
{
is >> pointIndex >> tangent >> unk;
return !is.fail();
}
//---------------------------------------------------------------------------------
bool bob_x3vertex_data_record::toFile(obinaryfilestream& os)
{
os << pointIndex << tangent << unk;
return os.good();
}
//---------------------------------------------------------------------------------
/*int compare_x3vertex_rec(const void *a, const void *b)
{
const bob_x3vertex_data_record *rec1=*((bob_x3vertex_data_record**)a), *rec2=*((bob_x3vertex_data_record**)b);
return rec1->pointIndex - rec2->pointIndex;
}*/
//---------------------------------------------------------------------------------
// X3 uv list
bool bob_x3vertex_data::load(ibinaryfilestream& is)
{
int count;
bob_x3vertex_data_record *rec;
is >> count;
reserve(count);
for(int i=0; i < count; i++){
rec=new bob_x3vertex_data_record();
if(!rec->load(is)){
delete rec;
return false;
}
push_back(rec);
}
/*
there should never be the need to compare the data, because they are written in the order of vertices,
and thus their vertex indexes are always in sequence
*/
//sort(compare_x3vertex_rec);
return !is.fail();
}
//---------------------------------------------------------------------------------
bool bob_x3vertex_data::toFile(obinaryfilestream& os)
{
os << (int) size();
for(iterator &it=begin(); it!=end(); ++it){
it->toFile(os);
}
return os.good();
}
//---------------------------------------------------------------------------------
// FACE LIST
bool bob_face_list::load(ibinaryfilestream& is, bool x3data)
{
int count;
is >> materialIndex >> count;
for(int i=0; i < count; i++){
bob_face *face=new bob_face();
if(face->load(is)==false){
error(face->errorCode, "face[%d]: %s", i, bob_traslate_error(face->errorCode));
delete face;
return false;
}
push_back(face);
}
if(x3data && x3vertexData.load(is)==false) return false;
return !is.fail();
}
//---------------------------------------------------------------------------------
bool bob_face_list::toFile(obinaryfilestream& os, const bob_vertices& vertices, bool x3data)
{
os << materialIndex << (int)size();
for(iterator &it=begin(); it!=end(); ++it){
it->toFile(os);
}
if(x3data)
saveVertexTangents(os, vertices);
return os.good();
}
//---------------------------------------------------------------------------------
bool bob_face_list::saveVertexTangents(obinaryfilestream& os, const bob_vertices& vertices)
{
// the still unknown God damned vector
vector vec1(0,0,1); // default value
vector vec0(0,0,0); // zero value
bool *vert_map=new bool[vertices.new_vertices.size()];
memset(vert_map, 0, vertices.new_vertices.size() * sizeof(bool));
size_t count_pos=os.tell();
os << 123; // dummy count
int idx, count=0;
for(iterator &it=begin(); it!=end(); ++it){
for(int i=0; i < 3; i++){
idx=it->values[i];
if(vert_map[idx]==false) {
vector &tan=vertices.new_vertices[idx]->tangentVector;
os << idx << tan << (tan.isZero() ? vec0 : vec1);
vert_map[idx]=true;
count++;
}
}
}
delete[] vert_map;
// write the real count
size_t lastp=os.tell();
os.seek((int)count_pos, mystream::stream_base::seek_begin);
os << count;
os.seek((int)lastp, mystream::stream_base::seek_begin);
return os.good();
}
//---------------------------------------------------------------------------------
bool bob_face_list::outputX3VertexDataRaw(otextfilestream& os)
{
if(x3vertexData.size()==0) return true;
int old=os.flags();
os << noSemicolons << "// Material " << materialIndex << endl;
os << "// Material; point index; tangent; unknown" << endl << autoSemicolons;
for(bob_x3vertex_data::const_iterator &it=x3vertexData.begin(); it!=x3vertexData.end(); ++it){
os << materialIndex << it->pointIndex << it->tangent << it->unk << endl;
}
os << endl;
os.flags(old);
return os.good();
}
//---------------------------------------------------------------------------------
/*
bool bob_face_list::computeAndOutputTangents(otextfilestream& os, const bob_point_map& pointMap)
{
vertex v1, v2, v3;
geometry::point2d<double> w1,w2,w3;
int i1,i2,i3;
vector *tan1, *tan2;
tan1=new vector[pointMap.pointsSize() * 2];
tan2=tan1 + pointMap.pointsSize();
for(iterator &it=begin(); it!=end(); ++it){
i1=it->values[0]; i2=it->values[1]; i3=it->values[2];
v1=*pointMap[i1];
v2=*pointMap[i2];
v3=*pointMap[i3];
w1=pointMap[i1]->textureCoords;
w2=pointMap[i2]->textureCoords;
w3=pointMap[i3]->textureCoords;
double x1 = v2.x - v1.x;
double x2 = v3.x - v1.x;
double y1 = v2.y - v1.y;
double y2 = v3.y - v1.y;
double z1 = v2.z - v1.z;
double z2 = v3.z - v1.z;
double s1 = w2.x - w1.x;
double s2 = w3.x - w1.x;
double t1 = w2.y - w1.y;
double t2 = w3.y - w1.y;
double cp=s1 * t2 - s2 * t1;
if(cp!=0) {
double r = 1.0 / cp;
vector sdir((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r,
(t2 * z1 - t1 * z2) * r);
vector tdir((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r,
(s1 * z2 - s2 * z1) * r);
tan1[i1] += sdir;
tan1[i2] += sdir;
tan1[i3] += sdir;
tan2[i1] += tdir;
tan2[i2] += tdir;
tan2[i3] += tdir;
}
}
int oldf=os.flags();
os << noSemicolons << "// vertex tangents" << autoSemicolons << endl;
int i=0;
for(bob_point_map::const_iterator &it=pointMap.begin(); it!=pointMap.end(); ++it, i++){
const vector& n=it->normalVector;
const vector& t=tan1[i];
const vector& bt=tan2[i];
// Gram-Schmidt orthogonalize
vector tangent = (t - n * n.dot(t)).normalize();
os << i << tangent << endl;
}
delete[] tan1;
os.flags(oldf);
return os.good();
}*/
//---------------------------------------------------------------------------------
// PARTS - section PART
bool bob_parts::load(ibinaryfilestream& is)
{
int hdr, count;
is >> hdr;
if(hdr!=HDR_BEGIN){
error(e_badHeader);
return false;
}
is >> count;
bob_part *part;
for(int i=0; i < count; i++){
part=new bob_part();
if(!part->load(is)){
for(ErrorIterator &it=part->errors.begin(); it!=part->errors.end(); ++it){
error(it->severity, it->code, "part[%d]->%s", i, it->text);
}
delete part;
return false;
}
push_back(part);
}
is >> hdr;
if(hdr!=HDR_END)
error(e_badEndHeader);
return hdr==HDR_END && !is.fail();
}
//---------------------------------------------------------------------------------
bool bob_parts::toFile(obinaryfilestream& os, const bob_vertices& vertices)
{
os << HDR_BEGIN << (int) size();
for(iterator &it=begin(); it!=end(); ++it){
it->toFile(os, vertices);
}
os << HDR_END;
return os.good();
}
//---------------------------------------------------------------------------------
bool bob_parts::toFile(otextfilestream& os, const Settings& settings, const bob_materials *materials, const bob_point_map *pointMap)
{
int i=1;
for(iterator &it=begin(); it!=end(); ++it, ++i){
if(it->toFile(os, settings, materials, *pointMap, i)==false){
for(bob_part::ErrorIterator &e_it=it->errors.begin(); e_it!=it->errors.end(); ++e_it){
error(e_it->severity, e_it->code, "Part[%d]->%s", i, e_it->text);
}
return false;
}
}
return os.good();
}
//---------------------------------------------------------------------------------
bool bob_part_collision_box::load(ibinaryfilestream& is)
{
is >> sphereOffset >> sphereDiameter;
is >> boxOffset >> boxSize;
return !is.fail();
}
//---------------------------------------------------------------------------------
bool bob_part_collision_box::toFile(obinaryfilestream& os)
{
os << sphereOffset << sphereDiameter;
os << boxOffset << boxSize;
return os.good();
}
//---------------------------------------------------------------------------------
bool bob_part_collision_box::toFile(otextfilestream& os)
{
int old=os.flags();
os << noSemicolons;
os << "/! COLLISION_BOX: " << autoSemicolons;
os << boxOffset.x << boxOffset.y << boxOffset.z;
os << sphereDiameter << boxSize.x << boxSize.y << boxSize.z;
os << noSemicolons << "!/" << autoSemicolons << endl;
os.flags(old);
return os.good();
}
//---------------------------------------------------------------------------------
// PARTS - object
bool bob_part::load(ibinaryfilestream& is)
{
short count;
is >> flags >> count;
for(int i=0; i < count; i++){
bob_face_list *faces=new bob_face_list();
if(faces->load(is, (flags & FLAG_X3) > 0)==false){
for(ErrorIterator &it=faces->errors.begin(); it!=faces->errors.end(); ++it){
error(it->severity, it->code, "face list[%d]->%s", i, it->text);
}
delete faces;
return false;
}
push_back(faces);
}
if(flags & FLAG_X3)
collisionBox.load(is);
return !is.fail();
}
//---------------------------------------------------------------------------------
bool bob_part::toFile(obinaryfilestream& os, const bob_vertices& vertices)
{
os << flags << (short)size();
for(iterator &it=begin(); it!=end(); ++it){
it->toFile(os, vertices, (flags & FLAG_X3) > 0);
}
if(flags & FLAG_X3)
collisionBox.toFile(os);
return os.good();
}
//---------------------------------------------------------------------------------
bool bob_part::toFile(otextfilestream& os, const Settings& settings, const bob_materials *materials, const bob_point_map& pointMap, int idx)
{
if(settings.rawMode())
return outputRaw(os, pointMap, idx);
else
return outputBOD(os, settings, materials, pointMap, idx);
}
//---------------------------------------------------------------------------------
bool bob_part::outputBOD(otextfilestream& os, const Settings& settings, const bob_materials *materials, const bob_point_map& pointMap, int idx)
{
bob_face *face;
const bob_vertex *pnt;
int line=0;
int materialIndex;
int oldf=os.flags();
os << noSemicolons << "// ----- part " << idx << " (" << (int)numFaces() << " faces) -----" << endl << autoSemicolons;
for(iterator &facelist_it=begin(); facelist_it!=end(); ++facelist_it){
materialIndex=facelist_it->materialIndex;
for(bob_face_list::iterator &face_it=facelist_it->begin(); face_it!=facelist_it->end(); ++face_it, ++line){
face=*face_it;
os << autoSemicolons << materialIndex;
for(int i=0; i < 3; i++){
os << pointMap.uniqueIndex(face->values[i]);
}
pnt=pointMap[face->values[0]];
if(pnt==NULL){
error(e_pointNotFound);
return false;
}
int SGBits=pnt->sgbits;
int magic = 1; // bit 1 is always set
/*
meaning of "magic" number:
-25: smoothing bits and UV coords
-17: smoothing bits and no UV coords
-9: no smoothing and UV coords
-1: no smoothing and no UV coords
--obsolete----------------------
old text from Checker's sources:
if there are no materials used, magic is -17
if there are materials and last value of the first point is non zero,
magic is -25, otherwise it's -9
*/
const bob_vertex *points_ar[3];
for(int i=0; i < 3; i++){
pnt=pointMap[face->values[i]];
if(pnt==NULL){
error(e_pointNotFound);
return false;
}
points_ar[i]=pnt;
}
bool bHasUV=false;
for(int i=0; i < 3; i++){
if(bHasUV=points_ar[i]->hasTextureCoords())
break;
}
if(bHasUV)
magic|=BOD_FLAG_UV;
if(SGBits)
magic|=BOD_FLAG_SGBITS;
os << (magic * -1);
if(SGBits!=0)
os << SGBits;
// we have uv coords, lets output them
if(bHasUV){
for(int i=0; i < 3; i++){
os << points_ar[i]->textureCoords; // correct output
}
os << noSemicolons << "/! ";
outputNormals(os, points_ar);
if(settings.extraPntInfo())
outputExtraPtInfo(os, points_ar);
os << noSemicolons << "!/ ";
}
os << noSemicolons << "// " << line << endl;
}
}
// x3 data
if(flags & FLAG_X3){
collisionBox.toFile(os);
}
int bit=1;
char str[21];
for(int i=19; i >= 0; i--){
str[i]=flags & bit ? '1' : '0';
bit<<=1;
}
str[sizeof(str)-1]=0;
os << autoSemicolons << "-99" << str << noSemicolons << "// part " << idx << " end" << endl;
os.flags(oldf);
return os.good();
}
//---------------------------------------------------------------------------------
bool bob_part::outputX3VertexData(otextfilestream& os, const bob_point_map& pointMap)
{
int old=os.flags();
os << endl << noSemicolons
<< "// X3 vertex data (tangent and <unknown>)" << endl
<< autoSemicolons;
int i=1;
for(iterator &facelist_it=begin(); facelist_it!=end(); ++facelist_it, i++){
facelist_it->outputX3VertexDataRaw(os);
//facelist_it->computeAndOutputTangents(os, pointMap);
}
os.flags(old);
return true;
}
//---------------------------------------------------------------------------------
void bob_part::outputNormals(otextfilestream& os, const bob_vertex *points[])
{
int oldf=os.flags();
bool bSame=true;
for(int i=1; i < 3; i++){
bSame&=points[i]->normalVector == points[i - 1]->normalVector;
}
os << noSemicolons << "N: { " << autoSemicolons;
for(int i=0; i < (bSame ? 1 : 3); i++){
os << points[i]->normalVector;
}
os << noSemicolons << "} ";
os.flags(oldf);
}
//---------------------------------------------------------------------------------
// those are the unknown values stored in point after texture coordinates
// I place them after bod part definition and behind comment, so they are invisible to
// bod viewer and x2
void bob_part::outputExtraPtInfo(otextfilestream& os, const bob_vertex *points[])
{
int oldf=os.flags();
bool bInfo=false;
for(int i=0; i < 3; i++){
bInfo|=(points[i]->flags & bob_vertex::FLAG_WEIRD_STUFF) > 0;
}
if(bInfo==false) return;
os << noSemicolons << "XPINFO: ";
for(int i=0; i < 3; i++){
os << noSemicolons << "{ " << autoSemicolons
<< points[i]->weirdCoords
<< noSemicolons << "} ";
}
os.flags(oldf);
}
//---------------------------------------------------------------------------------
// PART - object
bool bob_face::load(ibinaryfilestream& is)
{
for(int i=0; i < 3; i++){
is >> values[i];
}
is >> flags;
if(is.fail())
errorCode=e_notEnoughData;
return !is.fail();
}
//---------------------------------------------------------------------------------
bool bob_face::toFile(obinaryfilestream& os)
{
for(int i=0; i < 3; i++){
os << values[i];
}
os << flags;
return os.good();
}
//---------------------------------------------------------------------------------
bool bob_body::load(ibinaryfilestream& is)
{
is >> bodySize >> bodyFlags;
if(peek(is)==bob_bones::HDR_BEGIN){
if(!bones.load(is)){
for(ErrorIterator &it=bones.errors.begin(); it!=bones.errors.end(); ++it){
error(it->code, "bones: %s", it->text);
}
return false;
}
}
if(peek(is)==bob_vertices::HDR_BEGIN){
if(vertices.load(is)==false){
for(ErrorIterator &it=vertices.errors.begin(); it!=vertices.errors.end(); ++it){
error(it->code, "vertices->%s", it->text);
}
return false;
}
}
if(peek(is)==bob_weights::HDR_BEGIN){
if(!weights.load(is)){
for(ErrorIterator &it=weights.errors.begin(); it!=weights.errors.end(); ++it){
error(it->code, "weights->%s", it->text);
}
return false;
}
}
if(peek(is)==bob_parts::HDR_BEGIN){
if(parts.load(is)==false){
for(ErrorIterator &it=parts.errors.begin(); it!=parts.errors.end(); ++it){
error(it->code, "parts->%s", it->text);
}
return false;
}
}
return !is.fail();
}
//---------------------------------------------------------------------------------
bool bob_body::toFile(obinaryfilestream& os)
{
os << bodySize << bodyFlags;
bones.toFile(os);
vertices.toFile(os);
weights.toFile(os);
parts.toFile(os, vertices);
return os.good();
}
//---------------------------------------------------------------------------------
bool bob_body::toFile(otextfilestream& os, const Settings& settings, const bob_materials *materials, int idx)
{
os << "// beginning of body " << idx << endl;
os << autoSemicolons << bodySize << endl << endl;
bones.toFile(os);
vertices.toFile(os, settings);
weights.toFile(os, &vertices.map);
if(parts.toFile(os, settings, materials, &vertices.map)==false){
for(bob_parts::ErrorIterator &e_it=parts.errors.begin(); e_it!=parts.errors.end(); ++e_it){
error(e_it->severity, e_it->code, "Parts->%s", e_it->text);
}
return false;
}
char str[17]; int bit=1;
for(int i=15; i >= 0; i--){
str[i]=bodyFlags & bit ? '1' : '0';
bit<<=1;
}
str[sizeof(str)-1]=0;
os << "-99" << str << noSemicolons << "// body " << idx << " end" << endl;
return os.good();
}
//---------------------------------------------------------------------------------
// BONES
bool bob_bones::load(ibinaryfilestream& is)
{
int hdr, count;
is >> hdr;
if(hdr!=HDR_BEGIN){
error(e_badHeader);
return false;
}
is >> count;
char *name;
for(int i=0; i < count; i++){
is >> name;
if(name==0){
error(e_notEnoughData);
delete[] name;
return false;
}
push_back(name);
}
is >> hdr;
if(hdr!=HDR_END){
error(e_badEndHeader);
return false;
}
return true;
}
//---------------------------------------------------------------------------------
bool bob_bones::toFile(obinaryfilestream& os)
{
if(size()==0) return true;
os << HDR_BEGIN << (int) size();
for(iterator &it=begin(); it!=end(); ++it){
os << *it;
}
os << HDR_END;
return os.good();
}
//---------------------------------------------------------------------------------
bool bob_bones::toFile(otextfilestream& os)
{
if(size()==0) return true;
os << noSemicolons << "BONES: " << autoSemicolons << (int)size() << endl;
for(iterator &it=begin(); it!=end(); ++it){
os << *it << endl;
}
os << endl;
return os.good();
}
//---------------------------------------------------------------------------------
// WEIGHTS - section
bool bob_weights::load(ibinaryfilestream& is)
{
int hdr;
is >> hdr;
if(hdr!=HDR_BEGIN){
error(e_badHeader);
return false;
}
int count;
is >> count;
resize(count);
bob_weight *ch;
for(int i=0; i < count; i++){
ch=new bob_weight();
if(!ch->load(is)){
error(ch->errorCode, "weight[%d]: %s", i, bob_traslate_error(ch->errorCode));
delete ch;
return false;
}
(*this)[i]=ch;
}
is >> hdr;
if(hdr!=HDR_END){
error(e_badEndHeader);
return false;
}
return true;
}
//---------------------------------------------------------------------------------
bool bob_weights::toFile(obinaryfilestream& os)
{
if(new_weights.size()==0 && size()==0) return true;
os << HDR_BEGIN;
if(new_weights.size()){
os << (int)new_weights.size();
for(WeightList::iterator &it=new_weights.begin(); it!=new_weights.end(); ++it){
it->toFile(os);
}
}
else{
os << (int)size();
for(iterator &it=begin(); it!=end(); ++it){
it->toFile(os);
}
}
os << HDR_END;
return os.good();
}
//---------------------------------------------------------------------------------
bool bob_weights::toFile(otextfilestream& os, const bob_point_map *pointMap)
{
if(size()==0) return true;
os << noSemicolons << "WEIGHTS " << autoSemicolons << (int) pointMap->uniquePointsSize() << endl;
int i=0;
for(bob_point_map::const_index_iterator &it=pointMap->indexBegin(); it!=pointMap->indexEnd(); ++it){
(*this)[*it]->toFile(os, i++);
}
os << autoSemicolons << "-1" << endl << endl;
return os.good();
}
//---------------------------------------------------------------------------------
// WEIGHT - object
bool bob_weight::load(ibinaryfilestream& is)
{
short count;
value v;
is >> count;
for(int i=0; i < count; i++){
is >> v.boneIdx >> v.boneCoefficient;
values.push_back(v);
}
return !is.fail();
}
//---------------------------------------------------------------------------------
bool bob_weight::toFile(obinaryfilestream& os)
{
os << (short) values.size();
value v;
for(iterator &it=values.begin(); it!=values.end(); ++it){
v=*it;
os << v.boneIdx << v.boneCoefficient;
}
return os.good();
}
//---------------------------------------------------------------------------------
bool bob_weight::toFile(otextfilestream& os, int idx)
{
os << autoSemicolons;
for(iterator &it=values.begin(); it!=values.end(); ++it){
(*it).toFile(os);
}
os << noSemicolons << "-1; // " << idx << endl;
return os.good();
}
//---------------------------------------------------------------------------------
bool bob_part::outputRaw(otextfilestream& os, const bob_point_map& pointMap, int idx)
{
int oldf=os.flags();
os << noSemicolons << "// Part " << idx << endl << "// " << (int)numFaces() << " faces" << endl;
for(iterator& facelist_it=begin(); facelist_it!=end(); ++facelist_it){
os << noSemicolons << "// Material " << facelist_it->materialIndex << endl << autoSemicolons;
for(bob_face_list::iterator& face_it=facelist_it->begin(); face_it!=facelist_it->end(); ++face_it){
for(int i=0; i < 3; i++)
os << face_it->values[i];
os << face_it->flags;
os << endl;
}
}
bool bRes = true;
if(flags & FLAG_X3) {
bRes = outputX3VertexData(os, pointMap);
os << noSemicolons << "Collision sphere: offset: " << autoSemicolons << collisionBox.sphereOffset.x << collisionBox.sphereOffset.y << collisionBox.sphereOffset.z << noSemicolons << "diameter: " << autoSemicolons << collisionBox.sphereDiameter << endl;
os << noSemicolons << "Collision box: offset: " << autoSemicolons << collisionBox.boxOffset.x << collisionBox.boxOffset.y << collisionBox.boxOffset.z << noSemicolons << "size: " << autoSemicolons << collisionBox.boxSize.x << collisionBox.boxSize.y << collisionBox.boxSize.z << endl;
}
os.flags(oldf);
return os.good() && bRes;
}
//---------------------------------------------------------------------------------