The 2024 Wheel Reinvention Jam just concluded. See the results.

cute_headers - Game Framework in C/C++

I have not! Looks like this kind of system would be needed for large-scale file watching for mostly performance reasons. For a small utility like the one here, checking timestamps is a simple and effective solution :)
I agree. But I'm more concerned with the fact that you're relying on OS's ability to cache the FS.
With a naive FS implementation you end up issuing a drive command per frame per file, which is not ideal. (Drives still do their own caching, but it is better not to saturate unnecessary busses)

In my case, I dynamically reload my game library and shaders - which is 10 files. I check them every frame at 60FPS, which adds up to 600 FS queries a second. (still not that big of a number, but it seems not to be that scalable)
Sort of related, but I released ZeroTypes Library on Handmade and recently created a pseudo-SFL version of it and it is definitely game-dev related. Wanted to share

http://github.com/h3rb/ZeroTypesSFL

The Cartesian class is pretty powerful if you learn how to use it. You can do all sorts of collision systems.
I'm not sure I see benefit of wrapping every single primitive type into class.

If you're using C++ then what's wrong with C++11 initialization?
1
class F { int x = 0; };
And why using std::string or string comparison would require boost?

Edited by Mārtiņš Možeiko on
Been going very slowly. Ended up sick with a cold. In the meantime I've been thinking of how to go about creating a font header. I'm thinking something that wraps stb_truetype would be great, but also hand-crafted bitmap fonts would be my primary interest. For a typical 2D game a high quality hand-crafted bitmap font can be created in English as the primary font for initial release. Then for localization and debug rendering truetype fonts can be used. Truetype fonts can be rasterized at run-time and glyphs can individually be loaded up into tinyspritebatch. Since tinyspritebatch is made to work with individual images, it will intelligently batch font characters based on which ones are actively drawn. In this way it becomes trivial to support truetype fonts, and will actually use less GPU memory than traditional packed rasterized bitmap techniques (since only used glyphs are ever sent to the GPU).

I'm thinking the API can look something like:
* Loader for hand-crafted bitmap font images. Some kind of format convention to make parsing the image into glyphs trivial
* Loader for truetype by wrapping stb_truetype.h
* Glyph represented as uncompressed pixels, one channel of floats
* Map glyphs to run-time indices
* Map glyph indices to codepoints via user-defined mapping

The key part is to let users map codepoints to glyphs. This lets the user define their own convention or ordering for their custom handcrafted bitmap fonts.
Re: ZeroTypes Pod-non-Pod

There are benefits. Not everyone is open to new ideas. However, I wrote ZeroTypes to simplify code, reduce code time and fatigue, to improve readability and to improve reliability. Also, I've kept it fairly simple, comparative with Java, Javascript and PHP, and quickly transmutable into such -- using commonalities of many different languages.

I provide examples of how it simplifies things on the ZeroTypes github. Pod-non-pod attacks a very core mistake in the design of C/C++. It also makes all casting and type-to-type relationships predictable.

It also came along before C++11 - I started it in 2007 Visual Studio - and some of it goes all the way back to 1991 C code. The problem with new features is that they don't always get adopted, so I've kept to core features that can't be removed. And, if you write code with ZeroTypes:

ZeroTypes:
1
2
3
class MyClass {
 Zint i;
};


PHP:
1
2
3
class MyClass {
 var $i;
};


Java:
1
2
3
class MyClass {
 int i;
};


C:
1
2
3
struct MyClass {
 int i;
};


Javascript:
1
2
3
class MyClass {
 var i;
};


In C++:
Because Zint + Zdouble was defined, you now know exactly what that operation will perform, no matter what platform you build it on. You'll always get out of it with (int)myZint, or (double)myZdouble. You'll never have to create an initializer, worried about not initializing. If you do choose to start a value as a non-zero, you'll only have to initialize the non-Zero values keeping the code simple:

1
2
3
4
5
6
7
8
class MyClass {
public:
 Zint x,y,w,h;
 Zbool fullscreen;
 MyClass() {
  fullscreen=true;
 }
};


And you won't have to rely on features of C++11, you can go back to any (most since 98) version of C++ and it will work (excluding when using Processing and development Marlin in C++).

Additionally, the LinkedList class and its supporting Macros makes life very easy. If you choose to use the support macros (which will effect transmutability), you gain additional simplicity and readability and you treat everything as being a single and a collection:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
ONE(MyClass,{})
 Zint x,y,w,h;
 void Render() {
  glRecti((GLint)x,(GLint)y,(GLint)w,(GLint)h);
 }
MANY(MyClass,MyClassHandle,MyClassHandles,"MyClass",MyClasses,{value_of_pi=3.14159267;})
 Zbool othervalue;
 Zdouble total1,total2,value_of_pi;
 CALLEACH(MyClass,Render);
DONE(MyClass);


The only advantage to using std::string more in ZeroTypesSFL than in ZeroTypes is that it is more cross-platform-friendly, and that the code is more widely adopted / acceptable and predictable across platforms, whereas the "homebaked C string wranglers" were simply rooted in some C oddities.

Finally there is the lovely minimal C-style-array-handler ZIndexed template that makes life super simple.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
class MyDisposableGridNode { public: Zint myValue; };
ZIndexed<Zdis<MyDisposableGridNode>> grid,grid2;

...
grid2.Size(10);
for ( int k=0; k<(int)grid.length; k++ ){
  //  the disposable will instantiate when -> finds a null
 grid2[k]->value = millis();  // whatever time it is...
};
grid.Size(10,10);
for ( int k=0; k<(int)grid.length; k++ ){
 grid[k].Recycle();
 grid[k]->value = 
}
... cleanup of grid is done for you when grid goes out of scope! yay.


Edited by Lost Astronaut Studios on
Re: Texture Fonts

I've spent some time exploring atlases https://store.steampowered.com/app/738830/Atlas_Tile_Editor_ATE/ including their applicability to holding font data.

It's one of those very icky parts of game/app development - always complicated, many options and each one has its pros and cons. You either are using FTGL, FreeType, or something similar. In the world of vectors and vbos or in that of atlases and simple quad-vbos and "texcoord lookups", one is smoothly scale-able but memory and process intensive on the loadup, the other is less scalable (though it can be written resolution independent)

Edited by Lost Astronaut Studios on
In my experience using custom types leads opposite to "simplify code, reduce code time and fatigue". Because now you need to have different mental model of your code and data structures. If you need to use some other API/library/module which does not use these types, that means there are either implicit or explicit conversions happening which you need to be aware of or different semantics. Which is always bad.

And btw, the sample you showed with "fullscreen=true" is not initialization. It is assignment.
I'll be using my ZeroTypes library as long as I write C++, which is hopefully about 20-30 more years (unless I decide to get the hell away from C++, which I've been contemplating lately with my pixitron initiative).

"Because now you need to have different mental model of your code and data structures."

That's kind of an irrational fear, since that's true no matter what. It's like saying "now if you want coffee and you buy vanilla beans, you won't be able to make coffee" or "if you start using a Java library and you like it then you go and start writing D ..." or "now that you learned Cobol you aren't going to be able to write Fortran like that" ... of course not!

In C++ there is such a wide range of difference (yet commonalities) in coding styles, its hard to get A to work like B. I've seen many "MACRO CLASS WRAPPERS" and I wrote what I feel is the best one. I made ZeroTypes because I got sick of initializing every single variable to 0. It took a lot of my day and the grief caused by accidentally missing one of many values in a complex class was not worth it. This protects me from making that mistake. Things get hectic when you have 100 variables in a class.

ZeroTypes is just smartly made -as best it can be- and it's not something I came up with over a weekend. It's taken me years to refine it to the point it has reached today. It's there to make it easier to develop. If you can't see the benefit, then there's no need to respond and, ultimately, it's your loss. I think it's very helpful.



"And btw, the sample you showed with "fullscreen=true" is not initialization. It is assignment."

Well, the optimizer would make it into an initialization. Example:

1
2
3
4
Constructor() {
fullscreen = false;  // removed by optimizer
fullscreen = true;
}

Edited by Lost Astronaut Studios on
That's still not initialization. Those are two assignments. http://en.cppreference.com/w/cpp/language/initializer_list

accidentally missing one of many values in a complex class
What if you miss one letter (Z) in type prefix in one of complex classes? I would argue that it will be much worse, because it is harder to spot one letter instead of properly initialized data structures.

Edited by Mārtiņš Možeiko on
In C++:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
struct Thing {
    int a;
    int b;
    int c;
    int d;
    int e;
    int f;
    // etc.
    int z;
};

// ...

Thing thing = {};


All memory occupied by "thing" is now initialized to 0.
Thanks for your example.

However, it's a struct and a struct is designed to take POD only. In classes, you need to use both PODs and non-PODs. It makes sense I would develop a POD-non-POD to bridge this gap. There is a style suggestion that indicates structs should not have methods and should consist only of POD (int, double, float). What you are showing is indeed valid and well-formed C++.

My examples were a bit too narrow in the interest of time and simplicity. Besides, this is marginally OT so I feel OT guilt. I guess I'll stop replying. Maybe I can cross-post this onto the ZeroTypes thread. And I apologize if you didn't like my earlier criticisms.

This is the example from my personal use of ZeroTypes assisting in a complex class for a game:
  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
/*********************************************************************************************
 *  __    __________________   ________________________________   __________  ________       *
 * /\ \  /\  __ \  ___\__  _\ /\  __ \  ___\__  _\  == \  __ \ "-.\ \  __ \ \/\ \__  _\ (tm) *
 * \ \ \_\_\ \/\ \___  \/\ \/ \ \  __ \___  \/\ \/\  __<\ \/\ \ \-.  \  __ \ \_\ \/\ \/      *
 *  \ \_____\_____\_____\ \_\  \ \_\ \_\_____\ \_\ \_\ \_\_____\_\\"\_\_\ \_\_____\ \_\      *
 *   \/_____/_____/_____/\/_/   \/_/\/_/_____/\/_/\/_/\/_/_____/_/ \/_/_/\/_/_____/\/_/      *
 *    --------------------------------------------------------------------------------       *
 *     Lost Astronaut Game Development Framework (c) 2007-2017 H. Elwood Gilliland III       *
 *********************************************************************************************
 * BSD LICENSE - See accompanying "License.txt" for details.                                 *
 *********************************************************************************************/
#pragma once

#include "LinkedList.h"

/*
 * JSON Encoder
 */
class JSONTree;
class JSONNodeHandles;
class JSONNode : public ListItem {
public:
 Zp<JSONTree> tree;
 Zp<JSONNode> parent;
 Zdisposable<JSONNodeHandles> elements,children;
 Zstring key,value;
 Zint loopCatcher;
 JSONNode( const char *k, const char *v ) : ListItem() { key=k; value=v; children.Instantiate(); elements.Instantiate(); }
 JSONNode( string k, string v ) : ListItem() { key=k; value=v; children.Instantiate(); elements.Instantiate(); }
 JSONNode() : ListItem() { children.Instantiate(); elements.Instantiate(); }
 void AddChild( JSONNode *n );
 void AddElement( JSONNode *n );
 void Loop() { loopCatcher++; }
 bool Looped() { return loopCatcher > 0; }
 void Zero() { loopCatcher=0; }
};

HANDLES(JSONNode,JSONNodeHandle,JSONNodeHandles,"JSONNode");

class JSONNodes : public LinkedList {
public:
 Zp<JSONTree> tree;
 JSONNode *Add( JSONNode *node ) {
  Append(node);
  node->tree=tree;
  return node;
 }
 JSONNode *AddElement( JSONNode *parent, string key, string value ) {
  JSONNode *added=new JSONNode(key,value);
  parent->AddElement(added);
  return added;
 }
 JSONNode *AddChild( JSONNode *parent, string key, string value ) {
  JSONNode *added=new JSONNode(key,value);
  parent->AddChild(added);
  return added;
 }
 JSONNode *Add( JSONNode *parent, string key, string value ) {
  return Add(new JSONNode(key,value));
 }
 void Roots(JSONNodeHandles *out) {
  out->Clear();
  FOREACH(JSONNode,node) if ( !node->parent ) out->Add(node);
 }
 void Prune(JSONNode *target ) {
  Remove(target);
  FOREACHN(JSONNode,node,{
   if ( node->parent == target ) Remove(node);
   Prune(node);
   delete node;
  });
  delete target;
 }
};

class JSONTree : public ListItem {
public:
 JSONNodes nodes;
 JSONNodeHandles roots;
 JSONTree() : ListItem() {
  nodes.tree=this;
 }
 JSONNode *AddNode( JSONNode *parent, const char *k, const char *v="" ) {
  JSONNode *added=nodes.Add(parent,string(k),string(v));
  added->tree=this;
  return added;
 }
 JSONNode *AddElement( JSONNode *parent, const char *k, const char *v="" ) {
  return nodes.AddElement(parent,string(k),string(v));
 }
 JSONNode *AddElement( JSONNode *parent, string key, string value ) {
  return nodes.AddElement(parent,key,value);
 }
 JSONNode *AddChild( JSONNode *parent, string key, string value ) {
  return nodes.AddChild(parent,key,value);
 }
 JSONNode *AddChild( JSONNode *parent, const char *k, const char *v="" ) {
  return nodes.AddChild(parent,string(k),string(v));
 }
 void Roots() {
  nodes.Roots(&roots);
 }
 string rtrim_comma( string in ) {
  Zstring out(in);
  out.rTrim(" \t\v\r\n," );
  return out.value;
 }
 string brackets( string in ) {
  return string("{")+in+string("}");
 }
 string handle_quotes( string in ) {
  Zstring out(in);
  out("\\","\\\\");
  out("\"","\\\"");
  return out.value;
 }
 string quotes( string in ) {
  return string("\"")+handle_quotes(in)+string("\"");
 }
 string toJSON(JSONNodeHandle *node ) {
  Zstring out;
  if ( node->p->children->count > 0 ) {
   EACH(node->p->elements->first,JSONNodeHandle,nh) out+=toJSON(nh)+string(",");
   return quotes(node->p->key)+string(":")+brackets(rtrim_comma(out.value));
  } else if ( node->p->elements->count > 0 ) {
   EACH(node->p->elements->first,JSONNodeHandle,nh) out+=toJSON(nh)+string(",");
   return quotes(node->p->key)+string(":")+brackets(rtrim_comma(out.value));
  } else return quotes(node->p->key)+string(":")+quotes(node->p->value)+string(",");
 }
 string toJSON() {
  Zstring out;
  Roots();
  EACH(roots.first,JSONNodeHandle,nh) {
   out+=toJSON(nh);
  }
 }
};

HANDLED(JSONTree,JSONTreeHandle,JSONTreeHandles,JSONTreeHandlesHandle,JSONTreeHandlesHandles);

class JSONTrees : public LinkedList {
public:
 CLEARLISTRESET(JSONTree);
};


The effective (and spartan - the class has been expanded as needed) class output of this constructive use of ZeroTypes is:

1
2
3
4
5
6
class JSONNode; // A single node
class JSONNodes; // A list of node "singletons"
class JSONTree; // A meta-wrangler class for simplified-JSON trees
class JSONTreeHandles; // A list of references to trees
class JSONTreeHandlesHandle // A list of lists of references to trees
class JSONTrees;  // A "JSON forest" - a linear list of trees


The above example is an older form I used to use and it uses CLEARLISTRESET() and HANDLED(), two building blocks incorporated into the ONE..MANY..DONE Macro triplet.

I agree there are other ways to do some of the things ZeroTypes permits, it is an innovation of program writing, not an innovation in algorithmic data. It's a better "wrench" but it handles standard bolts.

Programming is addictive. This is my addiction. One man's trash may be another man's treasure I guess.

Here's another example of a later constructive linguistic form available through ZeroTypes, this should work if you just plop it into the ZeroTypes project (I haven't had a chance to test it fully but it should be fine. If not, remove the parts that don't work.):

  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
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
/*********************************************************************************************
 *  __    __________________   ________________________________   __________  ________       *
 * /\ \  /\  __ \  ___\__  _\ /\  __ \  ___\__  _\  == \  __ \ "-.\ \  __ \ \/\ \__  _\ (tm) *
 * \ \ \_\_\ \/\ \___  \/\ \/ \ \  __ \___  \/\ \/\  __<\ \/\ \ \-.  \  __ \ \_\ \/\ \/      *
 *  \ \_____\_____\_____\ \_\  \ \_\ \_\_____\ \_\ \_\ \_\_____\_\\"\_\_\ \_\_____\ \_\      *
 *   \/_____/_____/_____/\/_/   \/_/\/_/_____/\/_/\/_/\/_/_____/_/ \/_/_/\/_/_____/\/_/      *
 *    --------------------------------------------------------------------------------       *
 *     Lost Astronaut Game Development Framework (c) 2007-2017 H. Elwood Gilliland III       *
 *********************************************************************************************
 * This software is copyrighted software.  Use of this code is given only with permission to *
 * parties who have been granted such permission by its author, Herbert Elwood Gilliland III *
 *********************************************************************************************/
// Released 5/7/2018 MIT License - H. Elwood Gilliland for Handmade Network
#pragma once
#include "ZeroTypes.h"
#include "BinaryFile.h"
// Holds all information relevent to an object's screen position in the 2.5D engine

ONE(ScreenPosition,{})
 Zint x,y, w,h, x2,y2, cx,cy, h2,w2;
 Zfloat fx,fy, fw,fh, fx2,fy2, fcx,fcy, fh2,fw2;
 Zdouble dx,dy, dw,dh, dx2,dy2, dcx,dcy, dh2,dw2;
 Zdouble angle; // rotation
 KEYWORDS({
  NUMWORD("x",x)
  else NUMWORD("y",y)
  else NUMWORD("w",w)
  else NUMWORD("h",h)
  else NUMWORD("x2",x2)
  else NUMWORD("y2",y2)
  else NUMWORD("cx",cx)
  else NUMWORD("cx",cy)
  else NUMWORD("h2",h2)
  else NUMWORD("w2",w2)
  else NUMWORD("fx",fx)
  else NUMWORD("fx",fy)
  else NUMWORD("fw",fw)
  else NUMWORD("fh",fh)
  else NUMWORD("fx2",fx2)
  else NUMWORD("fy2",fy2)
  else NUMWORD("fcx",fcx)
  else NUMWORD("fcy",fcy)
  else NUMWORD("fh2",fh2)
  else NUMWORD("fw2",fw2)
  else NUMWORD("dx",dx)
  else NUMWORD("dx",dy)
  else NUMWORD("dw",dw)
  else NUMWORD("dh",dh)
  else NUMWORD("dx2",dx2)
  else NUMWORD("dy2",dy2)
  else NUMWORD("dcx",dcx)
  else NUMWORD("dcy",dcy)
  else NUMWORD("dh2",dh2)
  else NUMWORD("dw2",dw2)
  else NUMWORD("a",angle)
  else BADKEY("ScreenPosition")
 })
 WORDKEYS({
  NUMBKEY("x",x)
  NUMBKEY("y",y)
  NUMBKEY("w",w)
  NUMBKEY("h",h)
  NUMBKEY("x2",x2)
  NUMBKEY("y2",y2)
  NUMBKEY("cx",cx)
  NUMBKEY("cx",cy)
  NUMBKEY("h2",h2)
  NUMBKEY("w2",w2)
  NUMBKEY("fx",fx)
  NUMBKEY("fx",fy)
  NUMBKEY("fw",fw)
  NUMBKEY("fh",fh)
  NUMBKEY("fx2",fx2)
  NUMBKEY("fy2",fy2)
  NUMBKEY("fcx",fcx)
  NUMBKEY("fcy",fcy)
  NUMBKEY("fh2",fh2)
  NUMBKEY("fw2",fw2)
  NUMBKEY("dx",dx)
  NUMBKEY("dx",dy)
  NUMBKEY("dw",dw)
  NUMBKEY("dh",dh)
  NUMBKEY("dx2",dx2)
  NUMBKEY("dy2",dy2)
  NUMBKEY("dcx",dcx)
  NUMBKEY("dcy",dcy)
  NUMBKEY("dh2",dh2)
  NUMBKEY("dw2",dw2)
  NUMBKEY("a",angle)
 })
 CLONE(ScreenPosition,{
  DUPE(x);
  DUPE(y);
  DUPE(x2);
  DUPE(y2);
  DUPE(w);
  DUPE(h);
  DUPE(cx);
  DUPE(cy);
  DUPE(w2);
  DUPE(h2);
  DUPE(fx);
  DUPE(fy);
  DUPE(fx2);
  DUPE(fy2);
  DUPE(fw);
  DUPE(fh);
  DUPE(fcx);
  DUPE(fcy);
  DUPE(fw2);
  DUPE(fh2);
  DUPE(dx);
  DUPE(dy);
  DUPE(dx2);
  DUPE(dy2);
  DUPE(dw);
  DUPE(dh);
  DUPE(dcx);
  DUPE(dcy);
  DUPE(dw2);
  DUPE(dh2);
  DUPE(angle);
 })
 void BinaryRead( BinaryFile *open ) {
  open->read(&x);
  open->read(&y);
  open->read(&w);
  open->read(&h);
  open->read(&x2);
  open->read(&y2);
  open->read(&cx);
  open->read(&cy);
  open->read(&h2);
  open->read(&w2);
  open->read(&fx);
  open->read(&fy);
  open->read(&fw);
  open->read(&fh);
  open->read(&fx2);
  open->read(&fy2);
  open->read(&fcx);
  open->read(&fcy);
  open->read(&fh2);
  open->read(&fw2);
  open->read(&dx);
  open->read(&dy);
  open->read(&dw);
  open->read(&dh);
  open->read(&dx2);
  open->read(&dy2);
  open->read(&dcx);
  open->read(&dcy);
  open->read(&dh2);
  open->read(&dw2);
  open->read(&angle);
 }
 void BinaryWrite( BinaryFile *open ) {
  open->write(&x);
  open->write(&y);
  open->write(&w);
  open->write(&h);
  open->write(&x2);
  open->write(&y2);
  open->write(&cx);
  open->write(&cy);
  open->write(&h2);
  open->write(&w2);
  open->write(&fx);
  open->write(&fy);
  open->write(&fw);
  open->write(&fh);
  open->write(&fx2);
  open->write(&fy2);
  open->write(&fcx);
  open->write(&fcy);
  open->write(&fh2);
  open->write(&fw2);
  open->write(&dx);
  open->write(&dy);
  open->write(&dw);
  open->write(&dh);
  open->write(&dx2);
  open->write(&dy2);
  open->write(&dcx);
  open->write(&dcy);
  open->write(&dh2);
  open->write(&dw2);
  open->write(&angle);
 }
 void Set( ScreenPosition *s ) {
  x=    s->x;
  y=    s->y;
  w=    s->w;
  h=    s->h;
  x2=   s->x2;
  y2=   s->y2;
  cx=   s->cx;
  cy=   s->cy;
  h2=   s->h2;
  w2=   s->w2;
  fx=   s->fx;
  fy=   s->fy;
  fw=   s->fw;
  fh=   s->fh;
  fx2=  s->fx2;
  fy2=  s->fy2;
  fcx=  s->fcx;
  fcy=  s->fcy;
  fh2=  s->fh2;
  fw2=  s->fw2;
  dx=   s->dx;
  dy=   s->dy;
  dw=   s->dw;
  dh=   s->dh;
  dx2=  s->dx2;
  dy2=  s->dy2;
  dcx=  s->dcx;
  dcy=  s->dcy;
  dh2=  s->dh2;
  dw2=  s->dw2;
  angle=s->angle;
 }
 int RandomX() { return x+upto(w); }
 int RandomY() { return y+upto(h); }
 float RandomXf() { return float_range(fx,fx+fw); }
 float RandomYf() { return float_range(fy,fy+fh); }
 double RandomXd() { return double_range(dx,dx+dw); }
 double RandomYd() { return double_range(dy,dy+dh); }
 int RandomW() { return upto(w); }
 int RandomH() { return upto(h); }
 float RandomWf() { return float_range(0.0f,fw); }
 float RandomHf() { return float_range(0.0f,fh); }
 double RandomWd() { return double_range(0.0,dw); }
 double RandomHd() { return double_range(0.0,dh); }
 void X( int x ) { PositionX(x); }
 void X( float x ) { PositionX(x); }
 void X( double x ) { PositionX(x); }
 void PositionX( int X ) {
  x=X;
  fx=(float)X;
  dx=(double)X;
  x2=x+w;
  fx2=fx+fw;
  dx2=dx+dw;
  cx=x+w/2;
  fcx=fx+fw/2.0f;
  dcx=dx+dw/2.0;
 }
 void PositionX( float X ) {
  x=(int)X;
  fx=X;
  dx=(double)X;
  x2=x+w;
  fx2=fx+fw;
  dx2=dx+dw;
  cx=x+w/2;
  fcx=fx+fw/2.0f;
  dcx=dx+dw/2.0;
 }
 void PositionX( double X ) {
  x=(int)X;
  fx=(float)X;
  dx=X;
  x2=x+w;
  fx2=fx+fw;
  dx2=dx+dw;
  cx=x+w/2;
  fcx=fx+fw/2.0f;
  dcx=dx+dw/2.0;
 }
 void Y( int y ) { PositionY(y); }
 void Y( float y ) { PositionY(y); }
 void Y( double y ) { PositionY(y); }
 void PositionY( int Y ) {
  y=Y;
  fy=(float)Y;
  dy=(double)Y;
  y2=y+h;
  fy2=fy+fh;
  dy2=dy+dh;
  cy=y+h/2;
  fcy=fy+fh/2.0f;
  dcy=dy+dh/2.0;
 }
 void PositionY( float Y ) {
  y=(int)Y;
  fy=Y;
  dy=(double)Y;
  y2=y+h;
  fy2=fy+fh;
  dy2=dy+dh;
  cy=y+h/2;
  fcy=fy+fh/2.0f;
  dcy=dy+dh/2.0;
 }
 void PositionY( double Y ) {
  y=(int)Y;
  fy=(float)Y;
  dy=Y;
  y2=y+h;
  fy2=fy+fh;
  dy2=dy+dh;
  cy=y+h/2;
  fcy=fy+fh/2.0f;
  dcy=dy+dh/2.0;
 }
 void W( int w ) { Width(w); }
 void W( float w  ) { Width(w); }
 void W( double w ) { Width(w); }
 void Width( int W ) {
  w=W;
  fw=(float)W;
  dw=(double)W;
  w2=w/2;
  fw2=fw/2.0f;
  dw2=dw/2.0;
  x2=x+w;
  fx2=fx+fw;
  dx2=dx+dw;
  cx=x+w/2;
  fcx=fx+fw/2.0f;
  dcx=dx+dw/2.0;
 }
 void Width( float W ) {
  w=(int)W;
  fw=W;
  dw=(double)W;
  w2=w/2;
  fw2=fw/2.0f;
  dw2=dw/2.0;
  x2=x+w;
  fx2=fx+fw;
  dx2=dx+dw;
  cx=x+w/2;
  fcx=fx+fw/2.0f;
  dcx=dx+dw/2.0;
 }
 void Width( double W ) {
  w=(int)W;
  fw=(float)W;
  dw=W;
  w2=w/2;
  fw2=fw/2.0f;
  dw2=dw/2.0;
  x2=x+w;
  fx2=fx+fw;
  dx2=dx+dw;
  cx=x+w/2;
  fcx=fx+fw/2.0f;
  dcx=dx+dw/2.0;
 }
 void H( int h ) { Height(h); }
 void H( float h ) { Height(h); }
 void H( double h ) { Height(h); }
 void Height( int H ) {
  h=H;
  fh=(float)H;
  dh=(double)H;
  h2=h/2;
  fh2=fh/2.0f;
  dh2=dh/2.0;
  y2=y+h;
  fy2=fy+fh;
  dy2=dy+dh;
  cy=y+h/2;
  fcy=fy+fh/2.0f;
  dcy=dy+dh/2.0;
 }
 void Height( float H ) {
  h=(int)H;
  fh=H;
  dh=(double)H;
  h2=h/2;
  fh2=fh/2.0f;
  dh2=dh/2.0;
  y2=y+h;
  fy2=fy+fh;
  dy2=dy+dh;
  cy=y+h/2;
  fcy=fy+fh/2.0f;
  dcy=dy+dh/2.0;
 }
 void Height( double H ) {
  h=(int)H;
  fh=(float)H;
  dh=H;
  h2=h/2;
  fh2=fh/2.0f;
  dh2=dh/2.0;
  y2=y+h;
  dy2=fy+fh;
  dy2=dy+dh;
  cy=y+h/2;
  fcy=fy+fh/2.0f;
  dcy=dy+dh/2.0;
 }
 void Size( int w, int h ) {
  Height(h);
  Width(w);
 }
 void Size( float w, float h ) {
  Height(h);
  Width(w);
 }
 void Size( double w, double h ) {
  Height(h); 
  Width(w);
 }
 void Size( int wh ) {
  Height(wh);
  Width(wh);
 }
 void Size( float wh ) {
  Height(wh);
  Width(wh);
 }
 void Size( double wh ) {
  Height(wh);
  Width(wh);
 }
 void MoveTo( int X, int Y ) {
  PositionX(X);
  PositionY(Y);
 }
 void MoveTo( float X, float Y ) {
  PositionX(X);
  PositionY(Y);
 }
 void MoveTo( double X, double Y ) {
  PositionX(X);
  PositionY(Y);
 }
 void MoveToCenter( int CX, int CY ) {
  CenterX(CX);
  CenterY(CY);
 }
 void MoveToCenter( float CX, float CY ) {
  CenterX(CX);
  CenterY(CY);
 }
 void MoveToCenter( double CX, double CY ) {
  CenterX(CX);
  CenterY(CY);
 }
 void MoveBy( int X, int Y ) {
  PositionX(this->x+X);
  PositionY(this->y+Y);
 }
 void MoveBy( float X, float Y ) {
  PositionX(this->fx+X);
  PositionY(this->fy+Y);
 }
 void MoveBy( double X, double Y ) {
  PositionX(this->dx+X);
  PositionY(this->dy+Y);
 }
 void Set( int X, int Y ) {
  PositionX(X);
  PositionY(Y);
 }
 void Set( float X, float Y ) {
  PositionX(X);
  PositionY(Y);
 }
 void Set( double X, double Y ) {
  PositionX(X);
  PositionY(Y);
 }
 void Set( int X, int Y, int W, int H ) {
  Width(W);
  Height(H);
  CenterX(X+W/2);
  CenterY(Y+H/2);
 }
 void Set( float X, float Y, float W, float H ) {
  Width(W);
  Height(H);
  CenterX(X+W/2.0f);
  CenterY(Y+H/2.0f);
 }
 void Set( double X, double Y, double W, double H ) {
  Width(W);
  Height(H);  
  CenterX(X+W/2.0);
  CenterY(Y+H/2.0);
 }
 void Corners( int X, int Y, int X2, int Y2 ) {
  int x=X<X2?X:X2;
  int y=Y<Y2?Y:Y2;
  int w=abs(X2-X);
  int h=abs(Y2-Y);
  Set(x,y,w,h);
 }
 void Corners( float X, float Y, float X2, float Y2 ) {
  float x=X<X2?X:X2;
  float y=Y<Y2?Y:Y2;
  float w=abs(X2-X);
  float h=abs(Y2-Y);
  Set(x,y,w,h);
 }
 void Corners( double X, double Y, double X2, double Y2 ) {
  double x=X<X2?X:X2;
  double y=Y<Y2?Y:Y2;
  double w=abs(X2-X);
  double h=abs(Y2-Y);
  Set(x,y,w,h);
 }
 void Center( int cx, int cy ) {
  CenterX(cx);
  CenterY(cy);
 }
 void Center( float cx, float cy ) {
  CenterX(cx);
  CenterY(cy);
 }
 void Center( double cx, double cy ) {
  CenterX(cx);
  CenterY(cy);
 }
 void CenterX( int CX ) { PositionX(CX-w/2); }
 void CenterY( int CY ) { PositionY(CY-h/2); }
 void CenterX( float CX ) { PositionX(CX-fw/2.0f); }
 void CenterY( float CY ) { PositionY(CY-fh/2.0f); }
 void CenterX( double CX ) { PositionX(CX-dw/2.0); }
 void CenterY( double CY ) { PositionY(CY-dh/2.0); }
 void Set( Cartesian *in ) { Set(in->x,in->y,in->w,in->h); }
 void Get( Cartesian *out ) { out->Corners((int)x,(int)y,(int)x2,(int)y2,(int)w,(int)h); }
 void GetNormalizedPosition( double inx, double iny, double *outx, double *outy ) {
  if ( dx < 0 ) {
   if ( inx < dx ) (*outx)=-((inx-dx)/dw);
   else (*outx)=(inx+abs(dx))/dw;
  } else {
   if ( inx < dx ) {
    if ( inx < 0 ) {
     (*outx)=-((abs(inx)+dx)/dh);
    } else (*outx)=-((dx-inx)/dw);
   } else (*outx)=inx/dw;
  }
  if ( dy < 0 ) {
   if ( iny < dy ) (*outy)=-((iny-dy)/dh);
   else (*outy)=(iny+abs(dy))/dh;
  } else {
   if ( iny < dy ) {
    if ( iny < 0 ) {
     (*outy)=-((abs(iny)+dy)/dh);
    } else (*outy)=-((dy-iny)/dh);
   }
   else (*outy)=iny/dh;
  }
 }
 bool OnScreen()  {
  return (dx > -dw && dy > -dh && dx2 < display.wd+dw && dy2 < display.hd+dh );
 }
 bool OnScreeni() {
  return (x > -w && y > -h && x2 < display.w+w && y2 < display.h+h );
 }
 bool OnScreenf() {
  return (fx > -fw && fy > -fh && fx2 < display.wf+fw && fy2 < display.hf+fh );
 }
// void DrawDebug();
 bool within( int mx, int my ) {
  return ( mx >= x && mx <= x2 && my >= y && my <= y2 );
 }
 bool within( float mx, float my ) {
  return ( mx >= fx && mx <= fx2 && my >= fy && my <= fy2 );
 }
 bool within( double mx, double my ) {
  return ( mx >= dx && mx <= dx2 && my >= dy && my <= dy2 );
 }
 bool within( const Zint& mx, const Zint& my ) {
  return ( mx >= x && mx <= x2 && my >= y && my <= y2 );
 }
 bool within( const Zfloat& mx, const Zfloat& my ) {
  return ( mx >= fx && mx <= fx2 && my >= fy && my <= fy2 );
 }
 bool within( const Zdouble& mx, const Zdouble& my ) {
  return ( mx >= dx && mx <= dx2 && my >= dy && my <= dy2 );
 }
 bool within( ScreenPosition *box ) {
  return (
     WITHIN(box->x,box->y,x,y,x2,y2)
  || WITHIN(box->x,box->y2,x,y,x2,y2)
  || WITHIN(box->x2,box->y2,x,y,x2,y2)
  || WITHIN(box->x2,box->y,x,y,x2,y2)
  );
 }
 double Aspect() {
  return dw/dh;
 }
 double AspectInverse() {
  return dh/dw;
 }
MANY(ScreenPosition,ScreenPositionHandle,ScreenPositionHandles,"ScreenPosition",ScreenPositions,{})
 KEYSWORDSGroups("ScreenPosition",ScreenPosition)
 CLONES(ScreenPosition,ScreenPositions)
DONE(ScreenPosition)



I use ZeroTypes because I like the way it forms my code thereafter. It also handles all of the common layers needed by most complex data types:

- Binary Reading / Writing
- Conversion to and from a string
- Ability to be transmuted into other languages
- Everything in a list can easily have a name, be sorted, customized, etc.

It's a philosophy of design. To me it marries poetics more closely with my code. It also encourages certain precautionary measures, and protects me from some common mistakes. With a minimal penalty to optimization, I can write code more freely and think more poetically - it is something I like. I admit some of it is born from laziness -- that's one of the pillars of what's successful technological development. We invent to solve problems in our lives - technology provides that distilled solution.

I agree some of it is perhaps to someone else ugly or unnecessary or even wrong. It has its upsides and its downsides, like any other piece of tech.

One thing I like is that I know I can easily write scripts that generate code that helps me write faster when I write in ZeroTypes. I can also parse ZeroTypes code predictably, since it uses a restricted set of classes -- even down to the POD layer -- and it permits me an angle on construction I would not otherwise have. I don't want to give it up. It's my code, don't you love your code? Not all of your code, perhaps, but certainly the code you appreciate - even more so because you made it? That's pretty much the spirit here, right?

I wrote this a number of years ago for my game engine: http://lostastronaut.com/tools/shaders

It generates code for my "simple" GLSL Shader handling class. I paste in a specially formatted shader, and it generates all of the C++ code I need. It also has some basic tools for converting shader code to and from strings so that I can embed the shaders right in my code.

ZeroTypes is supposed to be about relaxing your mind, not getting all caught up in it. It's there to free you not to put you in a mental prison. If you don't agree, go find something that you personally like. However, I can see the benefits this provides me and I like them.

Edited by Lost Astronaut Studios on
Finished up a demo. Tried out tinyspritebatch, tinyc2, tinytime, tinyalloc, tinyfilewatch, tinypng, tinytiled, altogether in one demo. Worked out really well! Link: https://github.com/RandyGaul/tinycavestory

Screenshot (more on github):




Edited by Randy Gaul on
Randy what did you do to handle physics? Did you use Box2d?