Sunday, June 28, 2015

Smooth Animation, but lots of jaggy edges


You'd think a game loop wouldn't be a hard thing.

while(true) {
  process_input();
  update_game_logic();
  render();
}

That can be adequate for a lot of simple games, but the cool thing to do is to decouple the update calls from the render calls, update on a fixed (sim) clock, and render as often as you can, using a very lightweight interpolation inside the render loop to smooth the trajectories between update calls.

In particular, I'm using a version from Robert Nystrom's "Game Programming Patterns", which looks like this in my language:

 loop {
    float currentTime = get_current_time();
    float elapsedTime = currentTime - previousTime;
    previousTime = currentTime;
    lag = lag + elapsedTime;
    
    sdl_tick_input();
    if (sdl_quit_signalled() == 1) {
      break;
    }

    while (lag >= SECONDS_PER_UPDATE) {
      update();
      lag = lag - SECONDS_PER_UPDATE;
      updates = updates + 1;
    }

    float alpha = lag / SECONDS_PER_UPDATE;
    draw(alpha);
    renders = renders + 1;
  }

The nice thing about this is that the updates are always at a fixed rate, so the simulations don't go unstable, and you still get to render as often as your machine is capable of. I could stick an artificial delay in there to keep the frame rate from going too high (rarely a problem, but if I wanted to conserve battery power on portable devices (phones, tablets, laptops) it might be worth considering.


Several bits that I ran into along the way that I need to clean up:
  • I'm being sloppy about pointers within my compiler. I just throw an extra load() to dereference the pointer, and things seem to work out, but it feels super sloppy.
  • I'm getting a segmentation fault about 13 seconds into the run. Don't know why that is, but it's reproducible. Which is a nice thing for a crash bug.
  • I've got user-defined data types (let's call them "structs"). But if I create them at global scope, they don't get linked properly. Gotta figure that out.
I was hoping to get the ship to fly around with simulated intention by this point. That's soon, but not yet, I guess.

Wednesday, June 24, 2015

White Triangle


From a compiler/language perspective, this isn't an interesting post. All I've done is incorporate OpenGL into my existing SDL2 support from the Pong game, earlier.

It was a bit of a hassle merging the SDL2 OpenGL tutorials (which are, I guess, pretty new, and pretty spartan) with the NeHe "drawing a shape on the screen" tutorial (which has a SDL1 implementation). But, hey, there you go. A triangle, rendered in perspective, in my language.

If you're familiar with the NeHe tutorials, you might expect there to be a square on the screen, too. And the square does get drawn, just not at the point that you see here - I have a few different "game modes", and in the first state, I draw a triangle. After several seconds, I switch states, and then I draw the square. So that's even fancier than the NeHe tutorials. Take that!

For the next foreseeable bit, I'll be hooking up OpenGL to my language, so that's not pretty, but it's what needs to happen. I suppose I can write a Python script to grab GL.h and provide some amount of interface for free.


A few things that I should add to my TODO list:

  • GLES support - I'm using the old OpenGL glBegin(GL_TRIANGLES) style. That won't fly on all the platforms I intend to hit, so I'll rewrite the triangle using a vertex array, which hopefully my language will be able to support natively.
  • Strings - pretty soon, I'm going to want to accept user input (for a high score list?) and show text onscreen (on an about screen?) without the gross approach I used in Pong, which included a draw_char call that put a character at a position on the screen - no word wrapping, no language support for strings. Maybe that won't be too hard.

Monday, June 22, 2015

I have nothing to say, but it's OK, because now I can say it.

Apologies to The Beatles.

A bit ago, I copied the sourcecode for my Pong game into a new directory, as a way to start work on my next game in my language. I proceeded to comment out a large chunk of code.

Tangent: languages often don't have good facilities for commenting out chunks of code that might already include commented out code. In C++, say, you've got your single line comments

// like this

And there are multiple-line comments

/*
 * that can go on for many
 * lines, like this
 */

And if you want to disable a chunk of code that has a single-line comment, it's fine:

  for (int i=0; i<10; i++) {
    if (i < 3) {
/*
      // show small numbers
      printf("small number %d", i);
*/
      process_data(i);
  }

But it gets tricky if I wanted to disable that entire loop because */ terminates a comment, even if the comment was itself in a comment.

C and C++ have one more tool, the preprocessor, which helps some, so I could just do this:

#if 0
  for (int i=0; i<10; i++) {
    if (i < 3) {
/*
      // show small numbers
      printf("small number %d", i);
*/
      process_data(i);
  }
#endif //0


but that's still not terrific. Maybe disabling code isn't what a compiler is for. Still.


But that's not what I came here to talk about today. As I was saying at the top, I commented out a bunch of code from my Pong game, and stuff wouldn't compile. Ok, I thought, perhaps I was sloppy and commented out half of a function, and the remaining bits are causing problems. That may well have been part of it, but I cleaned up the obvious errors like that, and still I was running into issues.

One thing that doesn't get a lot of coverage in compilers tutorials is how to deal with errors - lexing errors, parse errors - there's perhaps a paragraph talking about inserting a special error token into your language and that's what gets called when things go wrong, which is a start, but then what do you do when that production gets called? How do you present enough information to the user of your compiler to fix the problem?

Right now, I print a warning with a line number and a little more information, which isn't currently sufficient. For one thing, the line number doesn't line up with the actual line number of the file being compiled. I think part of that comes from my compiler starting at line number 0 versus emacs, which starts at 1. Also, if I #include files, those throw off the numbering. Whoops. So, that's stuff to fix.

It'd also be nice to know what column the error was on, if I know that.

I've looked a little bit at pycparser, which seems to do a better job than I am for this sort of thing. TODO: roll in more of pycparser's approach to error handling.


And even that isn't what I meant to be talking about.

So, I waded through the output of my compiler, complaining about unexpected closing braces, and I ultimately determined that code like this was causing trouble:

void display_char(char c) {
# sdl_show_char(c);
}

Seems innocuous - a call to an external function that I commented out, since I'm rewriting my graphics library. Except, whoops, aha. The body of display_char is empty. And, whaddayaknow, my compiler doesn't like empty bodies for functions. Or, as it turns out for if/elif/else bodies, either:

if (phase == PLAY_GAME) {
#  draw_game();
} elif (phase == SHOW_TITLE) {
# draw_title();
} elif (phase == SHOW_CREDITS) {
# ...
}

As it turned out, that was super easy to fix - I just extended my grammar to allow statementlists to be 0 or more statements, instead of 1 or more, which is how they were before.

So, now I can have functions that do nothing, and blocks of code that are empty. Progress!    

Saturday, June 13, 2015

Local arrays, arrays of objects


What you see here is an array of user-defined objects (Ship) like so:

class Ship {
  Vec2f pos;
  Vec2f vel;
}

in a locally-defined array. And you can see position and velocity being set, and then the position being updated using the ship's velocity. And the values are being read out correctly.

All working as you expect.

After the flailing to get the arrays working to begin with, this feels anticlimactic.

Next up: graphics, including using the above position and velocity data, vertex arrays, all on the way to an Asteroids-like game.

Friday, June 12, 2015

Reading/Writing ints/floats to global arrays


It doesn't look like a big thing, but the relevant bit of my code is this:


int intvals[3];
float floatvals[10];

int main() {
  intvals[0] = 17;
  intvals[1] = 19;
  floatvals[0] = 3.14;
  floatvals[1] = 1.5;


Here, I'm allocating two arrays in global space, assigning to them (and then reading from them, not pictured in the code snippet here).

A couple things I discovered along the way, which isn't well documented in the stuff I was looking at, was that array allocations need to have their "linkage" specified, which I haven't been doing for other global variables. Also, I wasn't able to get things working until I provided initializers for my arrays. That's a good thing, and I was considering providing default initialization anyway. I found it surprising that the LLVM assembler didn't want to accept my generated bytecode until I provided initialization values for my arrays.

Next up:
- arrays declared locally (top of function, inside loops)
- arrays of structs (e.g. Vec2f, Ship)
- *GL linkage, passing arrays through to OpenGL and WebGL


Thursday, June 4, 2015

Loading into, reading from, structs


I've found that in order to make progress on my language, it helps to have very specific lines of code that I want to make sure my compiler compiles, and focus on those.

The couple lines of code that I've been struggling with off and on lately have been:

  newpos.x = pos.x + vel.x;
  newpos.y = pos.y + vel.y;

Really simple stuff; retrieve member data from an aggregate type, do some arithmetic, store the results into member fields of an aggregate type. It so happens that this is simple physics / animation code, but the compiler doesn't care about that.

I had done some reading of the LLVMlite documentation and was sure that I needed to do some sort of insert_value and extract_value code. And then there's getelementptr, which is tricky, to the point that it's got its own FAQ page: http://llvm.org/releases/3.5.1/docs/GetElementPtr.html

In my previous post, I talked about using Clang as a reference - I might not have to use all of LLVM if Clang's got a way to accomplish what I'm doing, I can do the same thing that it does. And all it does is simple getelementptr instructions. 

So, I started stripping out stuff that I had built to handle stuff on the left hand side of assignments differently from stuff on the right hand side. I put some getelementptr calls into my code. I started seeing errors about "gep not implemented on identified struct type", which I thought I maybe had to work around, but it turns out that somebody else had run into that bug and had submitted a fix for it. So, git pull and reinstall the LLVMlite module, and all of a sudden, things were working a lot better.

There's still some gross bits that are left over from my efforts to set up a complex solution to what was ultimately a simple problem - that's got to get cleaned up before I push this stuff up to my repository. I think I've also found some pointer stuff that now looks ripe for refactoring.

Next short term feature: (static?) array support - being able to create an array of objects, either simple or aggregate objects, and then reading and writing those objects.

Longer term ambition: some sort of Asteroids-ish clone. That'll put the above physics / animation code into context, and having a collection of asteroids floating around the screen will motivate the array support.

Getting away from language features, an Asteroids clone will provide pressure for more OpenGL support, which will be a good thing.