Subversion Repositories spk

Rev

Rev 1 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
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
//---------------------------------------------------------------------------------