| 1 | cycrow | 1 | #include "bod_bob_parser.h"
 | 
        
           |  |  | 2 | #include "../common/strutils.h"
 | 
        
           | 114 | cycrow | 3 |   | 
        
           |  |  | 4 | #define ISMATERIAL(text) ((strcmp(text, "MATERIAL6")==0 || strcmp(text, "MATERIAL5")==0 || \
 | 
        
           |  |  | 5 |                           strcmp(text, "MATERIAL3")==0 || strcmp(text, "MATERIAL")==0))
 | 
        
           |  |  | 6 |   | 
        
           | 1 | cycrow | 7 | //---------------------------------------------------------------------------------
 | 
        
           | 114 | cycrow | 8 |   | 
        
           |  |  | 9 | geometry::point2d<double> bod_bob_parser::uv_coord::NULL_COORDS(123456, 78910);
 | 
        
           |  |  | 10 | //---------------------------------------------------------------------------------
 | 
        
           |  |  | 11 | bool bod_bob_parser::compile(token_stream& is, obinaryfilestream& os, bool bEmbedded)
 | 
        
           | 1 | cycrow | 12 | {
 | 
        
           | 114 | cycrow | 13 | 	bob_dom_bob *bob=loadBOB(is, bEmbedded);
 | 
        
           | 1 | cycrow | 14 | 	if(bob)
 | 
        
           |  |  | 15 | 		bob->toFile(os);
 | 
        
           |  |  | 16 | 	delete bob;
 | 
        
           |  |  | 17 | 	return bob!=NULL;
 | 
        
           |  |  | 18 | }
 | 
        
           |  |  | 19 | //---------------------------------------------------------------------------------
 | 
        
           |  |  | 20 | bob_dom_bob * bod_bob_parser::loadBOB(token_stream& is, bool bEmbedded)
 | 
        
           |  |  | 21 | {
 | 
        
           |  |  | 22 | 	token *t;
 | 
        
           |  |  | 23 | 	bob_dom_bob *bob=new bob_dom_bob(m_settings);
 | 
        
           |  |  | 24 | 	bool abort=false;
 | 
        
           | 114 | cycrow | 25 |   | 
        
           | 1 | cycrow | 26 | 	while((t=is.tok()) && t->type==token::t_hdrinfo){
 | 
        
           |  |  | 27 | 		if(bob->info.text()!=0)
 | 
        
           |  |  | 28 | 			error(is.tok(), S_Warning, "Header info already defined, last value will be used");
 | 
        
           |  |  | 29 | 		bob->info.text(t->text);
 | 
        
           |  |  | 30 | 		++is;
 | 
        
           |  |  | 31 | 	}
 | 
        
           | 114 | cycrow | 32 |   | 
        
           | 1 | cycrow | 33 | 	// first load material definitions, break on first numeric token
 | 
        
           | 114 | cycrow | 34 | 	while((t=is.tok()) && t->type!=token::t_closeCrBracket){
 | 
        
           | 1 | cycrow | 35 | 		if(t->type!=token::t_text){
 | 
        
           |  |  | 36 | 			error(t, S_Error, "Unexpected here: '%s'", t->getText());
 | 
        
           |  |  | 37 | 			abort=true; break;
 | 
        
           |  |  | 38 | 		}
 | 
        
           |  |  | 39 | 		if(isinteger(t->text)) break;
 | 
        
           | 114 | cycrow | 40 |   | 
        
           | 1 | cycrow | 41 | 		if(ISMATERIAL(t->text)){
 | 
        
           |  |  | 42 | 			if(!loadMaterial(bob, is)){
 | 
        
           |  |  | 43 | 				abort=true; break;
 | 
        
           |  |  | 44 | 			}
 | 
        
           |  |  | 45 | 		}
 | 
        
           |  |  | 46 | 		else{
 | 
        
           |  |  | 47 | 			error(t, S_Error, "Unexpected here '%s'", t->getText());
 | 
        
           |  |  | 48 | 			abort=true; break;
 | 
        
           |  |  | 49 | 		}
 | 
        
           |  |  | 50 | 	}
 | 
        
           | 114 | cycrow | 51 |   | 
        
           | 1 | cycrow | 52 | 	// now load the body definition: body size, points, parts
 | 
        
           |  |  | 53 | 	if(!abort){
 | 
        
           |  |  | 54 | 		m_materials=&(bob->materials);
 | 
        
           |  |  | 55 | 		do{
 | 
        
           |  |  | 56 | 			if(abort=(loadBody(bob, is)==false)) break;
 | 
        
           | 114 | cycrow | 57 |   | 
        
           | 1 | cycrow | 58 | 			if(bEmbedded){
 | 
        
           |  |  | 59 | 				if(is.tok()==NULL){
 | 
        
           |  |  | 60 | 					error(is.previous(), S_Error, "Unexpected end of document found while loading embedded BOB - do you miss the '}'?");
 | 
        
           |  |  | 61 | 					abort=true; break;
 | 
        
           |  |  | 62 | 				}
 | 
        
           | 114 | cycrow | 63 | 				else if(is.tok()->type==token::t_closeCrBracket)
 | 
        
           | 1 | cycrow | 64 | 					break;
 | 
        
           |  |  | 65 | 			}
 | 
        
           |  |  | 66 | 			else if(is.eof())
 | 
        
           |  |  | 67 | 				break;
 | 
        
           |  |  | 68 | 		}
 | 
        
           |  |  | 69 | 		while(1); // while what? while '}' if embedded or while eof if standalone
 | 
        
           |  |  | 70 | 	}
 | 
        
           | 114 | cycrow | 71 |   | 
        
           | 1 | cycrow | 72 | 	if(abort){
 | 
        
           |  |  | 73 | 		delete bob;
 | 
        
           |  |  | 74 | 		bob=NULL;
 | 
        
           |  |  | 75 | 	}
 | 
        
           | 114 | cycrow | 76 |   | 
        
           | 1 | cycrow | 77 | 	++is; // advance past the close bracket (if embedded)
 | 
        
           | 114 | cycrow | 78 |   | 
        
           | 1 | cycrow | 79 | 	return bob;
 | 
        
           |  |  | 80 | }
 | 
        
           |  |  | 81 | //---------------------------------------------------------------------------------
 | 
        
           | 114 | cycrow | 82 | bool bod_bob_parser::loadMatRGB(token_stream& is, bob_material5::rgb& rgb)
 | 
        
           | 1 | cycrow | 83 | {
 | 
        
           |  |  | 84 | 	int vals[3];
 | 
        
           |  |  | 85 | 	token *t;
 | 
        
           |  |  | 86 | 	for(int i=0; i < 3; i++){
 | 
        
           |  |  | 87 | 		t=loadValue(is);
 | 
        
           |  |  | 88 | 		if(t==NULL) return false;
 | 
        
           |  |  | 89 | 		if(!isinteger(t->text)){
 | 
        
           |  |  | 90 | 			error(t, S_Error, "Expected integer value at position %d in RBG", i);
 | 
        
           |  |  | 91 | 			return false;
 | 
        
           |  |  | 92 | 		}
 | 
        
           |  |  | 93 | 		vals[i]=atoi(t->text);
 | 
        
           |  |  | 94 | 	}
 | 
        
           |  |  | 95 | 	rgb.r=vals[0];
 | 
        
           |  |  | 96 | 	rgb.g=vals[1];
 | 
        
           |  |  | 97 | 	rgb.b=vals[2];
 | 
        
           |  |  | 98 | 	return true;
 | 
        
           |  |  | 99 | }
 | 
        
           |  |  | 100 | //---------------------------------------------------------------------------------
 | 
        
           | 114 | cycrow | 101 | bool bod_bob_parser::loadMatPair(token_stream& is, bob_material5::pair& pair)
 | 
        
           | 1 | cycrow | 102 | {
 | 
        
           |  |  | 103 | 	int vals[2];
 | 
        
           | 114 | cycrow | 104 |   | 
        
           | 1 | cycrow | 105 | 	for(int i=0; i < 2; i++){
 | 
        
           |  |  | 106 | 		if(!loadIntValue(is, vals + i))
 | 
        
           |  |  | 107 | 			return false;
 | 
        
           | 114 | cycrow | 108 |   | 
        
           | 1 | cycrow | 109 | 	}
 | 
        
           |  |  | 110 | 	pair.value=vals[0];
 | 
        
           |  |  | 111 | 	pair.strength=vals[1];
 | 
        
           |  |  | 112 | 	return true;
 | 
        
           |  |  | 113 | }
 | 
        
           |  |  | 114 | //---------------------------------------------------------------------------------
 | 
        
           | 114 | cycrow | 115 | bool bod_bob_parser::loadMatPair(token_stream& is, bob_material6::Small::pair& pair)
 | 
        
           | 1 | cycrow | 116 | {
 | 
        
           |  |  | 117 | 	int i;
 | 
        
           |  |  | 118 | 	if((pair.texture=loadString(is, "texture name"))==0) return false;
 | 
        
           |  |  | 119 | 	if(strcmp(pair.texture, "NULL")==0){
 | 
        
           |  |  | 120 | 		delete pair.texture; pair.texture=0;
 | 
        
           |  |  | 121 | 	}
 | 
        
           |  |  | 122 | 	if(loadIntValue(is, &i, "texture strength")==false) return false;
 | 
        
           |  |  | 123 | 	pair.strength=i;
 | 
        
           |  |  | 124 | 	return true;
 | 
        
           |  |  | 125 | }
 | 
        
           |  |  | 126 | //---------------------------------------------------------------------------------
 | 
        
           |  |  | 127 | bool bod_bob_parser::checkImmediatePlacement(const bod_bob_parser::token *token1, const bod_bob_parser::token *token2)
 | 
        
           |  |  | 128 | {
 | 
        
           |  |  | 129 | 	if(token1->line!=token2->line || (token1->col + strlen(token1->getText())!=token2->col)){
 | 
        
           |  |  | 130 | 		error(token2, S_Error, "'%s' must be placed directly after '%s'", token2->getText(), token1->getText());
 | 
        
           |  |  | 131 | 		return false;
 | 
        
           |  |  | 132 | 	}
 | 
        
           |  |  | 133 | 	else
 | 
        
           |  |  | 134 | 		return true;
 | 
        
           |  |  | 135 | }
 | 
        
           |  |  | 136 | //---------------------------------------------------------------------------------
 | 
        
           | 114 | cycrow | 137 | bool bod_bob_parser::loadMat(bob_material5 *mat, token_stream &is)
 | 
        
           | 1 | cycrow | 138 | {
 | 
        
           |  |  | 139 | 	do{
 | 
        
           | 114 | cycrow | 140 | 		int i;
 | 
        
           |  |  | 141 | 		bob_material5::rgb rgb;
 | 
        
           |  |  | 142 | 		bob_material5::pair pair;
 | 
        
           |  |  | 143 |   | 
        
           | 1 | cycrow | 144 | 		if(!loadIntValue(is, &i)) break;
 | 
        
           |  |  | 145 | 		mat->index=i;
 | 
        
           |  |  | 146 | 		if(!loadIntValue(is, &i)) break;
 | 
        
           |  |  | 147 | 		mat->textureID=i;
 | 
        
           |  |  | 148 | 		if(!loadMatRGB(is, rgb)) break;
 | 
        
           |  |  | 149 | 		mat->ambient=rgb;
 | 
        
           |  |  | 150 | 		if(!loadMatRGB(is, rgb)) break;
 | 
        
           |  |  | 151 | 		mat->diffuse=rgb;
 | 
        
           |  |  | 152 | 		if(!loadMatRGB(is, rgb)) break;
 | 
        
           |  |  | 153 | 		mat->specular=rgb;
 | 
        
           | 114 | cycrow | 154 | 		if(mat->type!=bob_material::mat1) {
 | 
        
           | 1 | cycrow | 155 | 			if(!loadIntValue(is, &i)) break;
 | 
        
           |  |  | 156 | 			mat->transparency=i;
 | 
        
           |  |  | 157 | 			if(!loadIntValue(is, &i)) break;
 | 
        
           |  |  | 158 | 			mat->selfIllumination=i;
 | 
        
           |  |  | 159 | 			if(!loadMatPair(is, pair)) break;
 | 
        
           |  |  | 160 | 			mat->shininess=pair;
 | 
        
           |  |  | 161 | 			if(!loadIntValue(is, &i)) break;
 | 
        
           |  |  | 162 | 			mat->destinationBlend=i!=0;
 | 
        
           |  |  | 163 | 			if(!loadIntValue(is, &i)) break;
 | 
        
           |  |  | 164 | 			mat->twoSided=i!=0;
 | 
        
           |  |  | 165 | 			if(!loadIntValue(is, &i)) break;
 | 
        
           |  |  | 166 | 			mat->wireframe=i!=0;
 | 
        
           |  |  | 167 | 			if(!loadIntValue(is, &i)) break;
 | 
        
           |  |  | 168 | 			mat->textureValue=i;
 | 
        
           |  |  | 169 | 			if(!loadMatPair(is, pair)) break;
 | 
        
           |  |  | 170 | 			mat->enviromentMap=pair;
 | 
        
           |  |  | 171 | 			if(!loadMatPair(is, pair)) break;
 | 
        
           |  |  | 172 | 			mat->bumpMap=pair;
 | 
        
           | 114 | cycrow | 173 |   | 
        
           |  |  | 174 | 			if(mat->type==bob_material::mat5){
 | 
        
           | 1 | cycrow | 175 | 				if(!loadMatPair(is, pair)) break;
 | 
        
           |  |  | 176 | 				mat->lightMap=pair;
 | 
        
           |  |  | 177 | 			}
 | 
        
           |  |  | 178 | 		}
 | 
        
           |  |  | 179 | 		return true;
 | 
        
           |  |  | 180 | 	}
 | 
        
           |  |  | 181 | 	while(false);
 | 
        
           |  |  | 182 | 	return false;
 | 
        
           |  |  | 183 | }
 | 
        
           |  |  | 184 | //---------------------------------------------------------------------------------
 | 
        
           | 114 | cycrow | 185 | bool bod_bob_parser::loadMat(bob_material6 *mat, token_stream &is)
 | 
        
           | 1 | cycrow | 186 | {
 | 
        
           |  |  | 187 | 	int i; bool bRes=false;
 | 
        
           |  |  | 188 | 	do{
 | 
        
           |  |  | 189 | 		if(!loadIntValue(is, &i)) break;
 | 
        
           |  |  | 190 | 			mat->index=i;
 | 
        
           | 114 | cycrow | 191 |   | 
        
           | 1 | cycrow | 192 | 		if(!loadIntValue(is, &i)) break;
 | 
        
           |  |  | 193 | 			mat->flags=i;
 | 
        
           | 114 | cycrow | 194 |   | 
        
           |  |  | 195 | 		if(mat->flags==bob_material6::Big::flag)
 | 
        
           | 1 | cycrow | 196 | 			bRes=loadMaterial6Big(mat, is);
 | 
        
           |  |  | 197 | 		else
 | 
        
           |  |  | 198 | 			bRes=loadMaterial6Small(mat, is);
 | 
        
           |  |  | 199 | 	}
 | 
        
           |  |  | 200 | 	while(false);
 | 
        
           | 114 | cycrow | 201 |   | 
        
           | 1 | cycrow | 202 | 	return bRes;
 | 
        
           |  |  | 203 | }
 | 
        
           |  |  | 204 | //---------------------------------------------------------------------------------
 | 
        
           | 114 | cycrow | 205 | bool bod_bob_parser::loadMaterial6Small(bob_material6 *mat, token_stream &is)
 | 
        
           | 1 | cycrow | 206 | {
 | 
        
           |  |  | 207 | 	int i;
 | 
        
           | 114 | cycrow | 208 | 	bob_material1::rgb rgb;
 | 
        
           |  |  | 209 | 	bob_material1::pair int_pair;
 | 
        
           |  |  | 210 | 	bob_material6::Small::pair pair;
 | 
        
           |  |  | 211 |   | 
        
           |  |  | 212 | 	mat->small=new bob_material6::Small();
 | 
        
           | 1 | cycrow | 213 | 	do{
 | 
        
           |  |  | 214 | 		if((mat->small->textureFile=loadString(is, "texture name: "))==0) break;
 | 
        
           | 114 | cycrow | 215 | 		if(strcmp(mat->small->textureFile, "NULL")==0)
 | 
        
           | 1 | cycrow | 216 | 			{ delete[] mat->small->textureFile; mat->small->textureFile=0; }
 | 
        
           |  |  | 217 | 		if(!loadMatRGB(is, rgb)) break;
 | 
        
           |  |  | 218 | 		mat->small->ambient=rgb;
 | 
        
           |  |  | 219 | 		if(!loadMatRGB(is, rgb)) break;
 | 
        
           |  |  | 220 | 		mat->small->diffuse=rgb;
 | 
        
           |  |  | 221 | 		if(!loadMatRGB(is, rgb)) break;
 | 
        
           |  |  | 222 | 		mat->small->specular=rgb;
 | 
        
           |  |  | 223 | 		if(!loadIntValue(is, &i)) break;
 | 
        
           |  |  | 224 | 		mat->small->transparency=i;
 | 
        
           |  |  | 225 | 		if(!loadIntValue(is, &i)) break;
 | 
        
           |  |  | 226 | 		mat->small->selfIllumination=i;
 | 
        
           |  |  | 227 | 		if(!loadMatPair(is, int_pair)) break;
 | 
        
           |  |  | 228 | 		mat->small->shininess=int_pair;
 | 
        
           |  |  | 229 | 		if(!loadIntValue(is, &i)) break;
 | 
        
           |  |  | 230 | 		mat->small->destinationBlend=i!=0;
 | 
        
           |  |  | 231 | 		if(!loadIntValue(is, &i)) break;
 | 
        
           |  |  | 232 | 		mat->small->twoSided=i!=0;
 | 
        
           |  |  | 233 | 		if(!loadIntValue(is, &i)) break;
 | 
        
           |  |  | 234 | 		mat->small->wireframe=i!=0;
 | 
        
           |  |  | 235 | 		if(!loadIntValue(is, &i)) break;
 | 
        
           |  |  | 236 | 		mat->small->textureValue=i;
 | 
        
           |  |  | 237 | 		if(!loadMatPair(is, pair)) break;
 | 
        
           |  |  | 238 | 		mat->small->enviromentMap=pair;
 | 
        
           |  |  | 239 | 		if(!loadMatPair(is, pair)) break;
 | 
        
           |  |  | 240 | 		mat->small->bumpMap=pair;
 | 
        
           |  |  | 241 |   | 
        
           |  |  | 242 | 		if(!loadMatPair(is, pair)) break;
 | 
        
           |  |  | 243 | 		mat->small->lightMap=pair;
 | 
        
           |  |  | 244 |   | 
        
           |  |  | 245 | 		if(!loadMatPair(is, pair)) break;
 | 
        
           |  |  | 246 | 		mat->small->map4=pair;
 | 
        
           |  |  | 247 | 		if(!loadMatPair(is, pair)) break;
 | 
        
           |  |  | 248 | 		mat->small->map5=pair;
 | 
        
           | 114 | cycrow | 249 |   | 
        
           | 1 | cycrow | 250 | 		short flags=0;
 | 
        
           |  |  | 251 | 		if(mat->small->destinationBlend) flags&=0x2;
 | 
        
           |  |  | 252 | 		if(mat->small->twoSided) flags&=0x10;
 | 
        
           |  |  | 253 | 		if(mat->small->wireframe) flags&=0x8;
 | 
        
           |  |  | 254 | 		mat->flags=flags;
 | 
        
           | 114 | cycrow | 255 |   | 
        
           | 1 | cycrow | 256 | 		return true;
 | 
        
           |  |  | 257 | 	}
 | 
        
           |  |  | 258 | 	while(false);
 | 
        
           |  |  | 259 | 	return false;
 | 
        
           |  |  | 260 | }
 | 
        
           |  |  | 261 | //---------------------------------------------------------------------------------
 | 
        
           | 114 | cycrow | 262 | bool bod_bob_parser::loadMaterial6Big(bob_material6 *mat, token_stream &is)
 | 
        
           | 1 | cycrow | 263 | {
 | 
        
           |  |  | 264 | 	int count,i;
 | 
        
           | 114 | cycrow | 265 |   | 
        
           |  |  | 266 | 	bob_material6::Big *big=new bob_material6::Big();
 | 
        
           | 1 | cycrow | 267 | 	mat->big=big;
 | 
        
           | 114 | cycrow | 268 |   | 
        
           | 1 | cycrow | 269 | 	if(!loadIntValue(is, &i, "Technique idx: ")) return false;
 | 
        
           |  |  | 270 | 	big->technique=i;
 | 
        
           | 114 | cycrow | 271 |   | 
        
           | 1 | cycrow | 272 | 	if((big->effect=loadString(is, "Effect name: "))==0) return false;
 | 
        
           | 114 | cycrow | 273 |   | 
        
           | 1 | cycrow | 274 | 	material6_value *val;
 | 
        
           |  |  | 275 | 	if(!loadIntValue(is, &count, "Value count: ")) return false;
 | 
        
           |  |  | 276 | 	for(i=0; i < count; i++){
 | 
        
           |  |  | 277 | 		if((val=loadMat6Value(is))==0) return false;
 | 
        
           |  |  | 278 | 		big->values.push_back(val);
 | 
        
           |  |  | 279 | 	}
 | 
        
           | 114 | cycrow | 280 |   | 
        
           | 1 | cycrow | 281 | 	return true;
 | 
        
           |  |  | 282 | }
 | 
        
           |  |  | 283 | //---------------------------------------------------------------------------------
 | 
        
           |  |  | 284 | material6_value * bod_bob_parser::loadMat6Value(token_stream& is)
 | 
        
           |  |  | 285 | {
 | 
        
           |  |  | 286 | 	bool bRes=false;
 | 
        
           |  |  | 287 | 	// name, type, value
 | 
        
           |  |  | 288 | 	char *name, *strtype;
 | 
        
           | 114 | cycrow | 289 |   | 
        
           | 1 | cycrow | 290 | 	material6_value *val=new material6_value();
 | 
        
           | 114 | cycrow | 291 |   | 
        
           | 1 | cycrow | 292 | 	token_stream::token *typepos;
 | 
        
           | 114 | cycrow | 293 |   | 
        
           | 1 | cycrow | 294 | 	do{
 | 
        
           |  |  | 295 | 		if((name=loadString(is, "Property name: "))==0) break;
 | 
        
           |  |  | 296 | 		if(name[0]==0) {
 | 
        
           |  |  | 297 | 			error(is.tok(), S_Error, "Empty property name");
 | 
        
           |  |  | 298 | 			return false;
 | 
        
           |  |  | 299 | 		}
 | 
        
           |  |  | 300 | 		if((strtype=loadString(is, "Property type: "))==0) break;
 | 
        
           |  |  | 301 | 		typepos=is.tok();
 | 
        
           | 114 | cycrow | 302 |   | 
        
           | 1 | cycrow | 303 | 		int type=-1;
 | 
        
           | 114 | cycrow | 304 |   | 
        
           | 1 | cycrow | 305 | 		for(int i=0; i < material6_value::typeNameCount(); i++){
 | 
        
           |  |  | 306 | 			if(strcmp(strtype, material6_value::typeName(i))==0) {
 | 
        
           |  |  | 307 | 				if(strtype[0]!=0)
 | 
        
           |  |  | 308 | 					type=i;
 | 
        
           |  |  | 309 | 				break;
 | 
        
           |  |  | 310 | 			}
 | 
        
           |  |  | 311 | 		}
 | 
        
           | 114 | cycrow | 312 |   | 
        
           | 1 | cycrow | 313 | 		if(type==-1){
 | 
        
           |  |  | 314 | 			error(typepos, S_Error, "Unknown property type: \"%s\"", strtype);
 | 
        
           |  |  | 315 | 			break;
 | 
        
           |  |  | 316 | 		}
 | 
        
           |  |  | 317 | 		val->type=(material6_value::Type)type;
 | 
        
           | 114 | cycrow | 318 | 		val->name=name;
 | 
        
           | 1 | cycrow | 319 | 		name=0;
 | 
        
           | 114 | cycrow | 320 |   | 
        
           | 1 | cycrow | 321 | 		double d;
 | 
        
           |  |  | 322 | 		switch(val->type){
 | 
        
           |  |  | 323 | 			case material6_value::typeBool: // nobreak
 | 
        
           |  |  | 324 | 			case material6_value::typeLong:
 | 
        
           |  |  | 325 | 				bRes=loadIntValue(is, &val->val.i, "Property value: ");
 | 
        
           |  |  | 326 | 				break;
 | 
        
           |  |  | 327 | 			case material6_value::typeString:
 | 
        
           |  |  | 328 | 				bRes=((val->val.psz=loadString(is, "Property value: "))!=0);
 | 
        
           |  |  | 329 | 				break;
 | 
        
           |  |  | 330 | 			case material6_value::typeFloat:
 | 
        
           |  |  | 331 | 				bRes=loadDoubleValue(is, &d, "Property value: ");
 | 
        
           |  |  | 332 | 				val->val.f=(float)d;
 | 
        
           |  |  | 333 | 				break;
 | 
        
           |  |  | 334 | 			case material6_value::typeFloat4:
 | 
        
           |  |  | 335 | 				for(int i=0; i < 4; i++){
 | 
        
           |  |  | 336 | 					if((bRes=loadDoubleValue(is, &d, "Property value"))==false) break;
 | 
        
           |  |  | 337 | 					val->val.f4.f[i]=(float)d;
 | 
        
           |  |  | 338 | 				}
 | 
        
           |  |  | 339 | 				break;
 | 
        
           |  |  | 340 | 			default:
 | 
        
           |  |  | 341 | 				error(0, S_Error, "Don't know how to output type \"%s\"", strtype);
 | 
        
           |  |  | 342 | 				bRes=false;
 | 
        
           |  |  | 343 | 		}
 | 
        
           |  |  | 344 | 		if(bRes==false)
 | 
        
           |  |  | 345 | 			break;
 | 
        
           | 114 | cycrow | 346 |   | 
        
           | 1 | cycrow | 347 | 		bRes=true;
 | 
        
           |  |  | 348 | 	}
 | 
        
           |  |  | 349 | 	while(0);
 | 
        
           | 114 | cycrow | 350 |   | 
        
           | 1 | cycrow | 351 | 	delete[] name; delete[] strtype;
 | 
        
           | 114 | cycrow | 352 |   | 
        
           | 1 | cycrow | 353 | 	if(bRes==false) {
 | 
        
           |  |  | 354 | 		delete val;
 | 
        
           |  |  | 355 | 		val=0;
 | 
        
           |  |  | 356 | 	}
 | 
        
           | 114 | cycrow | 357 |   | 
        
           | 1 | cycrow | 358 | 	return val;
 | 
        
           |  |  | 359 | }
 | 
        
           |  |  | 360 | //---------------------------------------------------------------------------------
 | 
        
           |  |  | 361 | bool bod_bob_parser::loadMaterial(bob_dom_bob *bob, token_stream& is)
 | 
        
           |  |  | 362 | {
 | 
        
           | 114 | cycrow | 363 | 	bob_material5::materialType type;
 | 
        
           |  |  | 364 |   | 
        
           | 1 | cycrow | 365 | 	token *t=is.tok();
 | 
        
           | 114 | cycrow | 366 |   | 
        
           | 1 | cycrow | 367 | 	if(t){
 | 
        
           |  |  | 368 | 		if(strcmp(t->getText(), "MATERIAL6")==0)
 | 
        
           | 114 | cycrow | 369 | 			type=bob_material::mat6;
 | 
        
           | 1 | cycrow | 370 | 		else if(strcmp(t->getText(), "MATERIAL5")==0)
 | 
        
           | 114 | cycrow | 371 | 			type=bob_material::mat5;
 | 
        
           | 1 | cycrow | 372 | 		else if(strcmp(t->getText(), "MATERIAL3")==0)
 | 
        
           | 114 | cycrow | 373 | 			type=bob_material::mat3;
 | 
        
           | 1 | cycrow | 374 | 		else if(strcmp(t->getText(), "MATERIAL")==0)
 | 
        
           | 114 | cycrow | 375 | 			type=bob_material5::mat1;
 | 
        
           | 1 | cycrow | 376 | 	}
 | 
        
           | 114 | cycrow | 377 |   | 
        
           | 1 | cycrow | 378 | 	if(t==NULL || t->type!=token::t_text){
 | 
        
           |  |  | 379 | 		error(t ? t : is.previous(), S_Error, "Expected material header (MATERIAL, MATERIAL3, MATERIAL5 or MATERIAL6)");
 | 
        
           |  |  | 380 | 		return NULL;
 | 
        
           |  |  | 381 | 	}
 | 
        
           |  |  | 382 | 	t=(++is).tok();
 | 
        
           |  |  | 383 | 	if(t==NULL || t->type!=token::t_colon){
 | 
        
           |  |  | 384 | 		error(t ? t : is.previous(), S_Error, "Expected ':' after '%s'", is.previous()->getText());
 | 
        
           |  |  | 385 | 		return NULL;
 | 
        
           |  |  | 386 | 	}
 | 
        
           |  |  | 387 | 	if(!checkImmediatePlacement(is.previous(), is.tok()))
 | 
        
           |  |  | 388 | 		return NULL;
 | 
        
           | 114 | cycrow | 389 |   | 
        
           | 1 | cycrow | 390 | 	++is;
 | 
        
           | 114 | cycrow | 391 |   | 
        
           | 1 | cycrow | 392 | 	bool bRes;
 | 
        
           | 114 | cycrow | 393 | 	bob_material *mat;
 | 
        
           | 1 | cycrow | 394 | 	switch(type) {
 | 
        
           | 114 | cycrow | 395 | 		case bob_material::mat6:
 | 
        
           |  |  | 396 | 			mat=new bob_material6();
 | 
        
           |  |  | 397 | 			bRes=loadMat((bob_material6*)mat, is);
 | 
        
           | 1 | cycrow | 398 | 			break;
 | 
        
           |  |  | 399 | 		default: // always mat5 because lower mats are not supported in binary form
 | 
        
           | 114 | cycrow | 400 | 			mat=new bob_material5();
 | 
        
           | 1 | cycrow | 401 | 			mat->type=type;
 | 
        
           | 114 | cycrow | 402 | 			bRes=loadMat((bob_material5*)mat, is);
 | 
        
           | 1 | cycrow | 403 | 			break;
 | 
        
           |  |  | 404 | 	}
 | 
        
           | 114 | cycrow | 405 |   | 
        
           | 1 | cycrow | 406 | 	if(bRes==false)
 | 
        
           |  |  | 407 | 		delete mat;
 | 
        
           |  |  | 408 | 	else
 | 
        
           |  |  | 409 | 		bob->materials.push_back(mat);
 | 
        
           | 114 | cycrow | 410 |   | 
        
           | 1 | cycrow | 411 | 	return bRes;
 | 
        
           |  |  | 412 | }
 | 
        
           |  |  | 413 | //---------------------------------------------------------------------------------
 | 
        
           |  |  | 414 | bool bod_bob_parser::loadBody(bob_dom_bob *bob, token_stream& is)
 | 
        
           |  |  | 415 | {
 | 
        
           |  |  | 416 | 	static const char *context="Body: ";
 | 
        
           | 114 | cycrow | 417 | 	bob_body *body=bob->bodies.createChild();
 | 
        
           |  |  | 418 | 	VertexList list;
 | 
        
           |  |  | 419 |   | 
        
           | 1 | cycrow | 420 | 	deleteTempData();
 | 
        
           | 114 | cycrow | 421 |   | 
        
           | 1 | cycrow | 422 | 	loadIntValue(is, &(body->bodySize), context);
 | 
        
           | 114 | cycrow | 423 |   | 
        
           | 1 | cycrow | 424 | 	if(!loadBones(body, is)){
 | 
        
           |  |  | 425 | 		bob->bodies.removeChild(--bob->bodies.end());
 | 
        
           |  |  | 426 | 		return false;
 | 
        
           |  |  | 427 | 	}
 | 
        
           | 114 | cycrow | 428 | 	if(!loadVertices(body, is, list)) {
 | 
        
           | 1 | cycrow | 429 | 		bob->bodies.removeChild(--bob->bodies.end());
 | 
        
           |  |  | 430 | 		return false;
 | 
        
           |  |  | 431 | 	}
 | 
        
           | 114 | cycrow | 432 |   | 
        
           | 1 | cycrow | 433 | 	if(!loadWeights(body, is)){
 | 
        
           |  |  | 434 | 		bob->bodies.removeChild(--bob->bodies.end());
 | 
        
           |  |  | 435 | 		return false;
 | 
        
           |  |  | 436 | 	}
 | 
        
           | 114 | cycrow | 437 |   | 
        
           | 1 | cycrow | 438 | 	if(m_weights.size() && m_weights.size()!=list.size()){
 | 
        
           |  |  | 439 | 		error(0, S_Error, "Number of Weights (%d) does not match number of Points (%d)", m_weights.size(), list.size());
 | 
        
           |  |  | 440 | 		bob->bodies.removeChild(--bob->bodies.end());
 | 
        
           |  |  | 441 | 		return false;
 | 
        
           |  |  | 442 | 	}
 | 
        
           | 114 | cycrow | 443 |   | 
        
           | 1 | cycrow | 444 | 	// move the points to array so we can access them with index
 | 
        
           | 114 | cycrow | 445 | 	m_vertices.resize(list.size());
 | 
        
           | 1 | cycrow | 446 | 	int i=0;
 | 
        
           | 114 | cycrow | 447 | 	for(VertexList::iterator &it=list.begin(); it!=list.end(); ++it, ++i){
 | 
        
           |  |  | 448 | 		m_vertices[i]=*it;
 | 
        
           | 1 | cycrow | 449 | 	}
 | 
        
           |  |  | 450 | 	list.clear();
 | 
        
           | 114 | cycrow | 451 |   | 
        
           |  |  | 452 | 	// reserve space in the vertex array (some of the vertices will be duplicated)
 | 
        
           |  |  | 453 | 	body->vertices.new_vertices.reserve((size_t)(m_vertices.size() * 2));
 | 
        
           |  |  | 454 | 	body->vertices.new_vertices.growby((size_t)(m_vertices.size() * 0.25));
 | 
        
           |  |  | 455 |   | 
        
           | 1 | cycrow | 456 | 	int endval;
 | 
        
           |  |  | 457 | 	do{
 | 
        
           |  |  | 458 | 		if(!loadPart(body, is)) {
 | 
        
           |  |  | 459 | 			bob->bodies.removeChild(--bob->bodies.end());
 | 
        
           |  |  | 460 | 			return false;
 | 
        
           |  |  | 461 | 		}
 | 
        
           | 114 | cycrow | 462 |   | 
        
           | 1 | cycrow | 463 | 		loadIntValue(is, &endval);
 | 
        
           |  |  | 464 | 		if(endval!=-99)
 | 
        
           |  |  | 465 | 			ungetValue(is);
 | 
        
           |  |  | 466 | 	}
 | 
        
           |  |  | 467 | 	while(is.good() && endval!=-99); // -99 means end of body
 | 
        
           | 114 | cycrow | 468 |   | 
        
           | 1 | cycrow | 469 | 	if(endval!=-99){
 | 
        
           |  |  | 470 | 		error(is.previous(), S_Error, "Unexpected end of document found while loading Body. Do you miss the '-99'?");
 | 
        
           |  |  | 471 | 		bob->bodies.removeChild(--bob->bodies.end());
 | 
        
           |  |  | 472 | 		return false;
 | 
        
           |  |  | 473 | 	}
 | 
        
           |  |  | 474 | 	if(!flagsFromString(is, body->bodyFlags)){
 | 
        
           |  |  | 475 | 		bob->bodies.removeChild(--bob->bodies.end());
 | 
        
           |  |  | 476 | 		return false;
 | 
        
           |  |  | 477 | 	}
 | 
        
           | 114 | cycrow | 478 |   | 
        
           |  |  | 479 | 	computeVertexTangents(*body);
 | 
        
           |  |  | 480 |   | 
        
           | 1 | cycrow | 481 | 	return true;
 | 
        
           |  |  | 482 | }
 | 
        
           |  |  | 483 | //---------------------------------------------------------------------------------
 | 
        
           | 114 | cycrow | 484 | bool bod_bob_parser::loadVertices(bob_body *body, token_stream& is, VertexList& points)
 | 
        
           | 1 | cycrow | 485 | {
 | 
        
           |  |  | 486 | 	bool bEnd;
 | 
        
           |  |  | 487 | 	int x, y, z;
 | 
        
           | 114 | cycrow | 488 | 	static const char *context="Vertex: ";
 | 
        
           |  |  | 489 |   | 
        
           | 1 | cycrow | 490 | 	do{
 | 
        
           |  |  | 491 | 		loadIntValue(is, &x, context);
 | 
        
           |  |  | 492 | 		loadIntValue(is, &y, context);
 | 
        
           |  |  | 493 | 		if(!loadIntValue(is, &z, context)) return false;
 | 
        
           | 114 | cycrow | 494 |   | 
        
           |  |  | 495 | 		if(x==-1 && y==-1 && z==-1) {
 | 
        
           |  |  | 496 | 			bEnd=true;
 | 
        
           |  |  | 497 | 			break;
 | 
        
           | 1 | cycrow | 498 | 		}
 | 
        
           | 114 | cycrow | 499 | 		/* SameVertices will take care of translating the BOD coords to BOB format */
 | 
        
           |  |  | 500 | 		points.push_back(new SameVertices(x, y, z));
 | 
        
           | 1 | cycrow | 501 | 	}
 | 
        
           |  |  | 502 | 	while(is.good());
 | 
        
           | 114 | cycrow | 503 |   | 
        
           | 1 | cycrow | 504 | 	if(!bEnd){
 | 
        
           |  |  | 505 | 		error(is.previous(), S_Error, "Unexpected end of document found while loading Points. Do you miss the '-1;-1;-1;'?");
 | 
        
           |  |  | 506 | 		return false;
 | 
        
           |  |  | 507 | 	}
 | 
        
           | 114 | cycrow | 508 |   | 
        
           | 1 | cycrow | 509 | 	return true;
 | 
        
           |  |  | 510 | }
 | 
        
           |  |  | 511 | //---------------------------------------------------------------------------------
 | 
        
           |  |  | 512 | // load part - bunch of faces/uv's
 | 
        
           | 114 | cycrow | 513 | bool bod_bob_parser::loadPart(bob_body *body, token_stream& is)
 | 
        
           | 1 | cycrow | 514 | {
 | 
        
           |  |  | 515 | 	int matIdx;
 | 
        
           |  |  | 516 | 	bool bRes=true;
 | 
        
           |  |  | 517 | 	static const char *context="Parts: ";
 | 
        
           | 114 | cycrow | 518 | 	bool x3data=false;
 | 
        
           |  |  | 519 |   | 
        
           |  |  | 520 | 	bob_part *part=new bob_part();
 | 
        
           |  |  | 521 |   | 
        
           | 1 | cycrow | 522 | 	loadIntValue(is, &matIdx, context);
 | 
        
           |  |  | 523 | 	do{
 | 
        
           | 114 | cycrow | 524 | 		// no longer truth - negative number is direct texture ID of animated texture
 | 
        
           |  |  | 525 | 		/*if(matIdx < 0)
 | 
        
           | 1 | cycrow | 526 | 			{ error(is.previous(), S_Error, "%sMaterial index must be >= 0", context); bRes=false; break; }
 | 
        
           | 114 | cycrow | 527 | 		*/
 | 
        
           |  |  | 528 | 		if(matIdx > 0 && ((size_t)matIdx > m_materials->size() - 1))
 | 
        
           | 1 | cycrow | 529 | 			error(is.previous(), S_Warning, "%sMaterial index out of range: %d", context, matIdx);
 | 
        
           | 114 | cycrow | 530 |   | 
        
           | 1 | cycrow | 531 | 		if((bRes=loadFace(matIdx, *body, *part, is))==false)
 | 
        
           |  |  | 532 | 			break;
 | 
        
           | 114 | cycrow | 533 |   | 
        
           | 1 | cycrow | 534 | 		if(is.tok() && is.tok()->type==token::t_openInstrBlock) {
 | 
        
           | 114 | cycrow | 535 | 			x3data = true;
 | 
        
           |  |  | 536 |   | 
        
           |  |  | 537 | 			if((bRes = loadCollisionBoxData(++is, *part)) == false)
 | 
        
           | 1 | cycrow | 538 | 				break;
 | 
        
           |  |  | 539 | 		}
 | 
        
           | 114 | cycrow | 540 |   | 
        
           | 1 | cycrow | 541 | 		loadIntValue(is, &matIdx, context);
 | 
        
           |  |  | 542 | 	}
 | 
        
           |  |  | 543 | 	while(matIdx!=-99 && is.good()); // -99 means end of part
 | 
        
           | 114 | cycrow | 544 |   | 
        
           |  |  | 545 | 	if(bRes && matIdx != -99){
 | 
        
           | 1 | cycrow | 546 | 		error(is.previous(), S_Error, "Unexpected end of document found while loading Part. Do you miss the '-99'?");
 | 
        
           | 114 | cycrow | 547 | 		bRes = false;
 | 
        
           | 1 | cycrow | 548 | 	}
 | 
        
           | 114 | cycrow | 549 |   | 
        
           | 1 | cycrow | 550 | 	if(bRes)
 | 
        
           | 114 | cycrow | 551 | 		bRes = flagsFromString(is, part->flags);
 | 
        
           |  |  | 552 |   | 
        
           |  |  | 553 | 	// set x3 flag if either we loaded x3 part values or settings::writeX3Data is set
 | 
        
           |  |  | 554 | 	if(x3data || m_settings->writeX3Data())
 | 
        
           |  |  | 555 | 		part->flags|=bob_part::FLAG_X3;
 | 
        
           |  |  | 556 |   | 
        
           | 1 | cycrow | 557 | 	if(bRes)
 | 
        
           |  |  | 558 | 		body->parts.push_back(part);
 | 
        
           |  |  | 559 | 	else
 | 
        
           |  |  | 560 | 		delete part;
 | 
        
           | 114 | cycrow | 561 |   | 
        
           | 1 | cycrow | 562 | 	return bRes;
 | 
        
           |  |  | 563 | };
 | 
        
           |  |  | 564 | //---------------------------------------------------------------------------------
 | 
        
           |  |  | 565 | bool bod_bob_parser::flagsFromString(token_stream& is, int& flags)
 | 
        
           |  |  | 566 | {
 | 
        
           |  |  | 567 | 	bool bRes;
 | 
        
           |  |  | 568 | 	token *t=loadValue(is);
 | 
        
           | 114 | cycrow | 569 |   | 
        
           | 1 | cycrow | 570 | 	flags=0;
 | 
        
           |  |  | 571 | 	if(bRes=(t!=NULL)){
 | 
        
           |  |  | 572 | 		int len=(int)strlen(t->text);
 | 
        
           |  |  | 573 | 		int val=1;
 | 
        
           |  |  | 574 | 		for(int i=len-1; i >= 0; i--, val<<=1 ){
 | 
        
           |  |  | 575 | 			switch(t->text[i]){
 | 
        
           |  |  | 576 | 				case '0':
 | 
        
           |  |  | 577 | 					break;
 | 
        
           |  |  | 578 | 				case '1':
 | 
        
           |  |  | 579 | 					flags|=val;
 | 
        
           |  |  | 580 | 					break;
 | 
        
           |  |  | 581 | 				default:
 | 
        
           |  |  | 582 | 					error(is.previous(), S_Error, "Invalid flags definition. Expected binary number");
 | 
        
           |  |  | 583 | 					bRes=false;
 | 
        
           |  |  | 584 | 					break;
 | 
        
           |  |  | 585 | 			}
 | 
        
           |  |  | 586 | 			if(bRes==false) break;
 | 
        
           |  |  | 587 | 		}
 | 
        
           |  |  | 588 | 	}
 | 
        
           |  |  | 589 | 	return bRes;
 | 
        
           |  |  | 590 | }
 | 
        
           |  |  | 591 | //---------------------------------------------------------------------------------
 | 
        
           |  |  | 592 | // load face - actual face and its uv's
 | 
        
           | 114 | cycrow | 593 | bool bod_bob_parser::loadFace(int matIdx, bob_body& body, bob_part& part, token_stream& is)
 | 
        
           | 1 | cycrow | 594 | {
 | 
        
           |  |  | 595 | 	int indexes[3];
 | 
        
           |  |  | 596 | 	int magic;
 | 
        
           | 114 | cycrow | 597 | 	int sgbits;
 | 
        
           | 1 | cycrow | 598 | 	double dtexX, dtexY;
 | 
        
           |  |  | 599 | 	static const char *context="Part: ";
 | 
        
           | 114 | cycrow | 600 |   | 
        
           | 1 | cycrow | 601 | 	for(int i=0; i < 3; i++){
 | 
        
           |  |  | 602 | 		if(loadIntValue(is, indexes + i, context)){
 | 
        
           | 114 | cycrow | 603 | 			if(indexes[i] < 0 || (size_t)indexes[i] >= m_vertices.size()){
 | 
        
           | 1 | cycrow | 604 | 				error(is.previous(), S_Error, "Point index out of range: point %d, index %d", i, indexes[i]);
 | 
        
           |  |  | 605 | 				return false;
 | 
        
           |  |  | 606 | 			}
 | 
        
           |  |  | 607 | 		}
 | 
        
           |  |  | 608 | 		else
 | 
        
           |  |  | 609 | 			return false;
 | 
        
           |  |  | 610 | 	}
 | 
        
           | 114 | cycrow | 611 |   | 
        
           | 1 | cycrow | 612 | 	bool bRes=true;
 | 
        
           | 114 | cycrow | 613 |   | 
        
           |  |  | 614 | 	/*
 | 
        
           |  |  | 615 | 		original (old) meaning of the 'magic' number (now I'm using flags)
 | 
        
           |  |  | 616 | 		magic: -1 means no smoothing and no uv, -9 means no smoothing and uv
 | 
        
           |  |  | 617 | 		        -17 means smoothing and no uv, -25 means smoothing and uv
 | 
        
           |  |  | 618 | 	*/
 | 
        
           | 1 | cycrow | 619 |   | 
        
           |  |  | 620 | 	bRes&=loadIntValue(is, &magic, context);
 | 
        
           | 114 | cycrow | 621 |   | 
        
           |  |  | 622 | 	if(magic >= 0){
 | 
        
           |  |  | 623 | 		error(is.tok(), S_Error, "Faces are written using polygons not triangles - cannot continue");
 | 
        
           |  |  | 624 | 		return false;
 | 
        
           |  |  | 625 | 	}
 | 
        
           |  |  | 626 |   | 
        
           |  |  | 627 | 	magic*=-1;
 | 
        
           |  |  | 628 |   | 
        
           |  |  | 629 | 	if(magic & bob_part::BOD_FLAG_SGBITS)
 | 
        
           |  |  | 630 | 		bRes&=loadIntValue(is, &sgbits, context);
 | 
        
           | 1 | cycrow | 631 | 	else
 | 
        
           | 114 | cycrow | 632 | 		sgbits=0;
 | 
        
           |  |  | 633 |   | 
        
           | 1 | cycrow | 634 | 	if(bRes==false) return false;
 | 
        
           | 114 | cycrow | 635 |   | 
        
           |  |  | 636 | 	bob_vertex *vertex;
 | 
        
           |  |  | 637 | 	bob_face *face=new bob_face();
 | 
        
           |  |  | 638 | 	bob_vertex *points_ar[3];
 | 
        
           |  |  | 639 |   | 
        
           | 1 | cycrow | 640 | 	for(int i=0; i < 3; i++){
 | 
        
           | 114 | cycrow | 641 | 		if(magic & bob_part::BOD_FLAG_UV){
 | 
        
           | 1 | cycrow | 642 | 			loadDoubleValue(is, &dtexX, context);
 | 
        
           |  |  | 643 | 			bRes&=loadDoubleValue(is, &dtexY, context);
 | 
        
           |  |  | 644 | 		}
 | 
        
           |  |  | 645 | 		else{
 | 
        
           | 114 | cycrow | 646 | 			dtexX=dtexY=0;
 | 
        
           | 1 | cycrow | 647 | 		}
 | 
        
           | 114 | cycrow | 648 |   | 
        
           |  |  | 649 | 		/*
 | 
        
           |  |  | 650 | 			look (or create) for vertex with same coords and same sgbits
 | 
        
           |  |  | 651 | 		*/
 | 
        
           |  |  | 652 | 		SameSG_UVs *SGgroup=m_vertices[indexes[i]]->findTextureCoords(sgbits);
 | 
        
           |  |  | 653 | 		uv_coord *uv=NULL;
 | 
        
           | 1 | cycrow | 654 |   | 
        
           | 114 | cycrow | 655 | 		/*
 | 
        
           |  |  | 656 | 			look for the same UV coords or use anything if no UV is specified
 | 
        
           |  |  | 657 | 		*/
 | 
        
           |  |  | 658 | 		if(magic & bob_part::BOD_FLAG_UV)
 | 
        
           |  |  | 659 | 			uv=SGgroup->findUV(dtexX, dtexY);
 | 
        
           |  |  | 660 | 		else 
 | 
        
           |  |  | 661 | 			uv=SGgroup->findNullUV();
 | 
        
           | 1 | cycrow | 662 |   | 
        
           | 114 | cycrow | 663 | 		if(uv==NULL){
 | 
        
           |  |  | 664 | 			if(magic & bob_part::BOD_FLAG_UV)
 | 
        
           |  |  | 665 | 				uv=SGgroup->createUV(dtexX, dtexY);
 | 
        
           |  |  | 666 | 			else
 | 
        
           |  |  | 667 | 				uv=SGgroup->createNullUV();
 | 
        
           |  |  | 668 |   | 
        
           |  |  | 669 | 			vertex=uv->createBOBVertex();
 | 
        
           | 1 | cycrow | 670 |   | 
        
           | 114 | cycrow | 671 | 			uv->vertexIndex=(int)body.vertices.new_vertices.size();
 | 
        
           |  |  | 672 | 			body.vertices.new_vertices.push_back(vertex);
 | 
        
           |  |  | 673 |   | 
        
           |  |  | 674 | 			points_ar[i]=vertex; // this will be used to fetch values found in intruction block
 | 
        
           |  |  | 675 |   | 
        
           | 1 | cycrow | 676 | 			// now insert the appropriate weight
 | 
        
           |  |  | 677 | 			if(m_weights.size())
 | 
        
           | 114 | cycrow | 678 | 				body.weights.new_weights.push_back(new bob_weight(*m_weights[indexes[i]]));
 | 
        
           | 1 | cycrow | 679 | 		}
 | 
        
           |  |  | 680 | 		else
 | 
        
           |  |  | 681 | 			points_ar[i]=NULL;
 | 
        
           | 114 | cycrow | 682 |   | 
        
           |  |  | 683 | 		face->values[i]=uv->vertexIndex;
 | 
        
           | 1 | cycrow | 684 | 	}
 | 
        
           | 114 | cycrow | 685 | 	face->flags=1; // always 1 (or 0)
 | 
        
           |  |  | 686 |   | 
        
           | 1 | cycrow | 687 | 	part.facelist(matIdx)->push_back(face);
 | 
        
           | 114 | cycrow | 688 |   | 
        
           |  |  | 689 | 	bRes = loadSpecialValues(points_ar, is);
 | 
        
           | 1 | cycrow | 690 |   | 
        
           | 114 | cycrow | 691 | 	return bRes;
 | 
        
           | 1 | cycrow | 692 | }
 | 
        
           |  |  | 693 | //---------------------------------------------------------------------------------
 | 
        
           |  |  | 694 | // load special values which may be "hidden" in instruction block after standard part definition
 | 
        
           |  |  | 695 | // example: /! { 1;2;3; } { 4;5;6; } { 7;8;9; } !/
 | 
        
           | 114 | cycrow | 696 | bool bod_bob_parser::loadSpecialValues(bob_vertex *points[3], token_stream& is)
 | 
        
           | 1 | cycrow | 697 | {
 | 
        
           | 114 | cycrow | 698 | 	bob_vertex dummy_pnt;
 | 
        
           |  |  | 699 |   | 
        
           | 1 | cycrow | 700 | 	token *t=is.tok();
 | 
        
           | 114 | cycrow | 701 |   | 
        
           | 1 | cycrow | 702 | 	if(t && t->type==token::t_openInstrBlock){
 | 
        
           |  |  | 703 | 		++is;
 | 
        
           | 114 | cycrow | 704 |   | 
        
           |  |  | 705 | 		t=is.tok();
 | 
        
           |  |  | 706 | 		while(t != NULL && t->type != token::t_closeInstrBlock){
 | 
        
           |  |  | 707 | 			if(t == NULL || t->type != token::t_text){
 | 
        
           |  |  | 708 | 				error(t ? t : is.previous(), S_Error, "Expected identifier in instruction block.");
 | 
        
           |  |  | 709 | 				return false;
 | 
        
           |  |  | 710 | 			}
 | 
        
           |  |  | 711 |   | 
        
           |  |  | 712 | 			if(strcmp(t->text, "N") == 0){
 | 
        
           |  |  | 713 | 				if(!loadFaceNormal(is, points))
 | 
        
           | 1 | cycrow | 714 | 					return false;
 | 
        
           |  |  | 715 | 			}
 | 
        
           | 114 | cycrow | 716 | 			else if(strcmp(t->text, "XPINFO") == 0){
 | 
        
           |  |  | 717 | 				t = (++is).tok();
 | 
        
           |  |  | 718 | 				if(t == NULL || t->type != token::t_colon){
 | 
        
           |  |  | 719 | 					error(t ? t : is.previous(), S_Error, "Expected ':' after '%s'", is.previous()->getText());
 | 
        
           | 1 | cycrow | 720 | 					return false;
 | 
        
           | 114 | cycrow | 721 | 				}	
 | 
        
           |  |  | 722 | 				++is;
 | 
        
           |  |  | 723 | 				for(int i = 0; i < 3; i++){
 | 
        
           |  |  | 724 | 					if(!loadSpecialPointValues(is, points[i]))
 | 
        
           |  |  | 725 | 						return false;
 | 
        
           |  |  | 726 | 				}
 | 
        
           | 1 | cycrow | 727 | 			}
 | 
        
           | 114 | cycrow | 728 | 			else {
 | 
        
           |  |  | 729 | 				error(t, S_Error, "Unexpected identifier in instruction block: '%s'", t);
 | 
        
           |  |  | 730 | 				return false;
 | 
        
           |  |  | 731 | 			}
 | 
        
           |  |  | 732 | 			t=is.tok();
 | 
        
           | 1 | cycrow | 733 | 		}
 | 
        
           |  |  | 734 | 		if(t==NULL || t->type!=token::t_closeInstrBlock){
 | 
        
           |  |  | 735 | 			error(t ? t : is.previous(), S_Error, "Expected end of instruction block '!/' after '%s'", is.previous());
 | 
        
           |  |  | 736 | 			return false;
 | 
        
           |  |  | 737 | 		}
 | 
        
           |  |  | 738 | 		++is;
 | 
        
           |  |  | 739 | 	}
 | 
        
           |  |  | 740 | 	return true;
 | 
        
           |  |  | 741 | }
 | 
        
           |  |  | 742 | //---------------------------------------------------------------------------------
 | 
        
           | 114 | cycrow | 743 | // load one block from extra info in instruction block
 | 
        
           | 1 | cycrow | 744 | // example: { 1; 2; 3; }
 | 
        
           | 114 | cycrow | 745 |   | 
        
           |  |  | 746 | // point can be null!
 | 
        
           |  |  | 747 | bool bod_bob_parser::loadSpecialPointValues(token_stream& is, bob_vertex *point)
 | 
        
           | 1 | cycrow | 748 | {
 | 
        
           |  |  | 749 | 	static const char *context="Part - Extra point info: ";
 | 
        
           | 114 | cycrow | 750 |   | 
        
           | 1 | cycrow | 751 | 	token *t=is.tok();
 | 
        
           | 114 | cycrow | 752 | 	if(t==NULL || t->type!=token::t_openCrBracket){
 | 
        
           | 1 | cycrow | 753 | 		error(t ? t : is.previous(), S_Error, "Expected beginning of block after '%s'", is.previous()->getText());
 | 
        
           |  |  | 754 | 		return false;
 | 
        
           |  |  | 755 | 	}
 | 
        
           |  |  | 756 | 	++is;
 | 
        
           | 114 | cycrow | 757 |   | 
        
           |  |  | 758 | 	double x, y;
 | 
        
           |  |  | 759 |   | 
        
           |  |  | 760 | 	if(!loadDoubleValue(is, &x, context))
 | 
        
           |  |  | 761 | 		return false;
 | 
        
           |  |  | 762 | 	if(!loadDoubleValue(is, &y, context))
 | 
        
           |  |  | 763 | 		return false;
 | 
        
           |  |  | 764 |   | 
        
           |  |  | 765 | 	if(point != NULL){
 | 
        
           |  |  | 766 | 		point->weirdCoords.x = x;
 | 
        
           |  |  | 767 | 		point->weirdCoords.y = y;
 | 
        
           | 1 | cycrow | 768 |   | 
        
           | 114 | cycrow | 769 | 		point->flags|=bob_vertex::FLAG_WEIRD_STUFF;
 | 
        
           | 1 | cycrow | 770 | 	}
 | 
        
           | 114 | cycrow | 771 |   | 
        
           |  |  | 772 | 	if(is.tok()==NULL || is.tok()->type!=token::t_closeCrBracket){
 | 
        
           |  |  | 773 | 		if(is.tok()==NULL)
 | 
        
           | 1 | cycrow | 774 | 			error(is.previous(), S_Error, "Unexpected end of document found while loading extra point info. Do you miss the '}'?");
 | 
        
           |  |  | 775 | 		else
 | 
        
           |  |  | 776 | 			error(t, S_Error, "Unexpected '%s' found while loading extra point info", t->getText());
 | 
        
           |  |  | 777 | 		return false;
 | 
        
           |  |  | 778 | 	}
 | 
        
           | 114 | cycrow | 779 |   | 
        
           | 1 | cycrow | 780 | 	++is;
 | 
        
           | 114 | cycrow | 781 |   | 
        
           | 1 | cycrow | 782 | 	return true;
 | 
        
           |  |  | 783 | }
 | 
        
           |  |  | 784 | //---------------------------------------------------------------------------------
 | 
        
           | 114 | cycrow | 785 | bool bod_bob_parser::loadBones(bob_body *body, token_stream& is)
 | 
        
           | 1 | cycrow | 786 | {
 | 
        
           |  |  | 787 | 	const token *t=is.tok();
 | 
        
           |  |  | 788 | 	static const char *context2="Bones: ";
 | 
        
           |  |  | 789 | 	static const char *context="Bone: ";
 | 
        
           | 114 | cycrow | 790 |   | 
        
           | 1 | cycrow | 791 | 	if(!(t && t->type==token::t_text && strcmp(t->text, "BONES")==0))
 | 
        
           |  |  | 792 | 		return true;
 | 
        
           | 114 | cycrow | 793 |   | 
        
           | 1 | cycrow | 794 | 	t=(++is).tok();
 | 
        
           |  |  | 795 | 	if(t==NULL || t->type!=token::t_colon){
 | 
        
           |  |  | 796 | 		error(t ? t : is.previous(), S_Error, "Expected ':' after '%s'", is.previous()->getText());
 | 
        
           |  |  | 797 | 		return false;
 | 
        
           |  |  | 798 | 	}
 | 
        
           |  |  | 799 | 	if(!checkImmediatePlacement(is.previous(), t))
 | 
        
           |  |  | 800 | 		return false;
 | 
        
           | 114 | cycrow | 801 |   | 
        
           | 1 | cycrow | 802 | 	int count;
 | 
        
           |  |  | 803 | 	if(!loadIntValue(++is, &count, context2))
 | 
        
           |  |  | 804 | 		return false;
 | 
        
           | 114 | cycrow | 805 |   | 
        
           | 1 | cycrow | 806 | 	char *name;
 | 
        
           |  |  | 807 | 	for(int i=0; i < count; i++){
 | 
        
           |  |  | 808 | 		name=loadString(is, context);
 | 
        
           |  |  | 809 | 		if(name==NULL) return false;
 | 
        
           |  |  | 810 | 		body->bones.push_back(name);
 | 
        
           |  |  | 811 | 	}
 | 
        
           | 114 | cycrow | 812 |   | 
        
           | 1 | cycrow | 813 | 	return !is.fail();
 | 
        
           |  |  | 814 | }
 | 
        
           |  |  | 815 | //---------------------------------------------------------------------------------
 | 
        
           |  |  | 816 | // load the weights to temporary array. Weights from this array will then be inflated and added to body
 | 
        
           | 114 | cycrow | 817 | bool bod_bob_parser::loadWeights(bob_body *body, token_stream& is)
 | 
        
           | 1 | cycrow | 818 | {
 | 
        
           |  |  | 819 | 	const token *t=is.tok();
 | 
        
           |  |  | 820 | 	static const char *context="Weight: ";
 | 
        
           |  |  | 821 | 	static const char *context2="Weights: ";
 | 
        
           | 114 | cycrow | 822 |   | 
        
           | 1 | cycrow | 823 | 	if(!(t && t->type==token::t_text && strcmp(t->text, "WEIGHTS")==0))
 | 
        
           |  |  | 824 | 		return true;
 | 
        
           | 114 | cycrow | 825 |   | 
        
           | 1 | cycrow | 826 | 	int count;
 | 
        
           |  |  | 827 | 	if(!loadIntValue(++is, &count, context2))
 | 
        
           |  |  | 828 | 		return false;
 | 
        
           | 114 | cycrow | 829 |   | 
        
           | 1 | cycrow | 830 | 	bool bRes=true;
 | 
        
           |  |  | 831 | 	int v; double d;
 | 
        
           | 114 | cycrow | 832 | 	bob_weight *w;
 | 
        
           |  |  | 833 |   | 
        
           | 1 | cycrow | 834 | 	m_weights.resize(count, 0);
 | 
        
           | 114 | cycrow | 835 |   | 
        
           | 1 | cycrow | 836 | 	for(int i=0; i < count; i++){
 | 
        
           | 114 | cycrow | 837 | 		w=new bob_weight();
 | 
        
           | 1 | cycrow | 838 | 		do{
 | 
        
           | 114 | cycrow | 839 | 			if(!loadIntValue(is, &v, context))
 | 
        
           | 1 | cycrow | 840 | 				{ bRes=false; break; }
 | 
        
           | 114 | cycrow | 841 | 			if(v==-1)
 | 
        
           | 1 | cycrow | 842 | 				break;
 | 
        
           | 114 | cycrow | 843 |   | 
        
           | 1 | cycrow | 844 | 			if(v < 0 || (size_t)v >= body->bones.size()){
 | 
        
           |  |  | 845 | 				error(is.previous(), S_Error, "Weight: Bone index out of range (%d)", v);
 | 
        
           |  |  | 846 | 				{ bRes=false; break; }
 | 
        
           |  |  | 847 | 			}
 | 
        
           | 114 | cycrow | 848 |   | 
        
           |  |  | 849 | 			if(!loadDoubleValue(is, &d, context))
 | 
        
           | 1 | cycrow | 850 | 				{ bRes=false; break; }
 | 
        
           | 114 | cycrow | 851 |   | 
        
           |  |  | 852 | 			bob_weight::value val;
 | 
        
           | 1 | cycrow | 853 | 			val.boneIdx=v;
 | 
        
           | 114 | cycrow | 854 |   | 
        
           | 1 | cycrow | 855 | 			__asm{
 | 
        
           | 114 | cycrow | 856 | 				/* 
 | 
        
           |  |  | 857 | 					val.boneCoefficient = bob_weight::value::multiplier * d 
 | 
        
           |  |  | 858 | 				*/
 | 
        
           |  |  | 859 | 				fild bob_weight::value::MULTIPLIER
 | 
        
           | 1 | cycrow | 860 | 				fmul d
 | 
        
           |  |  | 861 | 				fistp val.boneCoefficient
 | 
        
           |  |  | 862 | 			}
 | 
        
           |  |  | 863 | 			w->values.push_back(val);
 | 
        
           |  |  | 864 | 		}
 | 
        
           |  |  | 865 | 		while(!is.fail());
 | 
        
           |  |  | 866 | 		if(is.fail()){
 | 
        
           |  |  | 867 | 			error(is.previous(), S_Error, "Unexpected end of document found while loading Weights. Do you miss the '-1'?");
 | 
        
           |  |  | 868 | 			bRes=false;
 | 
        
           |  |  | 869 | 		}
 | 
        
           |  |  | 870 | 		if(bRes==false){
 | 
        
           |  |  | 871 | 			delete w;
 | 
        
           |  |  | 872 | 			break;
 | 
        
           |  |  | 873 | 		}
 | 
        
           |  |  | 874 | 		m_weights[i]=w;
 | 
        
           |  |  | 875 | 	}
 | 
        
           |  |  | 876 | 	if(bRes){
 | 
        
           | 114 | cycrow | 877 | 		if(!loadIntValue(is, &v, context2))
 | 
        
           | 1 | cycrow | 878 | 			bRes=false;
 | 
        
           |  |  | 879 | 		else if(v!=-1){
 | 
        
           |  |  | 880 | 			error(is.previous(), S_Error, "Expected '-1' after end of Weights");
 | 
        
           |  |  | 881 | 			bRes=false;
 | 
        
           |  |  | 882 | 		}
 | 
        
           |  |  | 883 | 	}
 | 
        
           |  |  | 884 | 	return bRes;
 | 
        
           |  |  | 885 | }
 | 
        
           |  |  | 886 | //---------------------------------------------------------------------------------
 | 
        
           | 114 | cycrow | 887 | bool bod_bob_parser::loadCollisionBoxData(token_stream& is, bob_part& part)
 | 
        
           | 1 | cycrow | 888 | {
 | 
        
           | 114 | cycrow | 889 | 	static char *context="Collision box: ";
 | 
        
           |  |  | 890 | 	static char *HDR="COLLISION_BOX";
 | 
        
           |  |  | 891 |   | 
        
           |  |  | 892 | 	if(is.tok()==NULL || is.tok()->type!=token::t_text || strcmp(is.tok()->text, HDR)!=0) {
 | 
        
           |  |  | 893 | 		error(is.tok() ? is.tok() : is.previous(), S_Error, "Expected '%s' here", HDR);
 | 
        
           |  |  | 894 | 		return false;
 | 
        
           | 1 | cycrow | 895 | 	}
 | 
        
           | 114 | cycrow | 896 | 	if((++is).tok()==NULL || is.tok()->type!=token::t_colon){
 | 
        
           |  |  | 897 | 		error(is.tok() ? is.tok() : is.previous(), S_Error, "Expected ':' after '%s'", HDR);
 | 
        
           |  |  | 898 | 		return false;
 | 
        
           |  |  | 899 | 	}
 | 
        
           |  |  | 900 |   | 
        
           |  |  | 901 | 	++is;
 | 
        
           |  |  | 902 |   | 
        
           |  |  | 903 | 	loadDoubleValue(is, &part.collisionBox.boxOffset.x, "Box offset");
 | 
        
           |  |  | 904 | 	loadDoubleValue(is, &part.collisionBox.boxOffset.y, "Box offset");
 | 
        
           |  |  | 905 | 	if(!loadDoubleValue(is, &part.collisionBox.boxOffset.z, "Box offset"))
 | 
        
           |  |  | 906 | 		return false;
 | 
        
           |  |  | 907 |   | 
        
           |  |  | 908 | 	if(!loadDoubleValue(is, &part.collisionBox.sphereDiameter, "Sphere diameter"))
 | 
        
           |  |  | 909 | 		return false;
 | 
        
           |  |  | 910 |   | 
        
           |  |  | 911 | 	loadDoubleValue(is, &part.collisionBox.boxSize.x, "Box size");
 | 
        
           |  |  | 912 | 	loadDoubleValue(is, &part.collisionBox.boxSize.y, "Box size");
 | 
        
           |  |  | 913 | 	if(!loadDoubleValue(is, &part.collisionBox.boxSize.z, "Box size"))
 | 
        
           |  |  | 914 | 		return false;
 | 
        
           | 1 | cycrow | 915 |   | 
        
           | 114 | cycrow | 916 | 	part.collisionBox.sphereOffset = part.collisionBox.boxOffset;
 | 
        
           |  |  | 917 |   | 
        
           |  |  | 918 | 	if(is.tok()==NULL || is.tok()->type!=token::t_closeInstrBlock){
 | 
        
           |  |  | 919 | 		error(is.tok() ? is.tok() : is.previous(), S_Error, "Expected '!/' after end of Collision box");
 | 
        
           |  |  | 920 | 		return false;
 | 
        
           | 1 | cycrow | 921 | 	}
 | 
        
           | 114 | cycrow | 922 | 	++is;
 | 
        
           |  |  | 923 | 	return true;
 | 
        
           | 1 | cycrow | 924 | }
 | 
        
           |  |  | 925 | //---------------------------------------------------------------------------------
 | 
        
           | 114 | cycrow | 926 | bool bod_bob_parser::loadFaceNormal(token_stream& is, bob_vertex *points[3])
 | 
        
           | 1 | cycrow | 927 | {
 | 
        
           | 114 | cycrow | 928 | 	token *t;
 | 
        
           |  |  | 929 | 	t=is.tok();
 | 
        
           |  |  | 930 | 	if(t==NULL || t->type!=token::t_text || *t->text!='N'){
 | 
        
           |  |  | 931 | 		error(t, S_Error, "Error loading face normal: expecting 'N:'");
 | 
        
           |  |  | 932 | 		return false;
 | 
        
           |  |  | 933 | 	}
 | 
        
           |  |  | 934 | 	t=(++is).tok();
 | 
        
           |  |  | 935 | 	if(t==NULL || t->type!=token::t_colon){
 | 
        
           |  |  | 936 | 		error(t, S_Error, "Expecting ':' after '%'", is.previous()->getText());
 | 
        
           |  |  | 937 | 		return false;
 | 
        
           |  |  | 938 | 	}
 | 
        
           |  |  | 939 | 	++is;
 | 
        
           |  |  | 940 |   | 
        
           |  |  | 941 | 	t = is.tok();
 | 
        
           |  |  | 942 | 	if(t == NULL || t->type != token::t_openCrBracket){
 | 
        
           |  |  | 943 | 		error(t ? t : is.previous(), S_Error, "Expected beginning of block after '%s'", is.previous()->getText());
 | 
        
           |  |  | 944 | 		return false;
 | 
        
           |  |  | 945 | 	}
 | 
        
           | 1 | cycrow | 946 |   | 
        
           | 114 | cycrow | 947 | 	++is;
 | 
        
           |  |  | 948 |   | 
        
           |  |  | 949 | 	// buffer for normals - contains either 1 or 3 records
 | 
        
           |  |  | 950 | 	normal_vector normals[3];
 | 
        
           |  |  | 951 |   | 
        
           |  |  | 952 | 	int i;
 | 
        
           |  |  | 953 | 	// for each vertex
 | 
        
           |  |  | 954 | 	for(i = 0; i < 3; i++){
 | 
        
           |  |  | 955 | 		double d[3];
 | 
        
           |  |  | 956 |   | 
        
           |  |  | 957 | 		// load the vertex normal
 | 
        
           |  |  | 958 | 		for(int j=0; j < 3; j++){
 | 
        
           |  |  | 959 | 			if(!loadDoubleValue(is, d + j, "Face normal: "))
 | 
        
           |  |  | 960 | 				return false;
 | 
        
           | 1 | cycrow | 961 | 		}
 | 
        
           | 114 | cycrow | 962 | 		normals[i] = normal_vector(d[0], d[1], d[2]);
 | 
        
           | 1 | cycrow | 963 |   | 
        
           | 114 | cycrow | 964 | 		t = is.tok();
 | 
        
           |  |  | 965 | 		// bail out if end of block was reached - case of short (3 numbers) normal block
 | 
        
           |  |  | 966 | 		if(i == 0 && t && t->type == token::t_closeCrBracket)
 | 
        
           | 1 | cycrow | 967 | 			break;
 | 
        
           | 114 | cycrow | 968 | 	}	
 | 
        
           |  |  | 969 | 	int max = i > 0 ? 2 : 0;
 | 
        
           |  |  | 970 | 	for(i = 0; i < 3; i++){
 | 
        
           |  |  | 971 | 		if(points[i]!=NULL)
 | 
        
           |  |  | 972 | 			points[i]->normalVector = normals[__min(i, max)];
 | 
        
           | 1 | cycrow | 973 | 	}
 | 
        
           | 114 | cycrow | 974 |   | 
        
           |  |  | 975 | 	if(t == NULL || t->type != token::t_closeCrBracket){
 | 
        
           |  |  | 976 | 		error(t ? t : is.previous(), S_Error, "Expected end of block after '%s'", is.previous()->getText());
 | 
        
           |  |  | 977 | 		return false;
 | 
        
           |  |  | 978 | 	}
 | 
        
           |  |  | 979 | 	++is;
 | 
        
           |  |  | 980 |   | 
        
           |  |  | 981 | 	return true;
 | 
        
           | 1 | cycrow | 982 | }
 | 
        
           |  |  | 983 | //---------------------------------------------------------------------------------
 | 
        
           | 114 | cycrow | 984 | /*
 | 
        
           |  |  | 985 | 	computation taken from C4 3D engine (http://www.terathon.com/code/tangent.php)
 | 
        
           |  |  | 986 | */
 | 
        
           |  |  | 987 | void bod_bob_parser::computeVertexTangents(bob_body& body)
 | 
        
           | 1 | cycrow | 988 | {
 | 
        
           | 114 | cycrow | 989 | 	typedef ext::array<bob_vertex*> vertex_array;
 | 
        
           | 1 | cycrow | 990 |   | 
        
           | 114 | cycrow | 991 | 	bob_vertices::VertexArray &vertices=body.vertices.new_vertices;
 | 
        
           | 1 | cycrow | 992 |   | 
        
           | 114 | cycrow | 993 | 	// stuff for the computation
 | 
        
           |  |  | 994 | 	vertex v1, v2, v3; // vertices
 | 
        
           |  |  | 995 | 	geometry::point2d<double> w1, w2, w3; // uv coords
 | 
        
           |  |  | 996 | 	int i1, i2, i3; // vertex indexes
 | 
        
           | 1 | cycrow | 997 |   | 
        
           | 114 | cycrow | 998 | 	vector *tmp_tangents=new vector[vertices.size()];
 | 
        
           | 1 | cycrow | 999 |   | 
        
           | 114 | cycrow | 1000 | 	// every part in body
 | 
        
           |  |  | 1001 | 	for(bob_parts::iterator &part_it=body.parts.begin(); part_it!=body.parts.end(); part_it++){
 | 
        
           |  |  | 1002 | 		// every face list in a part
 | 
        
           |  |  | 1003 | 		for(bob_part::iterator &facelist_it=part_it->begin(); facelist_it!=part_it->end(); facelist_it++){
 | 
        
           |  |  | 1004 | 			// every face in face list
 | 
        
           |  |  | 1005 | 			for(bob_face_list::iterator &face_it=facelist_it->begin(); face_it!=facelist_it->end(); ++face_it){
 | 
        
           |  |  | 1006 | 				i1=face_it->values[0]; i2=face_it->values[1]; i3=face_it->values[2];
 | 
        
           |  |  | 1007 |   | 
        
           |  |  | 1008 | 				v1=*vertices[i1]; v2=*vertices[i2]; v3=*vertices[i3];
 | 
        
           |  |  | 1009 | 				w1=vertices[i1]->textureCoords; w2=vertices[i2]->textureCoords; w3=vertices[i3]->textureCoords;
 | 
        
           |  |  | 1010 |   | 
        
           |  |  | 1011 | 				double x1 = v2.x - v1.x;
 | 
        
           |  |  | 1012 | 				double x2 = v3.x - v1.x;
 | 
        
           |  |  | 1013 | 				double y1 = v2.y - v1.y;
 | 
        
           |  |  | 1014 | 				double y2 = v3.y - v1.y;
 | 
        
           |  |  | 1015 | 				double z1 = v2.z - v1.z;
 | 
        
           |  |  | 1016 | 				double z2 = v3.z - v1.z;
 | 
        
           |  |  | 1017 |   | 
        
           |  |  | 1018 | 				double s1 = w2.x - w1.x;
 | 
        
           |  |  | 1019 | 				double s2 = w3.x - w1.x;
 | 
        
           |  |  | 1020 | 				double t1 = w2.y - w1.y;
 | 
        
           |  |  | 1021 | 				double t2 = w3.y - w1.y;
 | 
        
           |  |  | 1022 |   | 
        
           |  |  | 1023 | 				double cp=s1 * t2 - s2 * t1;
 | 
        
           |  |  | 1024 |   | 
        
           |  |  | 1025 | 				if(cp!=0) {
 | 
        
           |  |  | 1026 | 					double r = 1.0 / cp;
 | 
        
           |  |  | 1027 | 					vector sdir((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r,
 | 
        
           |  |  | 1028 | 									(t2 * z1 - t1 * z2) * r);
 | 
        
           |  |  | 1029 |   | 
        
           |  |  | 1030 | 					tmp_tangents[i1] += sdir;
 | 
        
           |  |  | 1031 | 					tmp_tangents[i2] += sdir;
 | 
        
           |  |  | 1032 | 					tmp_tangents[i3] += sdir;
 | 
        
           |  |  | 1033 | 				}
 | 
        
           |  |  | 1034 | 			}
 | 
        
           |  |  | 1035 | 		}
 | 
        
           | 1 | cycrow | 1036 | 	}
 | 
        
           | 114 | cycrow | 1037 |   | 
        
           |  |  | 1038 | 	for(vertex_array::size_type i=0; i < vertices.size(); i++){
 | 
        
           |  |  | 1039 | 		const vector& n=vertices[(vertex_array::difference_type)i]->normalVector;
 | 
        
           |  |  | 1040 | 		const vector& t=tmp_tangents[i];
 | 
        
           |  |  | 1041 |   | 
        
           |  |  | 1042 | 		if(!t.isZero()){
 | 
        
           |  |  | 1043 | 			// Gram-Schmidt orthogonalize
 | 
        
           |  |  | 1044 | 			vertices[(vertex_array::difference_type)i]->tangentVector = (t - n * n.dot(t)).normalize();
 | 
        
           |  |  | 1045 | 		}
 | 
        
           |  |  | 1046 | 	}
 | 
        
           |  |  | 1047 |   | 
        
           |  |  | 1048 | 	delete[] tmp_tangents;
 | 
        
           | 1 | cycrow | 1049 | }
 | 
        
           |  |  | 1050 | //---------------------------------------------------------------------------------
 |