Subversion Repositories spk

Rev

Rev 1 | Blame | Compare with Previous | Last modification | View Log | RSS feed

#include "bod_bob_parser.h"
#include "../common/strutils.h"
//---------------------------------------------------------------------------------
bool bod_bob_parser::compile(token_stream& is, bob_dom_obinaryfilestream& os, bool bEmbedded)
{
        bob_dom_bob *bob=new bob_dom_bob(m_settings);
        bob=loadBOB(is, bEmbedded);
        if(bob)
                bob->toFile(os);
        delete bob;
        return bob!=NULL;
}
//---------------------------------------------------------------------------------
#define ISMATERIAL(text) ((strcmp(text, "MATERIAL6")==0 || strcmp(text, "MATERIAL5")==0 || \
                          strcmp(text, "MATERIAL3")==0 || strcmp(text, "MATERIAL")==0))

bob_dom_bob * bod_bob_parser::loadBOB(token_stream& is, bool bEmbedded)
{
        token *t;
        bob_dom_bob *bob=new bob_dom_bob(m_settings);
        bool abort=false;
        
        while((t=is.tok()) && t->type==token::t_hdrinfo){
                if(bob->info.text()!=0)
                        error(is.tok(), S_Warning, "Header info already defined, last value will be used");
                bob->info.text(t->text);
                ++is;
        }
        
        // first load material definitions, break on first numeric token
        while((t=is.tok()) && t->type!=token::t_closeBracket){
                if(t->type!=token::t_text){
                        error(t, S_Error, "Unexpected here: '%s'", t->getText());
                        abort=true; break;
                }
                if(isinteger(t->text)) break;
                
                //if(strcmp(t->text, "MATERIAL5")==0 || strcmp(t->text, "MATERIAL3")==0 || strcmp(t->text, "MATERIAL")==0){
                if(ISMATERIAL(t->text)){
                        if(!loadMaterial(bob, is)){
                                abort=true; break;
                        }
                }
                else{
                        error(t, S_Error, "Unexpected here '%s'", t->getText());
                        abort=true; break;
                }
        }
        
        // now load the body definition: body size, points, parts
        if(!abort){
                m_materials=&(bob->materials);
                do{
                        if(abort=(loadBody(bob, is)==false)) break;
                        
                        if(bEmbedded){
                                if(is.tok()==NULL){
                                        error(is.previous(), S_Error, "Unexpected end of document found while loading embedded BOB - do you miss the '}'?");
                                        abort=true; break;
                                }
                                else if(is.tok()->type==token::t_closeBracket)
                                        break;
                        }
                        else if(is.eof())
                                break;
                }
                while(1); // while what? while '}' if embedded or while eof if standalone
        }
        
        if(abort){
                delete bob;
                bob=NULL;
        }
        
        ++is; // advance past the close bracket (if embedded)
        
        // set the bob type (setting from Settings takes precedence)
        /*if(bob){
                switch(m_settings->X3BOB()){
                        case Settings::on:
                                bob->bobType=bobX3;
                                break;
                        case Settings::off:
                                bob->bobType=bobX2;
                                break;
                        default:
                                if(bob->materials.size() && bob->materials.front()->type==bob_dom_material::mat6)
                                        bob->bobType=bobX3;
                                else
                                        bob->bobType=bobX2;
                }       
        }*/
        
        return bob;
}
//---------------------------------------------------------------------------------
bool bod_bob_parser::loadMatRGB(token_stream& is, bob_dom_material5::rgb& rgb)
{
        int vals[3];
        token *t;
        for(int i=0; i < 3; i++){
                t=loadValue(is);
                if(t==NULL) return false;
                if(!isinteger(t->text)){
                        error(t, S_Error, "Expected integer value at position %d in RBG", i);
                        return false;
                }
                vals[i]=atoi(t->text);
        }
        rgb.r=vals[0];
        rgb.g=vals[1];
        rgb.b=vals[2];
        return true;
}
//---------------------------------------------------------------------------------
bool bod_bob_parser::loadMatPair(token_stream& is, bob_dom_material5::pair& pair)
{
        int vals[2];
        
        for(int i=0; i < 2; i++){
                if(!loadIntValue(is, vals + i))
                        return false;
                
        }
        pair.value=vals[0];
        pair.strength=vals[1];
        return true;
}
//---------------------------------------------------------------------------------
bool bod_bob_parser::loadMatPair(token_stream& is, bob_dom_material6::Small::pair& pair)
{
        int i;
        if((pair.texture=loadString(is, "texture name"))==0) return false;
        if(strcmp(pair.texture, "NULL")==0){
                delete pair.texture; pair.texture=0;
        }
        if(loadIntValue(is, &i, "texture strength")==false) return false;
        pair.strength=i;
        return true;
}
//---------------------------------------------------------------------------------
bool bod_bob_parser::checkImmediatePlacement(const bod_bob_parser::token *token1, const bod_bob_parser::token *token2)
{
        if(token1->line!=token2->line || (token1->col + strlen(token1->getText())!=token2->col)){
                error(token2, S_Error, "'%s' must be placed directly after '%s'", token2->getText(), token1->getText());
                return false;
        }
        else
                return true;
}
//---------------------------------------------------------------------------------
bool bod_bob_parser::loadMat(bob_dom_material5 *mat, token_stream &is)
{
        do{
                int i; 
                bob_dom_material5::rgb rgb;
                bob_dom_material5::pair pair;
                
                if(!loadIntValue(is, &i)) break;
                mat->index=i;
                if(!loadIntValue(is, &i)) break;
                mat->textureID=i;
                if(!loadMatRGB(is, rgb)) break;
                mat->ambient=rgb;
                if(!loadMatRGB(is, rgb)) break;
                mat->diffuse=rgb;
                if(!loadMatRGB(is, rgb)) break;
                mat->specular=rgb;
                if(mat->type!=bob_dom_material::mat1) {
                        if(!loadIntValue(is, &i)) break;
                        mat->transparency=i;
                        if(!loadIntValue(is, &i)) break;
                        mat->selfIllumination=i;
                        if(!loadMatPair(is, pair)) break;
                        mat->shininess=pair;
                        if(!loadIntValue(is, &i)) break;
                        mat->destinationBlend=i!=0;
                        if(!loadIntValue(is, &i)) break;
                        mat->twoSided=i!=0;
                        if(!loadIntValue(is, &i)) break;
                        mat->wireframe=i!=0;
                        if(!loadIntValue(is, &i)) break;
                        mat->textureValue=i;
                        if(!loadMatPair(is, pair)) break;
                        mat->enviromentMap=pair;
                        if(!loadMatPair(is, pair)) break;
                        mat->bumpMap=pair;
                        
                        if(mat->type==bob_dom_material::mat5){
                                if(!loadMatPair(is, pair)) break;
                                mat->lightMap=pair;
                        }
                }
                return true;
        }
        while(false);
        return false;
}
//---------------------------------------------------------------------------------
bool bod_bob_parser::loadMat(bob_dom_material6 *mat, token_stream &is)
{
        int i; bool bRes=false;
        do{
                if(!loadIntValue(is, &i)) break;
                        mat->index=i;
                
                if(!loadIntValue(is, &i)) break;
                        mat->flags=i;
                        
                if(mat->flags==bob_dom_material6::Big::flag)
                        bRes=loadMaterial6Big(mat, is);
                else
                        bRes=loadMaterial6Small(mat, is);
        }
        while(false);
        
        return bRes;
}
//---------------------------------------------------------------------------------
bool bod_bob_parser::loadMaterial6Small(bob_dom_material6 *mat, token_stream &is)
{
        int i;
        bob_dom_material1::rgb rgb;
        bob_dom_material1::pair int_pair;
        bob_dom_material6::Small::pair pair;
        
        mat->small=new bob_dom_material6::Small();
        do{
                if((mat->small->textureFile=loadString(is, "texture name: "))==0) break;
                if(strcmp(mat->small->textureFile, "NULL")==0) 
                        { delete[] mat->small->textureFile; mat->small->textureFile=0; }
                if(!loadMatRGB(is, rgb)) break;
                mat->small->ambient=rgb;
                if(!loadMatRGB(is, rgb)) break;
                mat->small->diffuse=rgb;
                if(!loadMatRGB(is, rgb)) break;
                mat->small->specular=rgb;
                if(!loadIntValue(is, &i)) break;
                mat->small->transparency=i;
                if(!loadIntValue(is, &i)) break;
                mat->small->selfIllumination=i;
                if(!loadMatPair(is, int_pair)) break;
                mat->small->shininess=int_pair;
                if(!loadIntValue(is, &i)) break;
                mat->small->destinationBlend=i!=0;
                if(!loadIntValue(is, &i)) break;
                mat->small->twoSided=i!=0;
                if(!loadIntValue(is, &i)) break;
                mat->small->wireframe=i!=0;
                if(!loadIntValue(is, &i)) break;
                mat->small->textureValue=i;
                if(!loadMatPair(is, pair)) break;
                mat->small->enviromentMap=pair;
                if(!loadMatPair(is, pair)) break;
                mat->small->bumpMap=pair;

                if(!loadMatPair(is, pair)) break;
                mat->small->lightMap=pair;

                if(!loadMatPair(is, pair)) break;
                mat->small->map4=pair;
                if(!loadMatPair(is, pair)) break;
                mat->small->map5=pair;
                
                short flags=0;
                if(mat->small->destinationBlend) flags&=0x2;
                if(mat->small->twoSided) flags&=0x10;
                if(mat->small->wireframe) flags&=0x8;
                mat->flags=flags;
        
                return true;
        }
        while(false);
        return false;
}
//---------------------------------------------------------------------------------
bool bod_bob_parser::loadMaterial6Big(bob_dom_material6 *mat, token_stream &is)
{
        int count,i;
        
        bob_dom_material6::Big *big=new bob_dom_material6::Big();
        mat->big=big;
        
        if(!loadIntValue(is, &i, "Technique idx: ")) return false;
        big->technique=i;
        
        if((big->effect=loadString(is, "Effect name: "))==0) return false;
        
        material6_value *val;
        if(!loadIntValue(is, &count, "Value count: ")) return false;
        for(i=0; i < count; i++){
                if((val=loadMat6Value(is))==0) return false;
                big->values.push_back(val);
        }
        
        return true;
}
//---------------------------------------------------------------------------------
material6_value * bod_bob_parser::loadMat6Value(token_stream& is)
{
        bool bRes=false;
        // name, type, value
        char *name, *strtype;
        
        material6_value *val=new material6_value();
        
        token_stream::token *typepos;
        
        do{
                if((name=loadString(is, "Property name: "))==0) break;
                if(name[0]==0) {
                        error(is.tok(), S_Error, "Empty property name");
                        return false;
                }
                if((strtype=loadString(is, "Property type: "))==0) break;
                typepos=is.tok();
                
                int type=-1;
                
                for(int i=0; i < material6_value::typeNameCount(); i++){
                        if(strcmp(strtype, material6_value::typeName(i))==0) {
                                if(strtype[0]!=0)
                                        type=i;
                                break;
                        }
                }
                
                if(type==-1){
                        error(typepos, S_Error, "Unknown property type: \"%s\"", strtype);
                        break;
                }
                val->type=(material6_value::Type)type;
                val->name=name; 
                name=0;
                
                double d;
                switch(val->type){
                        case material6_value::typeBool: // nobreak
                        case material6_value::typeLong:
                                bRes=loadIntValue(is, &val->val.i, "Property value: ");
                                break;
                        case material6_value::typeString:
                                bRes=((val->val.psz=loadString(is, "Property value: "))!=0);
                                break;
                        case material6_value::typeFloat:
                                bRes=loadDoubleValue(is, &d, "Property value: ");
                                val->val.f=(float)d;
                                break;
                        case material6_value::typeFloat4:
                                for(int i=0; i < 4; i++){
                                        if((bRes=loadDoubleValue(is, &d, "Property value"))==false) break;
                                        val->val.f4.f[i]=(float)d;
                                }
                                break;
                        default:
                                error(0, S_Error, "Don't know how to output type \"%s\"", strtype);
                                bRes=false;
                }
                if(bRes==false)
                        break;
                        
                bRes=true;
        }
        while(0);
        
        delete[] name; delete[] strtype;
        
        if(bRes==false) {
                delete val;
                val=0;
        }
        
        return val;
}
//---------------------------------------------------------------------------------
bool bod_bob_parser::loadMaterial(bob_dom_bob *bob, token_stream& is)
{
        bob_dom_material5::materialType type;
        
        token *t=is.tok();
        
        if(t){
                if(strcmp(t->getText(), "MATERIAL6")==0)
                        type=bob_dom_material::mat6;
                else if(strcmp(t->getText(), "MATERIAL5")==0)
                        type=bob_dom_material::mat5;
                else if(strcmp(t->getText(), "MATERIAL3")==0)
                        type=bob_dom_material::mat3;
                else if(strcmp(t->getText(), "MATERIAL")==0)
                        type=bob_dom_material5::mat1;
        }
        
        if(t==NULL || t->type!=token::t_text){
                error(t ? t : is.previous(), S_Error, "Expected material header (MATERIAL, MATERIAL3, MATERIAL5 or MATERIAL6)");
                return NULL;
        }
        t=(++is).tok();
        if(t==NULL || t->type!=token::t_colon){
                error(t ? t : is.previous(), S_Error, "Expected ':' after '%s'", is.previous()->getText());
                return NULL;
        }
        if(!checkImmediatePlacement(is.previous(), is.tok()))
                return NULL;
        
        ++is;
        
        bool bRes;
        bob_dom_material *mat;
        switch(type) {
                case bob_dom_material::mat6:
                        mat=new bob_dom_material6();
                        bRes=loadMat((bob_dom_material6*)mat, is);
                        break;
                default: // always mat5 because lower mats are not supported in binary form
                        mat=new bob_dom_material5();
                        mat->type=type;
                        bRes=loadMat((bob_dom_material5*)mat, is);
                        break;
        }
        
        if(bRes==false)
                delete mat;
        else
                bob->materials.push_back(mat);
                
        return bRes;
}
//---------------------------------------------------------------------------------
bool bod_bob_parser::loadBody(bob_dom_bob *bob, token_stream& is)
{
        static const char *context="Body: ";
        bob_dom_body *body=bob->bodies.createChild();
        PointList list;
        
        deleteTempData();
        
        loadIntValue(is, &(body->bodySize), context);
        
        if(!loadBones(body, is)){
                bob->bodies.removeChild(--bob->bodies.end());
                return false;
        }
        if(!loadPoints(body, is, list)) {
                bob->bodies.removeChild(--bob->bodies.end());
                return false;
        }
        
        if(!loadWeights(body, is)){
                bob->bodies.removeChild(--bob->bodies.end());
                return false;
        }
        
        if(m_weights.size() && m_weights.size()!=list.size()){
                error(0, S_Error, "Number of Weights (%d) does not match number of Points (%d)", m_weights.size(), list.size());
                bob->bodies.removeChild(--bob->bodies.end());
                return false;
        }
        
        // move the points to array so we can access them with index
        m_points.resize(list.size());
        int i=0;
        for(PointList::iterator &it=list.begin(); it!=list.end(); ++it, ++i){
                m_points[i]=*it;
        }
        list.clear();
        
        int endval;
        do{
                if(!loadPart(body, is)) {
                        bob->bodies.removeChild(--bob->bodies.end());
                        return false;
                }
                
                loadIntValue(is, &endval);
                if(endval!=-99)
                        ungetValue(is);
        }
        while(is.good() && endval!=-99); // -99 means end of body
        
        if(endval!=-99){
                error(is.previous(), S_Error, "Unexpected end of document found while loading Body. Do you miss the '-99'?");
                bob->bodies.removeChild(--bob->bodies.end());
                return false;
        }
        if(!flagsFromString(is, body->bodyFlags)){
                bob->bodies.removeChild(--bob->bodies.end());
                return false;
        }
        
        return true;
}
//---------------------------------------------------------------------------------
bool bod_bob_parser::loadPoints(bob_dom_body *body, token_stream& is, PointList& points)
{
        bool bEnd;
        int x, y, z;
        static const char *context="Point: ";
        
        do{
                loadIntValue(is, &x, context);
                loadIntValue(is, &y, context);
                if(!loadIntValue(is, &z, context)) return false;
                
                if(x==-1 && y==-1 && z==-1) { 
                        bEnd=true; 
                        break; 
                }
                
                __asm {
                        fild x
                        fdiv bob_dom_point::multiplier;
                        fistp x
                        
                        fild y
                        fdiv bob_dom_point::multiplier;
                        fistp y
                        
                        fild z
                        fdiv bob_dom_point::multiplier;
                        fistp z
                }
                points.push_back(new point_t(x, y, z));
        }
        while(is.good());
        
        if(!bEnd){
                error(is.previous(), S_Error, "Unexpected end of document found while loading Points. Do you miss the '-1;-1;-1;'?");
                return false;
        }
        
        return true;
}
//---------------------------------------------------------------------------------
// load part - bunch of faces/uv's
bool bod_bob_parser::loadPart(bob_dom_body *body, token_stream& is)
{
        int matIdx;
        bool bRes=true;
        static const char *context="Parts: ";
        bool secUV=false;
        
        bob_dom_part *part=new bob_dom_part();
        
        loadIntValue(is, &matIdx, context);
        do{
                if(matIdx < 0)
                        { error(is.previous(), S_Error, "%sMaterial index must be >= 0", context); bRes=false; break; }
                if(matIdx!=0 && ((size_t)matIdx > m_materials->size() - 1))
                        error(is.previous(), S_Warning, "%sMaterial index out of range: %d", context, matIdx);
                        
                if((bRes=loadFace(matIdx, *body, *part, is))==false)
                        break;
                
                if(is.tok() && is.tok()->type==token::t_openInstrBlock) {
                        secUV=true;
                        
                        if((bRes=loadX3PartValues(++is, *part))==false)
                                break;
                        
                        if((bRes=loadSecondaryUVs(is, *part))==false) 
                                break;
                }
                
                loadIntValue(is, &matIdx, context);
        }
        while(matIdx!=-99 && is.good()); // -99 means end of part
        
        if(bRes && matIdx!=-99){
                error(is.previous(), S_Error, "Unexpected end of document found while loading Part. Do you miss the '-99'?");
                bRes=false;
        }
        
        if(bRes)
                bRes=flagsFromString(is, part->flags);
                
        if(secUV)
                part->flags|=bob_dom_part::x3flag;
                
        if(bRes)
                body->parts.push_back(part);
        else
                delete part;
                
        return bRes;
};
//---------------------------------------------------------------------------------
bool bod_bob_parser::flagsFromString(token_stream& is, int& flags)
{
        bool bRes;
        token *t=loadValue(is);
        
        flags=0;
        if(bRes=(t!=NULL)){
                int len=(int)strlen(t->text);
                int val=1;
                for(int i=len-1; i >= 0; i--, val<<=1 ){
                        switch(t->text[i]){
                                case '0':
                                        break;
                                case '1':
                                        flags|=val;
                                        break;
                                default:
                                        error(is.previous(), S_Error, "Invalid flags definition. Expected binary number");
                                        bRes=false;
                                        break;
                        }
                        if(bRes==false) break;
                }
        }
        return bRes;
}
//---------------------------------------------------------------------------------
// load face - actual face and its uv's
bool bod_bob_parser::loadFace(int matIdx, bob_dom_body& body, bob_dom_part& part, token_stream& is)
{
        int indexes[3];
        int magic;
        int lastPntVal;
        double dtexX, dtexY;
        int texX, texY;
        static const char *context="Part: ";
        
        for(int i=0; i < 3; i++){
                if(loadIntValue(is, indexes + i, context)){
                        if(indexes[i] < 0 || (size_t)indexes[i] >= m_points.size()){
                                error(is.previous(), S_Error, "Point index out of range: point %d, index %d", i, indexes[i]);
                                return false;
                        }
                }
                else
                        return false;
        }
        
        bool bRes=true;
        
        // magic: -1 means no smoothing and no uv, -9 means no smoothing and uv
        //        -17 means smoothing and no uv, -25 means smoothing and uv
        bRes&=loadIntValue(is, &magic, context);
        if(magic!=-9 && magic!=-1)
                bRes&=loadIntValue(is, &lastPntVal, context);
        else
                lastPntVal=0;
        
        if(bRes==false) return false;
        
        bob_dom_point *point;
        bob_dom_face *face=new bob_dom_face();
        
        bob_dom_point *points_ar[3];
        int  magic_ar[3];
        
        for(int i=0; i < 3; i++){
                if(magic!=-17 && magic!=-1){
                        loadDoubleValue(is, &dtexX, context);
                        bRes&=loadDoubleValue(is, &dtexY, context);
                        
                        // this is like texX=(int)(dtexX / bob_dom_part::multiplier) with rounding 'to nearest'
                        __asm {
                                fld dtexX
                                fdiv bob_dom_part::multiplier
                                fistp texX
                                
                                fld dtexY
                                fdiv bob_dom_part::multiplier
                                fistp texY
                        }
                }
                else{
                        texX=0;
                        texY=0;
                }
                
                texture_coords_t *coords;
                texture_coord_t *coord=0;
                
                coords=m_points[indexes[i]]->findTextureCoords(lastPntVal);
                
                // I can't remember why -9 is duplicated - it is because it does not have smoothing?
                // should -1 be also here?
                if(magic!=-9 /*&& magic!=-1 ?? */){
                        coord=coords->findCoords(texX, texY);
                }
                if(coord==NULL){
                        coord=new texture_coord_t();
                        coord->x=texX;
                        coord->y=texY;
                        coords->push_back(coord);
                        
                        point=new bob_dom_point();
                        point->x=m_points[indexes[i]]->x;
                        point->y=m_points[indexes[i]]->y;
                        point->z=m_points[indexes[i]]->z;
                        point->textureCoords.left=texX;
                        point->textureCoords.right=texY;
                        
                        point->values.push_back(lastPntVal);
                        
                        coord->index=(int)body.points.new_points.size();
                        body.points.new_points.push_back(point);
                        
                        points_ar[i]=point; // this will be used to fetch values found in intruction block
                        
                        // now insert the appropriate weight
                        if(m_weights.size())
                                body.weights.new_weights.push_back(new bob_dom_weight(*m_weights[indexes[i]]));
                }
                else
                        points_ar[i]=NULL;
                
                magic_ar[i]=magic;
                face->values[i]=coord->index;
        }
        face->values[3]=1;
        part.facelist(matIdx)->push_back(face);
        
        
        return loadSpecialValues(points_ar, magic_ar, is);
}
//---------------------------------------------------------------------------------
// load special values which may be "hidden" in instruction block after standard part definition
// example: /! { 1;2;3; } { 4;5;6; } { 7;8;9; } !/
bool bod_bob_parser::loadSpecialValues(bob_dom_point *points[3], int magic[3], token_stream& is)
{
        // we must now fill the special coordinates to the points
        // they will be either specified in instruction block or we will use default values
        
        bob_dom_point dummy_pnt;
        dummy_pnt.values.push_back(1);
        
        token *t=is.tok();
        
        if(t && t->type==token::t_openInstrBlock){
                ++is;
                for(int i=0; i < 3; i++){
                        // if thte point was already loaded it is null, but we must still consume the values
                        // and check errors so I load them to dummy point
                        if(points[i]!=NULL){
                                if(!loadSpecialPointValues(is, points[i]))
                                        return false;
                        }
                        else{
                                if(!loadSpecialPointValues(is, &dummy_pnt))
                                        return false;
                                dummy_pnt.values.clear();
                                // the "last value" must be there otherwise loadSpecialPointValues would fail
                                dummy_pnt.values.push_back(1); 
                        }
                }
                t=is.tok();
                if(t==NULL || t->type!=token::t_closeInstrBlock){
                        error(t ? t : is.previous(), S_Error, "Expected end of instruction block '!/' after '%s'", is.previous());
                        return false;
                }
                ++is;
        }
        // use default values
        else{
                int count;
                for(int i=0; i < 3; i++){
                        if(points[i]==NULL) continue;
                        bob_dom_point::iterator last=--points[i]->values.end();
                        
                        // megic ==-17 means we are not using mateial so we can use the smallest point type 0x19
                        if(magic[i]==-17){
                                points[i]->type=0x19;
                                count=1;
                        }
                        else{
                                points[i]->type=0x1B;
                                count=3;
                        }
                        for(int j=0; j < count; j++){
                                points[i]->values.insert(last, 0);
                        }
                }
        }
        return true;
}
//---------------------------------------------------------------------------------
// load one block from extra info in instruction block 
// example: { 1; 2; 3; }
bool bod_bob_parser::loadSpecialPointValues(token_stream& is, bob_dom_point *point)
{
        double d;
        int v;
        static const char *context="Part - Extra point info: ";
        
        // point already has the "last point value" pushed into list, so we must
        // push new values before it
        bob_dom_point::iterator &last=--point->values.end();
        
        token *t=is.tok();
        if(t==NULL || t->type!=token::t_openBracket){
                error(t ? t : is.previous(), S_Error, "Expected beginning of block after '%s'", is.previous()->getText());
                return false;
        }
        ++is;
        while((t=is.tok())!=NULL && !(t->type==token::t_closeBracket || t->type==token::t_closeInstrBlock)){
                if(!loadDoubleValue(is, &d, context))
                        return false;
                
                __asm{
                        fld d
                        fdiv bob_dom_part::multiplier
                        fistp v
                }
                
                point->values.insert(last, v);
        }
        if(t==NULL || t->type!=token::t_closeBracket){
                if(t==NULL)
                        error(is.previous(), S_Error, "Unexpected end of document found while loading extra point info. Do you miss the '}'?");
                else
                        error(t, S_Error, "Unexpected '%s' found while loading extra point info", t->getText());
                return false;
        }
        
        switch(point->values.size()){
                case 2:
                        point->type=0x19;
                        break;
                case 4:
                        point->type=0x1B;
                        break;
                case 6:
                        point->type=0x1F;
                        break;
                default:
                        error(t, S_Error, "Invalid number of values in extra point info block (%d) must be 1, 3 or 5", point->values.size() - 1);
                        return false;
        }
        ++is;
        
        return true;
}
//---------------------------------------------------------------------------------
bool bod_bob_parser::loadBones(bob_dom_body *body, token_stream& is)
{
        const token *t=is.tok();
        static const char *context2="Bones: ";
        static const char *context="Bone: ";
        
        if(!(t && t->type==token::t_text && strcmp(t->text, "BONES")==0))
                return true;
                
        t=(++is).tok();
        if(t==NULL || t->type!=token::t_colon){
                error(t ? t : is.previous(), S_Error, "Expected ':' after '%s'", is.previous()->getText());
                return false;
        }
        if(!checkImmediatePlacement(is.previous(), t))
                return false;
        
        int count;
        if(!loadIntValue(++is, &count, context2))
                return false;
        
        char *name;
        for(int i=0; i < count; i++){
                name=loadString(is, context);
                if(name==NULL) return false;
                body->bones.push_back(name);
        }
        
        return !is.fail();
}
//---------------------------------------------------------------------------------
// load the weights to temporary array. Weights from this array will then be inflated and added to body
bool bod_bob_parser::loadWeights(bob_dom_body *body, token_stream& is)
{
        const token *t=is.tok();
        static const char *context="Weight: ";
        static const char *context2="Weights: ";
        
        if(!(t && t->type==token::t_text && strcmp(t->text, "WEIGHTS")==0))
                return true;
                
        int count;
        if(!loadIntValue(++is, &count, context2))
                return false;
        
        bool bRes=true;
        int v; double d;
        bob_dom_weight *w;
        
        m_weights.resize(count, 0);
        
        for(int i=0; i < count; i++){
                w=new bob_dom_weight();
                do{
                        if(!loadIntValue(is, &v, context)) 
                                { bRes=false; break; }
                        if(v==-1) 
                                break;
                                
                        if(v < 0 || (size_t)v >= body->bones.size()){
                                error(is.previous(), S_Error, "Weight: Bone index out of range (%d)", v);
                                { bRes=false; break; }
                        }
                        
                        if(!loadDoubleValue(is, &d, context)) 
                                { bRes=false; break; }
                        
                        bob_dom_weight::value val;
                        val.boneIdx=v;
                        
                        __asm{
                                // val.boneCoefficient = bob_dom_weight::value::multiplier * d
                                fild bob_dom_weight::value::multiplier
                                fmul d
                                fistp val.boneCoefficient
                        }
                        w->values.push_back(val);
                }
                while(!is.fail());
                if(is.fail()){
                        error(is.previous(), S_Error, "Unexpected end of document found while loading Weights. Do you miss the '-1'?");
                        bRes=false;
                }
                if(bRes==false){
                        delete w;
                        break;
                }
                m_weights[i]=w;
        }
        if(bRes){
                if(!loadIntValue(is, &v, context2)) 
                        bRes=false;
                else if(v!=-1){
                        error(is.previous(), S_Error, "Expected '-1' after end of Weights");
                        bRes=false;
                }
        }
        return bRes;
}
//---------------------------------------------------------------------------------
bool bod_bob_parser::loadSecondaryUVs(token_stream& is, bob_dom_part& part)
{
        bool bRes;
        do{
                if((bRes=loadSecondaryUVRecord(is, part))==false) break;
        }
        while(is.tok() && is.tok()->type!=token::t_closeInstrBlock);
        
        if(bRes){
                bRes=(is.tok() && is.tok()->type==token::t_closeInstrBlock);
                if(bRes==false)
                        error(is.tok() ? is.tok() : is.previous(), S_Error, "Unexpected end of document found while loading secondary UV's. Do you miss the '!/'?");
                else
                        ++is;
        }
        return bRes;
}
//---------------------------------------------------------------------------------
bool bod_bob_parser::loadSecondaryUVRecord(token_stream& is, bob_dom_part& part)
{
        int matIdx, pointIdx;
        bool bRes=false;
        double d;
        bob_face_list *faces;
        bob_x3uv *uv=new bob_x3uv();
        
        do{
                if(!loadIntValue(is, &matIdx, "")) break;
                if(!loadIntValue(is, &pointIdx, "")) break;
                for(int i=0; i < 6; i++){
                        if((bRes=loadDoubleValue(is, &d, ""))==false) break;
                        uv->values[i]=(float) d;
                }
                uv->idx=pointIdx;
                
                faces=part[matIdx];
                if(faces==NULL){
                        error(is.tok(), S_Error, "Secondary UVs: Face list with material idx %d not found", matIdx);
                        break;
                }
                faces->x3uvlist.push_back(uv);
                
                bRes=true;
        }
        while(0);
        if(bRes==false)
                delete uv;
                
        return bRes;
}
//---------------------------------------------------------------------------------
bool bod_bob_parser::loadX3PartValues(token_stream& is, bob_dom_part& part)
{
        static char *context="X3 part values: ";
        static char *hdr="PART_VALUES_RAW";
        
        if(is.tok()==NULL || is.tok()->type!=token::t_text || strcmp(is.tok()->text, "PART_VALUES_RAW")!=0) {
                error(is.tok() ? is.tok() : is.previous(), S_Error, "Expected '%s' here", hdr);
                return false;
        }
        if((++is).tok()==NULL || is.tok()->type!=token::t_colon){
                error(is.tok() ? is.tok() : is.previous(), S_Error, "Expected ':' after '%s'", hdr);
                return false;
        }
        
        ++is;
        
        int v;
        bool bRes;
        
        for(int i=0; i < 10; i++){
                if((bRes=loadIntValue(is, &v, context))==false) 
                        break;
                part.values[i]=v;
        }
        return bRes;
}
//---------------------------------------------------------------------------------