summaryrefslogtreecommitdiffstats
path: root/src/core/common.h
blob: 349392f42085fb9ce28dc17c0b20b336012b2069 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
#pragma once

#define _CRT_SECURE_NO_WARNINGS
#define _USE_MATH_DEFINES
#pragma warning(disable: 4244)	// int to float
#pragma warning(disable: 4800)	// int to bool
#pragma warning(disable: 4838)  // narrowing conversion
#pragma warning(disable: 4996)  // POSIX names

#include <stdint.h>
#include <string.h>
#include <math.h>

#if !defined RW_D3D9 && defined LIBRW
#undef WITHD3D
#undef WITHDINPUT
#endif

#if (defined WITHD3D && !defined LIBRW)
#define WITHWINDOWS
#endif

#if defined _WIN32 && defined WITHWINDOWS && !defined _INC_WINDOWS
#include <windows.h>
#endif

#ifdef WITHD3D
	#ifdef LIBRW
		#define WITH_D3D // librw includes d3d9 itself via this right now
	#else
		#ifndef USE_D3D9
		#include <d3d8types.h>
		#else
		#include <d3d9types.h>
		#endif
	#endif
#endif

#ifdef WITHDINPUT
#define DIRECTINPUT_VERSION 0x0800
#include <dinput.h>
#endif

#include <rwcore.h>
#include <rpworld.h>

// gotta put this somewhere
#ifdef LIBRW
#define STREAMPOS(str) ((str)->tell())
#define STREAMFILE(str) (((rw::StreamFile*)(str))->file)
#define HIERNODEINFO(hier) ((hier)->nodeInfo)
#define HIERNODEID(hier, i) ((hier)->nodeInfo[i].id)
#define HANIMFRAME(anim, i) ((RwUInt8*)(anim)->keyframes + (i)*(anim)->interpInfo->animKeyFrameSize)
#else
#define RWHALFPIXEL	// always d3d
#define STREAMPOS(str) ((str)->Type.memory.position)
#define STREAMFILE(str) ((str)->Type.file.fpFile)
#define HIERNODEINFO(hier) ((hier)->pNodeInfo)
#define HIERNODEID(hier, i) ((hier)->pNodeInfo[i].nodeID)
#define HANIMFRAME(anim, i) ((RwUInt8*)(anim)->pFrames + (i)*(anim)->interpInfo->keyFrameSize)
#define RpHAnimStdInterpFrame RpHAnimStdKeyFrame
#endif

#ifdef RWHALFPIXEL
#define HALFPX (0.5f)
#else
#define HALFPX (0.0f)
#endif

#define rwVENDORID_ROCKSTAR 0x0253F2

#define Max(a,b) ((a) > (b) ? (a) : (b))
#define Min(a,b) ((a) < (b) ? (a) : (b))

// Use this to add const that wasn't there in the original code
#define Const const

typedef uint8_t uint8;
typedef int8_t int8;
typedef uint16_t uint16;
typedef int16_t int16;
typedef uint32_t uint32;
typedef int32_t int32;
typedef uintptr_t uintptr;
typedef intptr_t intptr;
typedef uint64_t uint64;
typedef int64_t int64;
// hardcode ucs-2
typedef uint16_t wchar;

typedef uint8 bool8;
typedef uint16 bool16;
typedef uint32 bool32;

#if defined(_MSC_VER)
typedef ptrdiff_t ssize_t;
#endif

#ifndef nil
#define nil NULL
#endif

#include "config.h"
#include "memoryManager.h"
#include "relocatableChunk.h"

#include <rphanim.h>
#include <rpskin.h>

#ifdef __GNUC__
#define TYPEALIGN(n) __attribute__ ((aligned (n)))
#else
#ifdef _MSC_VER
#define TYPEALIGN(n) __declspec(align(n))
#else
#define TYPEALIGN(n)	// unknown compiler...ignore
#endif
#endif

#define ALIGNPTR(p) (void*)((((uintptr)(void*)p) + sizeof(void*)-1) & ~(sizeof(void*)-1))

// PDP-10 like byte functions
#define MASK(p, s) (((1<<(s))-1) << (p))
inline uint32 dpb(uint32 b, uint32 p, uint32 s, uint32 w)
{
	uint32 m = MASK(p,s);
	return (w & ~m) | ((b<<p) & m);
}
inline uint32 ldb(uint32 p, uint32 s, uint32 w)
{
	return w>>p & (1<<s)-1;
}

#include "skeleton.h"
#include "Draw.h"

#if defined(PROPER_SCALING)
	#ifdef FORCE_PC_SCALING
		#define DEFAULT_SCREEN_WIDTH  (640)
		#define DEFAULT_SCREEN_HEIGHT (448)
	#else
		#define DEFAULT_SCREEN_WIDTH  (640)
		#define DEFAULT_SCREEN_HEIGHT (480)
	#endif
#elif defined(GTA_PS2)
		#define DEFAULT_SCREEN_WIDTH  (640)
		#define DEFAULT_SCREEN_HEIGHT (480)
#else //elif defined(GTA_PC)
		#define DEFAULT_SCREEN_WIDTH  (640)
		#define DEFAULT_SCREEN_HEIGHT (448)
#endif

#define DEFAULT_ASPECT_RATIO (4.0f/3.0f)
#define DEFAULT_VIEWWINDOW (0.7f)

// game uses maximumWidth/Height, but this probably won't work
// with RW windowed mode
#ifdef GTA_PS2
	#ifdef GTA_PAL
		#define SCREEN_WIDTH  ((float)640)
		#define SCREEN_HEIGHT ((float)512)
	#else
		#define SCREEN_WIDTH  ((float)640)
		#define SCREEN_HEIGHT ((float)448)
	#endif
#else
#define SCREEN_WIDTH  ((float)RsGlobal.width)
#define SCREEN_HEIGHT ((float)RsGlobal.height)
#endif

#define SCREEN_HEIGHT_PAL ((float)512)
#define SCREEN_HEIGHT_NTSC ((float)448)

#define SCREEN_ASPECT_RATIO (CDraw::GetAspectRatio())
#define SCREEN_VIEWWINDOW (Tan(DEGTORAD(CDraw::GetScaledFOV() * 0.5f)))

// This scales from PS2 pixel coordinates to the real resolution
#define SCREEN_STRETCH_X(a)   ((a) * (float) SCREEN_WIDTH / DEFAULT_SCREEN_WIDTH)
#define SCREEN_STRETCH_Y(a)   ((a) * (float) SCREEN_HEIGHT / DEFAULT_SCREEN_HEIGHT)
#define SCREEN_STRETCH_FROM_RIGHT(a)  (SCREEN_WIDTH - SCREEN_STRETCH_X(a))
#define SCREEN_STRETCH_FROM_BOTTOM(a) (SCREEN_HEIGHT - SCREEN_STRETCH_Y(a))

// This scales from PS2 pixel coordinates while optionally maintaining the aspect ratio
#define SCREEN_SCALE_X(a) SCREEN_SCALE_AR(SCREEN_STRETCH_X(a))
#define SCREEN_SCALE_Y(a) SCREEN_STRETCH_Y(a)
#define SCREEN_SCALE_FROM_RIGHT(a) (SCREEN_WIDTH - SCREEN_SCALE_X(a))
#define SCREEN_SCALE_FROM_BOTTOM(a) (SCREEN_HEIGHT - SCREEN_SCALE_Y(a))

#ifdef ASPECT_RATIO_SCALE
#define SCREEN_SCALE_AR(a) ((a) * DEFAULT_ASPECT_RATIO / SCREEN_ASPECT_RATIO)
#define SCALE_AND_CENTER_X(x) ((SCREEN_WIDTH == DEFAULT_SCREEN_WIDTH) ? (x) : (SCREEN_WIDTH - SCREEN_SCALE_X(DEFAULT_SCREEN_WIDTH)) / 2 + SCREEN_SCALE_X((x)))
#ifdef PROPER_SCALING
	#ifndef FORCE_PC_SCALING			
		#undef SCREEN_SCALE_Y	
		#define SCREEN_SCALE_Y(a) CDraw::ScaleY(SCREEN_STRETCH_Y(a))	
	#endif
#endif
#else
#define SCREEN_SCALE_AR(a) (a)
#define SCALE_AND_CENTER_X(x) SCREEN_STRETCH_X(x)
#endif

#include "maths.h"
#include "Vector.h"
#include "Vector2D.h"
#include "Matrix.h"
#include "Rect.h"

class CRGBA
{
public:
	union
	{
	    uint32 color32;
		struct { uint8 r, g, b, a; };
		struct { uint8 red, green, blue, alpha; };
#ifdef RWCORE_H
		struct  { RwRGBA rwRGBA; };
#endif
	};
	
	CRGBA(void) { }
	CRGBA(uint8 r, uint8 g, uint8 b, uint8 a) : r(r), g(g), b(b), a(a) { }
	
	bool operator ==(const CRGBA &right)
	{
		return this->r == right.r && this->g == right.g && this->b == right.b && this->a == right.a;
	}
	
	bool operator !=(const CRGBA &right)
	{
		return !(*this == right);
	}
	
	CRGBA &operator =(const CRGBA &right)
	{
		this->r = right.r;
		this->g = right.g;
		this->b = right.b;
		this->a = right.a;
		return *this;
	}
#ifdef RWCORE_H
	operator RwRGBA &(void) {
		return rwRGBA;
	}
	
	operator RwRGBA *(void) {
		return &rwRGBA;
	}
	
	operator RwRGBA (void) const {
		return rwRGBA;
	}

	CRGBA &operator =(const RwRGBA &right)
	{
		this->r = right.red;
		this->g = right.green;
		this->b = right.blue;
		this->a = right.alpha;
		return *this;
	}
#endif
};

#if (defined(_MSC_VER))
extern int strcasecmp(const char *str1, const char *str2);
extern int strncasecmp(const char *str1, const char *str2, size_t len);
#endif

extern wchar *AllocUnicode(const char*src);

#define clamp(v, low, high) ((v)<(low) ? (low) : (v)>(high) ? (high) : (v))

#define clamp2(v, center, radius) ((v) < (center) ? Max(v, center - radius) : Min(v, center + radius))

inline float sq(float x) { return x*x; }
#define SQR(x) ((x) * (x))

#define PI (float)M_PI
#define TWOPI (PI*2)
#define HALFPI (PI/2)
#define DEGTORAD(x) ((x) * PI / 180.0f)
#define RADTODEG(x) ((x) * 180.0f / PI)

#ifdef USE_PS2_RAND
#define MYRAND_MAX		65535
#else
#define MYRAND_MAX		32767
#endif

int myrand(void);
void mysrand(unsigned int seed);

void re3_debug(const char *format, ...);
void re3_trace(const char *filename, unsigned int lineno, const char *func, const char *format, ...);
void re3_assert(const char *expr, const char *filename, unsigned int lineno, const char *func);
void re3_usererror(const char *format, ...);

#define DEBUGBREAK() __debugbreak();

// Switch to enable development messages.
#if 1 
#define DEV(f, ...)
#else
#define DEV(f, ...)   re3_debug("[DEV]: " f, ## __VA_ARGS__)
#endif

#define debug(f, ...) re3_debug("[DBG]: " f, ## __VA_ARGS__)
#define TRACE(f, ...) re3_trace(__FILE__, __LINE__, __FUNCTION__, f, ## __VA_ARGS__)
#define Error(f, ...) re3_debug("[ERROR]: " f, ## __VA_ARGS__)
#define USERERROR(f, ...) re3_usererror(f, ## __VA_ARGS__)

#define assert(_Expression) (void)( (!!(_Expression)) || (re3_assert(#_Expression, __FILE__, __LINE__, __FUNCTION__), 0) )
#define ASSERT assert

#define _TODO(x)
#define _TODOCONST(x) (x)

#ifdef CHECK_STRUCT_SIZES 
#define VALIDATE_SIZE(struc, size) static_assert(sizeof(struc) == size, "Invalid structure size of " #struc)
#else
#define VALIDATE_SIZE(struc, size)
#endif
#define VALIDATE_OFFSET(struc, member, offset) static_assert(offsetof(struc, member) == offset, "The offset of " #member " in " #struc " is not " #offset "...")

#define PERCENT(x, p)                    ((float(x) * (float(p) / 100.0f)))
#define ARRAY_SIZE(array)                (sizeof(array) / sizeof(array[0]))
#define BIT(num)                         (1<<(num))

#define ABS(a)  (((a) < 0) ? (-(a)) : (a))
#define norm(value, min, max) (((value) < (min)) ? 0 : (((value) > (max)) ? 1 : (((value) - (min)) / ((max) - (min)))))
#define lerp(norm, min, max) ( (norm) * ((max) - (min)) + (min) )

#define STRINGIFY(x)                    #x
#define STR(x)                          STRINGIFY(x)
#define CONCAT_(x,y) x##y
#define CONCAT(x,y) CONCAT_(x,y)

// Tweaking stuff for debugmenu
#define TWEAKPATH                                   ___tw___TWEAKPATH
#define SETTWEAKPATH(path)	                        static const char *___tw___TWEAKPATH = path;
#define TWEAKFUNC(v)                                static CTweakFunc   CONCAT(___tw___tweak, __COUNTER__)(&v, STR(v), TWEAKPATH);
#define TWEAKFUNCN(v, name)                         static CTweakFunc   CONCAT(___tw___tweak, __COUNTER__)(&v, name, TWEAKPATH);
#define TWEAKBOOL(v)                                static CTweakBool   CONCAT(___tw___tweak, __COUNTER__)(&v, STR(v), TWEAKPATH);
#define TWEAKBOOLN(v, name)                         static CTweakBool   CONCAT(___tw___tweak, __COUNTER__)(&v, name, TWEAKPATH);
#define TWEAKINT32(v, lower, upper, step)           static CTweakInt32  CONCAT(___tw___tweak, __COUNTER__)(&v, STR(v), lower, upper, step, TWEAKPATH);
#define TWEAKINT32N(v, lower, upper, step, name)    static CTweakInt32  CONCAT(___tw___tweak, __COUNTER__)(&v, name, lower, upper, step, TWEAKPATH);
#define TWEAKUINT32(v, lower, upper, step)          static CTweakUInt32 CONCAT(___tw___tweak, __COUNTER__)(&v, STR(v), lower, upper, step, TWEAKPATH);
#define TWEAKUINT32N(v, lower, upper, step, name)   static CTweakUInt32 CONCAT(___tw___tweak, __COUNTER__)(&v, name, lower, upper, step, TWEAKPATH);
#define TWEAKINT16(v, lower, upper, step)           static CTweakInt16  CONCAT(___tw___tweak, __COUNTER__)(&v, STR(v), lower, upper, step, TWEAKPATH);
#define TWEAKINT16N(v, lower, upper, step, name)    static CTweakInt16  CONCAT(___tw___tweak, __COUNTER__)(&v, name, lower, upper, step, TWEAKPATH);
#define TWEAKUINT16(v, lower, upper, step)          static CTweakUInt16 CONCAT(___tw___tweak, __COUNTER__)(&v, STR(v), lower, upper, step, TWEAKPATH);
#define TWEAKUINT16N(v, lower, upper, step, name)   static CTweakUInt16 CONCAT(___tw___tweak, __COUNTER__)(&v, name, lower, upper, step, TWEAKPATH);
#define TWEAKINT8(v, lower, upper, step)            static CTweakInt8   CONCAT(___tw___tweak, __COUNTER__)(&v, STR(v), lower, upper, step, TWEAKPATH);
#define TWEAKINT8N(v, lower, upper, step, name)     static CTweakInt8   CONCAT(___tw___tweak, __COUNTER__)(&v, name, lower, upper, step, TWEAKPATH);
#define TWEAKUINT8(v, lower, upper, step)           static CTweakUInt8  CONCAT(___tw___tweak, __COUNTER__)(&v, STR(v), lower, upper, step, TWEAKPATH);
#define TWEAKUINT8N(v, lower, upper, step, name)    static CTweakUInt8  CONCAT(___tw___tweak, __COUNTER__)(&v, name, lower, upper, step, TWEAKPATH);
#define TWEAKFLOAT(v, lower, upper, step)           static CTweakFloat  CONCAT(___tw___tweak, __COUNTER__)(&v, STR(v), lower, upper, step, TWEAKPATH);
#define TWEAKFLOATN(v, lower, upper, step, name)    static CTweakFloat  CONCAT(___tw___tweak, __COUNTER__)(&v, name, lower, upper, step, TWEAKPATH);
#define TWEAKSWITCH(v, lower, upper, str, f)        static CTweakSwitch CONCAT(___tw___tweak, __COUNTER__)(&v, STR(v), lower, upper, str, f, TWEAKPATH);
#define TWEAKSWITCHN(v, lower, upper, str, f, name) static CTweakSwitch CONCAT(___tw___tweak, __COUNTER__)(&v, name, lower, upper, str, f, TWEAKPATH);

// interface
class CTweakVar
{
public:
	virtual void AddDBG(const char *path) = 0;
};

class CTweakVars
{
public:
	static void Add(CTweakVar *var);
	static void AddDBG(const char *path);
};

class CTweakFunc : public CTweakVar
{
	const char *m_pPath, *m_pVarName;
	void (*m_pFunc)();
public:
	CTweakFunc(void (*pFunc)(), const char *strName, const char *strPath) :
		m_pPath(strPath), m_pVarName(strName), m_pFunc(pFunc)
	{
		CTweakVars::Add(this);
	}
	
	void AddDBG(const char *path);
};

class CTweakBool : public CTweakVar
{
	const char *m_pPath, *m_pVarName;
	bool *m_pBoolVar;
public:
	CTweakBool(bool *pBool, const char *strName, const char *strPath) :
		m_pPath(strPath), m_pVarName(strName), m_pBoolVar(pBool)
	{
		CTweakVars::Add(this);
	}
	
	void AddDBG(const char *path);
};

class CTweakSwitch : public CTweakVar
{
	const char *m_pPath, *m_pVarName;
	void *m_pIntVar;
	int32 m_nMin, m_nMax;
	const char **m_aStr;
	void (*m_pFunc)();
public:
	CTweakSwitch(void *pInt, const char *strName, int32 nMin, int32 nMax, const char **aStr,
	             void (*pFunc)(), const char *strPath)
	    : m_pPath(strPath), m_pVarName(strName), m_pIntVar(pInt), m_nMin(nMin), m_nMax(nMax),
	      m_aStr(aStr)
	{
		CTweakVars::Add(this);
	}

	void AddDBG(const char *path);
};

#define _TWEEKCLASS(name, type)                                                                    \
	class name : public CTweakVar                                                              \
	{                                                                                          \
	public:                                                                                    \
		const char *m_pPath, *m_pVarName;                                                  \
		type *m_pIntVar, m_nLoawerBound, m_nUpperBound, m_nStep;                           \
                                                                                                   \
		name(type *pInt, const char *strName, type nLower, type nUpper, type nStep,        \
		     const char *strPath)                                                          \
		    : m_pPath(strPath), m_pVarName(strName), m_pIntVar(pInt),                      \
		      m_nLoawerBound(nLower), m_nUpperBound(nUpper), m_nStep(nStep)                \
                                                                                                   \
		{                                                                                  \
			CTweakVars::Add(this);                                                     \
		}                                                                                  \
                                                                                                   \
		void AddDBG(const char *path);                                                     \
	};

_TWEEKCLASS(CTweakInt8, int8);
_TWEEKCLASS(CTweakUInt8, uint8);
_TWEEKCLASS(CTweakInt16, int16);
_TWEEKCLASS(CTweakUInt16, uint16);
_TWEEKCLASS(CTweakInt32, int32);
_TWEEKCLASS(CTweakUInt32, uint32);
_TWEEKCLASS(CTweakFloat, float);

#undef _TWEEKCLASS

#ifdef VALIDATE_SAVE_SIZE
extern int32 _saveBufCount;
#define INITSAVEBUF _saveBufCount = 0;
#define VALIDATESAVEBUF(b) assert(_saveBufCount == b);
#else
#define INITSAVEBUF
#define VALIDATESAVEBUF(b)
#endif

inline void SkipSaveBuf(uint8 *&buf, int32 skip)
{
	buf += skip;
#ifdef VALIDATE_SAVE_SIZE
	_saveBufCount += skip;
#endif
}

inline void SkipSaveBuf(uint8*& buf, uint32 &length, int32 skip)
{
	buf += skip;
	length += skip;
#ifdef VALIDATE_SAVE_SIZE
	_saveBufCount += skip;
#endif
}

template<typename T>
inline const T ReadSaveBuf(uint8 *&buf)
{
	T &value = *(T*)buf;
	SkipSaveBuf(buf, sizeof(T));
	return value;
}

template<typename T>
inline const T ReadSaveBuf(uint8 *&buf, uint32 &length)
{
	T &value = *(T*)buf;
	SkipSaveBuf(buf, length, sizeof(T));
	return value;
}

template<typename T>
inline T *WriteSaveBuf(uint8 *&buf, const T &value)
{
	T *p = (T*)buf;
	*p = value;
	SkipSaveBuf(buf, sizeof(T));
	return p;
}

template<typename T>
inline T *WriteSaveBuf(uint8 *&buf, uint32 &length, const T &value)
{
	T *p = (T*)buf;
	*p = value;
	SkipSaveBuf(buf, length, sizeof(T));
	return p;
}


#define SAVE_HEADER_SIZE (4*sizeof(char)+sizeof(uint32))

#define WriteSaveHeader(buf,a,b,c,d,size) \
	WriteSaveBuf(buf, a);\
	WriteSaveBuf(buf, b);\
	WriteSaveBuf(buf, c);\
	WriteSaveBuf(buf, d);\
	WriteSaveBuf<uint32>(buf, size);

#define WriteSaveHeaderWithLength(buf,len,a,b,c,d,size) \
	WriteSaveBuf(buf, len, a);\
	WriteSaveBuf(buf, len, b);\
	WriteSaveBuf(buf, len, c);\
	WriteSaveBuf(buf, len, d);\
	WriteSaveBuf<uint32>(buf, len, size);

#define CheckSaveHeader(buf,a,b,c,d,size)\
	assert(ReadSaveBuf<char>(buf) == a);\
	assert(ReadSaveBuf<char>(buf) == b);\
	assert(ReadSaveBuf<char>(buf) == c);\
	assert(ReadSaveBuf<char>(buf) == d);\
	assert(ReadSaveBuf<uint32>(buf) == size);

#define CheckSaveHeaderWithLength(buf,len,a,b,c,d,size)\
	assert(ReadSaveBuf<char>(buf,len) == a);\
	assert(ReadSaveBuf<char>(buf,len) == b);\
	assert(ReadSaveBuf<char>(buf,len) == c);\
	assert(ReadSaveBuf<char>(buf,len) == d);\
	assert(ReadSaveBuf<uint32>(buf,len) == size);


void cprintf(char*, ...);