Subversion Repositories spk

Rev

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