Subversion Repositories spk

Rev

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

Rev Author Line No. Line
1 cycrow 1
#include "bod_cut_parser.h"
2
#include "../common/strutils.h"
3
//---------------------------------------------------------------------------------
114 cycrow 4
bool bod_cut_parser::compile(token_stream& is, obinaryfilestream& os)
1 cycrow 5
{
114 cycrow 6
	os << bob_dom_cut::HDR_BEGIN;
7
 
1 cycrow 8
	bob_dom_cut *cut=loadCUT(is, &os, true);
114 cycrow 9
 
1 cycrow 10
	//if(cut)
11
		//cut->toFile(os);
114 cycrow 12
 
1 cycrow 13
	delete cut;
114 cycrow 14
 
15
	os << bob_dom_cut::HDR_END;
16
 
1 cycrow 17
	return cut!=NULL;
18
}
19
//---------------------------------------------------------------------------------
20
bob_dom_cut * bod_cut_parser::loadCUT(token_stream& is)
21
{
114 cycrow 22
	obinaryfilestream *dummy=0;
23
 
1 cycrow 24
	return loadCUT(is, dummy, false);
25
}
26
//---------------------------------------------------------------------------------
27
// this is bit weird function as it serves for 2 purposes: it can return loaded cut object
28
// or it can directly output parts of cut as it's being loaded
114 cycrow 29
bob_dom_cut * bod_cut_parser::loadCUT(token_stream& is, obinaryfilestream *os, bool bDirectOutput)
1 cycrow 30
{
31
	bod_text_parser::token *t;
114 cycrow 32
	bob_path *actPath=0;
33
	bob_stat *actStat=0;
1 cycrow 34
	bob_dom_cut *cut=new bob_dom_cut(m_settings);
114 cycrow 35
 
1 cycrow 36
	// used for direct output
37
	int pathCountOffset;
38
	int pathCount=0;
114 cycrow 39
 
1 cycrow 40
	bool bErrors=false;
41
	bool bRes=false;
114 cycrow 42
 
1 cycrow 43
	while(is.good() && is.tok()->type==token::t_hdrinfo){
44
		if(cut->info.text()!=0)
45
			error(is.tok(), S_Warning, "Header info already defined, last value will be used");
46
		cut->info.text(is.tok()->text);
47
		++is;
48
	}
49
 
50
	do{
51
		// VERSION
52
		t=is.tok();
53
		if(t==NULL || t->type!=token::t_text || strcmp(t->text, "VER")!=0)
54
			{ error(t ? t : is.previous(), S_Error, "Expected version specification"); break; }
114 cycrow 55
 
1 cycrow 56
		t=(++is).tok();
57
		if(t==NULL || t->type!=token::t_colon)
58
			{ error(t ? t : is.previous(), S_Error, "Expected ':' after '%s'", is.previous()->text); break; }
114 cycrow 59
 
60
		if(!checkImmediatePlacement(is.previous(), is.tok()))
1 cycrow 61
			break;
114 cycrow 62
 
1 cycrow 63
		if((t=loadValue(++is))==NULL)
64
			break;
65
		if(!isinteger(t->text))
66
			{ error(t ? t : is.previous(), S_Error, "Expected version number after ':'"); break; }
114 cycrow 67
 
1 cycrow 68
		cut->version=atoi(t->text);
114 cycrow 69
 
1 cycrow 70
		if(cut->version > bob_dom_cut::supported_version)
71
			error(is.tok(), S_Warning, "File version is %d, supported version is %d", cut->version, bob_dom_cut::supported_version);
114 cycrow 72
 
1 cycrow 73
		if(bDirectOutput){
74
			cut->info.toFile(*os);
114 cycrow 75
			*os << cut->version;
76
			/*
77
				we must output the path count right now,
1 cycrow 78
				but we will rewrite it once we finish
79
			*/
80
			pathCountOffset=(int)os->tell();
114 cycrow 81
			*os << pathCount;
1 cycrow 82
		}
114 cycrow 83
 
1 cycrow 84
		while(is.good()){
85
			t=is.tok();
114 cycrow 86
 
87
			if(t->type==token::t_openCrBracket){
1 cycrow 88
				if(actPath==NULL){
89
					error(t, S_Error, "Block unexpected here.");
90
					break;
91
				}
92
				else{
114 cycrow 93
					bErrors|=!loadFrame(actPath, ++is);
1 cycrow 94
				}
95
			}
114 cycrow 96
 
1 cycrow 97
			else{
98
				if(actPath && bDirectOutput){
99
					pathCount++;
100
					actPath->toFile(*os, cut->version);
101
					cut->removeChild(--cut->end());
102
				}
103
				if((actPath=loadPath(cut, is))==NULL)
104
					break;
114 cycrow 105
 
1 cycrow 106
				if(!is.good()){
107
					error(is.previous(), S_Error, "Missing Frame declaration after Body declaration");
108
					break;
109
				}
110
			}
111
			bRes=!bErrors;
112
		}
113
	}
114
	while(false);
114 cycrow 115
 
1 cycrow 116
	if(actPath && bDirectOutput){
117
		pathCount++;
118
		actPath->toFile(*os, cut->version);
119
		cut->removeChild(--cut->end());
120
	}
114 cycrow 121
 
1 cycrow 122
	if(bRes==false){
123
		delete cut;
124
		return NULL;
125
	}
126
	else{
114 cycrow 127
		if(bDirectOutput){
1 cycrow 128
			size_t endPos=os->tell();
114 cycrow 129
			os->seek(pathCountOffset, mystream::stream_base::seek_begin);
1 cycrow 130
			*os << pathCount;
114 cycrow 131
			os->seek((int)endPos, mystream::stream_base::seek_begin);
1 cycrow 132
		}
133
		return cut;
134
	}
135
}
136
//---------------------------------------------------------------------------------
114 cycrow 137
bob_path * bod_cut_parser::loadPath(bob_dom_cut *cut, token_stream& is)
1 cycrow 138
{
114 cycrow 139
	bob_path *path=cut->createChild();
1 cycrow 140
 
141
	bool bRes=false;
114 cycrow 142
 
1 cycrow 143
	bod_text_parser::token *t;
114 cycrow 144
 
1 cycrow 145
	do{
146
		t=is.tok();
114 cycrow 147
 
1 cycrow 148
		// index
149
		if(t==NULL || t->type!=token::t_text || strcmp(t->text, "P")!=0)
150
			{ error(t ? t : is.previous(), S_Error, "Expected body declaration starting with Path ID (P)."); break; }
151
		if((t=loadValue(++is))==NULL)
152
			break;
153
		if(!isinteger(t->text))
154
			{ error(t, S_Error, "Body declaration: Expected number after '%s'", is.previous()->text); break; }
155
		else
156
			path->partIdx=atoi(t->text);
114 cycrow 157
 
1 cycrow 158
		// body id
159
		t=is.tok();
160
		if(t==NULL || t->type!=token::t_text || strcmp(t->text, "B")!=0)
161
			{ error(t ? t : is.previous(), S_Error, "Body declaration: Expected Body ID (B)."); break; }
162
		if((t=loadValue(++is))==NULL)
163
			break;
164
		if(cut->version < 6 && !isinteger(t->text)) {
165
			error(t, S_Error, "Body declaration: body ID is string but cut version is %d. Change version to 6.", cut->version);
166
			break;
167
		}
168
		path->bodyId(t->text);
114 cycrow 169
 
1 cycrow 170
		bRes=true;
114 cycrow 171
 
1 cycrow 172
		bool bCockpit=false, bParentIdx=false, bName=false, bNotes=false;
114 cycrow 173
 
1 cycrow 174
		// cockpit, name, flag, body flag, inner bob, notes
175
		while(is.good()){
176
			t=is.tok();
114 cycrow 177
			if(t->type==token::t_openCrBracket)
1 cycrow 178
				break;
114 cycrow 179
 
1 cycrow 180
			if(t->type!=token::t_text || strlen(t->text) > 1){
181
				error(t, S_Error, "Unexpected here: '%s'", t->getText());
182
				bRes=false;
183
				break;
184
			}
114 cycrow 185
 
1 cycrow 186
			char ch=t->text[0];
114 cycrow 187
 
1 cycrow 188
			// cockpit index
189
			if(ch=='C'){
190
				if((t=loadValue(++is))==NULL)
191
					{ bRes=false; break; }
192
				if(!isinteger(t->text))
193
					{ error(t, S_Error, "Body declaration: Expected number after '%s'", is.previous()->text); bRes=false; break; }
114 cycrow 194
 
1 cycrow 195
				if(bCockpit)
196
					error(t, S_Warning, "Cockpit index already defined, last value will be used");
114 cycrow 197
 
1 cycrow 198
				bCockpit=true;
199
				path->cockpitIdx=atoi(t->text);
200
			}
201
			// parent index
202
			else if(ch=='F'){
203
				if((t=loadValue(++is))==NULL)
204
					{ bRes=false; break; }
205
				if(!isinteger(t->text))
206
					{ error(t, S_Error, "Body declaration: Expected number after '%s'", is.previous()->text); bRes=false; break; }
114 cycrow 207
 
1 cycrow 208
				if(bParentIdx)
209
					error(t, S_Warning, "Parent index already defined, last value will be used");
114 cycrow 210
 
1 cycrow 211
				bParentIdx=true;
212
				path->parentIdx=atoi(t->text);
213
			}
214
			// name
215
			else if(ch=='N'){
216
				const char *name=loadString(++is);
217
				if(name==0) break;
114 cycrow 218
 
1 cycrow 219
				if(bName)
220
					error(t, S_Warning, "Name already defined, last value will be used");
114 cycrow 221
 
1 cycrow 222
				bName=true;
223
				path->name.m_text=(char*)name;
224
			}
225
			// embedded bob
226
			else if(ch=='L'){
227
				t=(++is).tok();
114 cycrow 228
				if(t==NULL || t->type!=token::t_openCrBracket)
1 cycrow 229
					{ error(t ? t : is.previous(), S_Error, "Expected beginning of block after '%s'", is.previous()->getText()); bRes=false; break; }
230
				else{
231
					++is;
232
					path->bob=loadBOB(is, true);
233
					if(path->bob==NULL) {
234
						bRes=false; break;
235
					}
236
				}
237
			}
238
			// notes
239
			else if(ch=='T'){
114 cycrow 240
				if(loadNote(path, is)==false)
1 cycrow 241
					{ bRes=false; break; }
114 cycrow 242
 
1 cycrow 243
				if(bNotes)
244
					error(t, S_Warning, "Notes already defined, last definition will be used");
114 cycrow 245
 
1 cycrow 246
				bNotes=true;
247
			}
248
			// constants
249
			else if(ch=='K'){
250
				int count;
114 cycrow 251
				bob_constants::constant c;
252
 
1 cycrow 253
				if(!loadIntValue(++is, &count)){
254
					bRes=false; break;
255
				}
256
				for(int i=0; i < count; i++){
257
					loadIntValue(is, &(c.a));
258
					if(!loadDoubleValue(is, &(c.b))){
259
						bRes=false; break;
260
					}
261
					path->constants.values.push_back(c);
262
				}
114 cycrow 263
				if(bRes==false) break;
1 cycrow 264
			}
265
			// last try if it's a body flag (Camera, Light, Direct, v). It must not be followed by semicolon
266
			else{
267
				t=(++is).tok();
268
				if(t){
269
					if(t->type==token::t_semicolon)
270
						{ error(t, S_Error, "Invalid Body flag specification '%s': flag must NOT be followed by ';'", is.previous()->text); bRes=false; break; }
271
					if(t->type==token::t_colon)
272
						{ error(t, S_Error, "Unexpected here: ':'"); bRes=false; break; }
273
				}
274
				if(!(ch >='a' && ch<='z' || ch>='A' && ch<='Z'))
275
					{ error(is.previous(), S_Error, "Invalid Body flag specification '%c': flag must be alphabetic character", ch); bRes=false; break; }
276
				if(ch!='c' && ch!='l' && ch!='d' && ch!='v' && ch!='b' && ch!='j' && ch!='u')
277
					{ error(is.previous(), S_Warning, "Body flag '%c' out of safe limits, known values are 'c', 'l', 's', 'v', 'p', 'j', 'u'", ch); }
114 cycrow 278
 
1 cycrow 279
				//path->bodyFlag=ch - 'b';
280
				/*
281
					TODO: translate the char into body flag and
282
					OR the flags together
114 cycrow 283
 
1 cycrow 284
				*/
285
				/*
286
					if(bodyFlags & BodyFlags::fBody)
287
					os << "b ";
288
					if(bodyFlags & BodyFlags::fScene)
289
						os << "j ";
290
					int i=bodyFlags & 0x3F;
114 cycrow 291
					if(i)
1 cycrow 292
						os << (char) ('b' + i) << ' ';
293
				*/
294
				switch(ch){
295
					// both probably mean 'scene'
296
					case 'j': // no break
297
					case 'u':
114 cycrow 298
						path->bodyFlags|=bob_path::fScene;
1 cycrow 299
						break;
300
					case 'b':
114 cycrow 301
						path->bodyFlags|=bob_path::fBody;
1 cycrow 302
						break;
303
					default:
304
						path->bodyFlags|=ch - 'b';
305
				}
306
			}
307
		}
308
	}
309
	while(false);
114 cycrow 310
 
311
	if(bRes && t && t->type!=token::t_openCrBracket)
1 cycrow 312
		{ error(is.previous(), S_Error, "Unexpected end of document found when looking for beginning of Frame block"); bRes=false; }
114 cycrow 313
 
1 cycrow 314
	if(bRes==false){
315
		cut->removeChild(cut->end() - 1);
316
		path=NULL;
317
	}
114 cycrow 318
 
1 cycrow 319
	return path;
320
}
321
//---------------------------------------------------------------------------------
114 cycrow 322
bool bod_cut_parser::loadNote(bob_path *path, token_stream& is)
1 cycrow 323
{
324
	bob_note *n;
325
	bod_text_parser::token *t;
326
	bool bEnd=false;
114 cycrow 327
 
1 cycrow 328
	path->notes().removeChildren();
114 cycrow 329
 
1 cycrow 330
	++is;
331
	do{
332
		n=path->notes().createChild();
333
		// left
334
		if((t=loadValue(is))==NULL)
335
			break;
336
		if(!isinteger(t->text))
337
			{ error(t, S_Error, "Expected number"); break; }
338
		n->value=atoi(t->text);
114 cycrow 339
 
340
		if(n->value==-1) {
1 cycrow 341
			path->notes().removeChild(path->notes().end() - 1);
342
			bEnd=true;
343
			break; // end of notes
344
		}
114 cycrow 345
 
346
		// right
1 cycrow 347
		n->text=loadString(is);
348
		if(n->text==NULL){
349
			path->notes().removeChild(path->notes().end() - 1);
350
			break;
351
		}
352
	}
353
	while(is.good());
114 cycrow 354
 
1 cycrow 355
	if(bEnd==false && is.eof())
356
		error(is.previous(), S_Error, "Unexpected end of document found while looking for end of Notes (-1)");
114 cycrow 357
 
1 cycrow 358
	return t!=NULL;
359
}
360
//---------------------------------------------------------------------------------
114 cycrow 361
bool bod_cut_parser::loadFrame(bob_path *path, token_stream& is)
1 cycrow 362
{
363
	token *t;
364
	bool bRes=false;
114 cycrow 365
 
366
	bob_frame *frame=path->createChild();
1 cycrow 367
	int flags;
114 cycrow 368
 
1 cycrow 369
	// frame flags
370
	t=is.tok();
371
	if(t==NULL)
114 cycrow 372
		error(is.previous(), S_Error, "Expected frame ID");
1 cycrow 373
	else if(loadValue(is)){
374
		if(!(isinteger(t->text) || ishexa(t->text)))
375
			error(t, S_Error, "Expected frame ID in decadic or hexadecimal format");
376
		else{
377
			if(t->text[0]=='0' && ((t->text[1] | 0x20) == 'x'))
378
				flags=hextoi(t->text);
379
			else
380
				flags=atoi(t->text);
114 cycrow 381
 
1 cycrow 382
			if(flags & CUT_F_POSBEZINFO)
383
				error(NULL, S_Warning, "CUT_F_POSBEZINFO encoutered - don't know how to compile");
384
			if(flags & CUT_F_SAMESCALE)
385
				error(NULL, S_Warning, "CUT_F_SAMESCALE encoutered");
114 cycrow 386
 
387
			if(flags & ~bob_frame::flagMask)
1 cycrow 388
				error(is.tok(), S_Warning, "Unsupported bits set in frame flags - normalizing flags, unsupported values will not be compiled");
114 cycrow 389
 
390
			flags&=bob_frame::flagMask;
1 cycrow 391
			frame->flags=flags;
114 cycrow 392
 
1 cycrow 393
			bRes=true;
394
		}
395
	}
114 cycrow 396
 
1 cycrow 397
	while(bRes){
398
		static const char *pos_context = "frame: position: ";
399
		static const char *rot_context ="frame: rotation: ";
400
		static const char *tpos_context ="frame: target position: ";
401
		static const char *troll_context ="frame: roll angle: ";
402
		static const char *fov_context ="frame: FOV: ";
403
		static const char *color_context ="frame: RGB: ";
404
		static const char *len_context ="frame: length: ";
405
		static const char *idx_context ="frame: index: ";
114 cycrow 406
 
1 cycrow 407
		if((flags & CUT_F_SAMEPOS)==0){
408
			loadIntValue(is, &(frame->position.x), pos_context);
409
			loadIntValue(is, &(frame->position.y), pos_context);
410
			if((bRes=loadIntValue(is, &(frame->position.z), pos_context))==false) break;
114 cycrow 411
 
1 cycrow 412
			if(flags & CUT_F_POSTCBINFO) {
114 cycrow 413
				frame->pos_tcb_info=new bob_frame::tcb_info();
1 cycrow 414
				if((bRes=loadTCBInfo(is, frame->pos_tcb_info))==false) break;
415
			}
416
		}
417
		if((flags & CUT_F_SAMEROT)==0 && (flags & CUT_F_ROT)){
114 cycrow 418
			frame->rotation=new bob_frame::AngleAxis();
1 cycrow 419
			loadDoubleValue(is, &(frame->rotation->angle), rot_context);
420
			loadDoubleValue(is, &(frame->rotation->x), rot_context);
421
			loadDoubleValue(is, &(frame->rotation->y), rot_context);
422
			if((bRes=loadDoubleValue(is, &(frame->rotation->z), rot_context))==false) break;
114 cycrow 423
 
1 cycrow 424
			if(flags & CUT_F_ROTTCBINFO){
114 cycrow 425
				frame->rot_tcb_info=new bob_frame::tcb_info();
1 cycrow 426
				if((bRes=loadTCBInfo(is, frame->rot_tcb_info))==false) break;
427
			}
428
		}
429
		if(flags & CUT_F_TARGETPOS){
430
			if((flags & CUT_F_SAMETARGET)==0){
114 cycrow 431
				frame->targetPos=new bob_frame::Position();
1 cycrow 432
				loadIntValue(is, &(frame->targetPos->x), tpos_context);
433
				loadIntValue(is, &(frame->targetPos->y), tpos_context);
434
				if((bRes=loadIntValue(is, &(frame->targetPos->z), tpos_context))==false) break;
435
			}
436
			if((flags & CUT_F_SAMEROT)==0){
437
				if((bRes=loadDoubleValue(is, &(frame->rollAngle), troll_context))==false) break;
438
			}
439
			if(flags & CUT_F_TPOSTCBINFO){
114 cycrow 440
				frame->tpos_tcb_info=new bob_frame::tcb_info();
1 cycrow 441
				if((bRes=loadTCBInfo(is, frame->tpos_tcb_info))==false) break;
442
			}
443
		}
444
		if((flags & CUT_F_SAMEFOV)==0 && flags & CUT_F_FOV){
445
			if((bRes=loadDoubleValue(is, &(frame->fov), fov_context))==false) break;
446
		}
447
		if((flags & CUT_F_SAMECOLOR)==0 && flags & CUT_F_COLOR){
114 cycrow 448
			frame->color=new bob_frame::rgb();
1 cycrow 449
			loadDoubleValue(is, &(frame->color->r), color_context);
450
			loadDoubleValue(is, &(frame->color->r), color_context);
451
			if((bRes=loadDoubleValue(is, &(frame->color->r), color_context))==false) break;
452
		}
453
		if((bRes=loadIntValue(is, &(frame->length), len_context))==false) break;
454
		if((bRes=loadIntValue(is, &(frame->index), idx_context))==false) break;
114 cycrow 455
 
1 cycrow 456
		break;
457
	}
458
	if(bRes){
459
		int c=0;
114 cycrow 460
		while((t=is.tok()) && t->type!=token::t_closeCrBracket){
1 cycrow 461
			c++;
462
			if(loadValue(is)==false) break;
463
		}
464
		if(t==NULL){
465
			error(is.previous(), S_Error, "Unexpected end of document found while looking for end of frame block '}'");
466
		}
467
		else if(c > 0){
468
			error(is.tok(), S_Warning, "Too many values in frame block: %d (expected %d), they will be discarded", frame->valueCount() + 2, frame->valueCount() + 2 + c);
469
		}
470
		++is; // past the end bracket
471
	}
472
	else{
114 cycrow 473
		if(is.tok() && is.tok()->type==token::t_closeCrBracket)
1 cycrow 474
			error(is.tok(), S_Error, "Premature end of frame block encountered. Expected %d values (+frame flags)", frame->valueCount() + 2);
475
	}
476
	return bRes;
477
}
478
//---------------------------------------------------------------------------------
114 cycrow 479
bool bod_cut_parser::loadTCBInfo(token_stream& is, bob_frame::tcb_info *info)
1 cycrow 480
{
481
	if(!loadDoubleValue(is, &(info->tension), "TCB info (tension): ")) return false;
482
	if(!loadDoubleValue(is, &(info->continuity), "TCB info (continuity): ")) return false;
483
	if(!loadDoubleValue(is, &(info->bias), "TCB info (bias): ")) return false;
484
	if(!loadDoubleValue(is, &(info->easeFrom), "TCB info (ease from): ")) return false;
485
	if(!loadDoubleValue(is, &(info->easeTo), "TCB info (ease to): ")) return false;
486
	return true;
487
}
488
//---------------------------------------------------------------------------------