Broken Physics; Broken Graphics

I am starting to change my mind.

I looked into Chipmunk after Box2D warned me about Box2D requiring a lot of C++ experience. However, Chipmunk itself seems too complex. Worse, I could not find an API-indifferent way of putting graphics on the physics objects!

I looked into other game engines, but they, true to my predictions, use SDL or OpenGL and do not seem to have ways of rendering directly to the framebuffer. Speaking of the framebuffer, I am still awaiting on information on what exactly is a framebuffer in the first place. On Radius’ defense, Radius is probably taking time out of a busy day in making an appropriate reply.

I just feel frustrated because I feel lost. Radius gave me a much-needed nudge, but I need more.

I am not going back to Lua because I need the capabilities that C++ or Rust give. Even so, the Rust libraries and engines probably have the same dependencies on SDL or OpenGL that the other game engines have.

I should be spending this time working on my PICO-8 games.

I shall look at rpng, Libretro’s own decoder of .png graphics. That, being of Libretro itself, should have a way of rendering directly to the framebuffer.

Advertisements

The Framebuffer is the Way

Since my last post, I gotten some help at how to render graphics through Libretro. I mean, while I did take 2 classes in rendering graphics through GLUT (from OpenGL) and a bit of familiarity of Unity during my entire college career, I am still essentially new at graphics programming. I am just in a position to learn now.

I asked in the Libretro forums. Radius clarified to me that I am supposed to render to a framebuffer where I would set a pixel there to the color that I want. Physics engines can then be easily built on top of that concept. I then asked Radius about how I can go to learning about framebuffers in the first place. Meanwhile, given this point of clarity, I searched the libretro-samples repository for stuff on framebuffers. There, I found examples on how to use software rendering.

 

Basically, I would:

  • declare a bit-level variable that holds the framebuffer.
  • set the size of that framebuffer.
  • declare a static variable called “video_cb” that is of the retro_video_refresh_t type.
  • get the information of the AV system, including the dimensions, aspect ratio, and frames per second.
  • declare a couple of variables that hold the coordinates of the image I want to render.

I got difficulty going farther because, from reading the source code, the example is rendering a checkerboard. Apparently, the rendering itself involves copying the framebuffer to a separate “line” variable which holds an array, pushing the coordinates of the square to that “line” variable, then setting the value of those coordinates to a color, said color being a variable that holds a point in memory (0xff, specifically) to where you push the value while declaring that color variable.

(The example also apparently relies on the mouse. The mouse coordinates, which come from their own variables, use some “stride” variable that I do not know but is used in an intermediary buffer variable that copies itself to the “line” variable. There, the value of 0xff is put on the buffer variable, which is also an array, to some location that uses both some of its internal coordinates and that “stride” variable. I am not sure. I think I need to actually compile the source code if I were to understand.)

After all that, the example puts into the earlier “video_cb” variable:

  • the buffer variable
  • the specific dimensions
  • that “stride” variable that undergoes a left shift of 2 (whatever that means).

The above is inside a rendering the function that is executed at runtime.

At the time where the Libretro frontend actually loads the example, the example actually sets the retro pixel format. Afterwards, serialization makes a data array that is set to the image coordinates. A size of 2 is also involved in some way.

 

Changing our focus to the Libretro library itself, Libretro uses retro_framebuffer and retro_video_refresh_t. retro_framebuffer is a structure that has the following components:

  • the data that actually holds the framebuffer itself
  • the dimensions of the framebuffer
  • the “pitch”, that is, how many bytes take up the length of a scanline
  • the pixel format
  • access flags that say how “the core will access the memory in the framebuffer”
  • memory flags that tell the “core how the memory has been mapped”

I do not know about the existence, much less proper use, of these flags at the time I am writing this.

Except for the dimensions and access flags, most of the components use GET_CURRENT_SOFTWARE_FRAMEBUFFER, which returns a framebuffer directly to video memory. The thing is that GET_CURRENT_SOFTWARE_FRAMEBUFFER actually returns a pointer that must be writeable. However, actually rendering directly to the video memory instead of using a pixel format is optional. In this case, instead of directly setting the values of the buffer and “stride” variables, I would make a retro_framebuffer structure. In that structure I would:

  • set the dimensions normally.
  • set the access flags to RETRO_MEMORY_ACCESS_WRITE.
  • set the buffer variable to the framebuffer data.
  • set the “stride” variable to the framebuffer pitch that has a right shift 2 (whatever that means).

Of course, there is a fallback to the normal way.

retro_video_refresh_t is actually a type that Libretro defined, this type actually rendering the frame. The components of retro_video_refresh_t are:

  • data  from the above framebuffer
  • the dimensions of the framebuffer
  • a “pitch” which, according to the comments, is the number of bytes that make up the length between two lines in the framebuffer

 

While that is ample coverage of how do render to the framebuffer the data, there is still the issue on how to convert .png files to actual data in the first place. Fortunately, I looked up LodePNG. While that is not Libretro’s internal decoder of .png files, LodePNG has a simple way of decoding the file to pixels. I would simply declare a vector variable that carries the raw pixels, then I would also declare variables that carry the dimensions. I would then run LodePNG’s “decode” function that takes in the above 3 variables and the filename, putting the pixels in the vector variable. There, 4 bytes, representing RGBA in that order, represent each pixel. I am still not sure on how to use this raw .png data in Libretro, though.

 

I still am not sure on what is exactly a “framebuffer,” either.

Hard Work at Figuring out the Graphics

I should be finishing Re-Hoard and Reckless Abandon, but, other than doing most of the sprites at Re-Hoard, I spent most of my time trying to figure out how to display graphics through Libretro.

Basically, because I plan on using software rendering (which is more portable due to not dependent on any specific API), all I need to do is render to a framebuffer… or the backbuffer. I know that I am going to exclusively use .png files and, because of my choice of 2D retro-style graphics, the RGB565 format, but I do not know the exact procedure in displaying and moving graphics while targeting Libretro. I mean, I did not even know of RGB565 before reading the libretro.h file! LÖVE did not give me this much trouble!

I can use a sprite library, but those were made without the knowledge of Libretro, which means that they would render using SDL2 or OpenGL instead of the generic software rendering layer that Libretro uses. Even if I did find one that uses software rendering, I have trouble knowing how to write .png files to a framebuffer or backbuffer! Libretro does have its own png decoder, but I do not know how to use the thing! This is not even taking into account the Box2D or Chipmunk physics engines that I plan on using!

I still plan on going ahead with using straight C++ with Libretro instead of writing in Lua and running the resulting core through Lutro. After all, I prefer to be the closest possible to the Libretro library because I find that the extra control outweighs the difficulty. Besides, this knowledge would be helpful if I ever get a job at another game company. However, if this gets too difficult, then I shall use a Rust engine and rely on Libretro’s Rust wrapper, instead.

Lua to the End?

From the beginning of my game career, I intended to make games that use Libretro, a C/C++ library that can be used in writing emulators and standalone games. The reason why I learned Lua in the first place was because, compared to using straight C or C++, writing games in Lua and relying on the Lutro core seemed to be the more comfortable option. Indeed, because Lua programs do not need to be compiled, I ended up saving myself plenty of precious time in my last two college projects back when I took my Master’s Degree. Developing my final project using LÖVE instead of trying to understand the Libretro library, especially given the one-trimester deadline, spared me from a lot of grief. That knowledge of Lua also helped me develop games for the PICO-8, an all-in-one platform that not only helped me get used to normal game development but also has several channels of delivery, my favourite one being uploading the game itself in image format. You can even play these games in your browser with little fuss!

However, I am starting to feel the limitations Lua has. While Reckless Abandon has simple code, Re-Hoard has a game plan that needs object-oriented programming when generating random anti-hoarders, each with their own patrolling and hunting styles, per stage. Lua does not have any object-oriented functionality; other people fake that functionality using metatables. Even with that fake functionality, I fear that I would be better off relying on the real thing. Besides, if Lua lacked true object-oriented functionality, then what else would Lua lack? Other consideration include less layers of abstraction that might interfere with my wanting to interact with Libretro itself, the bigger maturity of C++ tools and libraries, and practice in a language that is still in high demand in the workplace. In fact, the more advanced aspects of Lua actually use a C library!

On the other hand, the gains from the lack of a compilation time proved to be an assets when I debugged my college projects. Also, LÖVE games store their assets as-is instead of they being baked directly in the program; I can edit a sprite or switch around a song and see the effects when running the game anew.

Despite these benefits, I am seriously considering working on my new games with C++ from now on. In fact, though Reckless Abandon would stay a PICO-8 game, I might move Re-Hoard to C++.

I just need to figure out how to display and move .png sprites and implement collision detection while I use Libretro.

Reckful Spriting

I managed to do almost all of the graphics of Reckless Abandon. I was actually out of ideas by the time I stopped, but I thankfully got almost everything done there. Other than that, I still have to do the bonus exhibit and a secret or so.

I stopped temporarily because I both wanted to rest and celebrate. I wanted the ideas to come, but that needed me stepping away from the game. Even coding would not give the rest my mind needed in gathering ideas.

I think I got almost all the ideas I needed since then now.

I feel accomplished that I did so much. I hope that I can release both Reckless Abandon and Re-Hoard by the end of this month.

A Human-Sized Wall

Recently, I started working on Reckless Abandon again. Weirdly, my problem was that I had trouble figuring out how to draw humans in sprite form. I think the reason behind my hesitation was because I am going to do a big number of human-based designs in both Reckless Abandon and Re-Hoard, yet in theory, there are several ways of drawing humans. There is a lot hanging on this base concept.

I decided to take my time in loosening up my human designs.

humans

The one I like the most is the purple design due to its reasonable compactness while still being recognizable and animatable.

Abandoning a Reckless Pace

Neither Re-Hoard nor Reckless Abandon are going to be released by Comi-Con this year.

Ever since my last post, I took my time both recovering and considering my needs. I realized that I would not be able to deliver a good product (or maybe any product) by that deadline. My health and other kinds of energy trump any business opportunities.

That does not mean that I would stop. I just needed to recover from the deadly pace I took. In fact, a couple of days ago, I reoriented myself on listing what both games still needed.

However, I fear that, given that this is my second delay, I am setting up an image of lazy unreliability.

Reckless with my Energy

Yesterday, I was stuck on how to represent the countries when designing the exhibits. Thankfully, I got the ideas going at night. I think I just needed to let my brain work out this stuff by itself and respect the time my brain needs on working on stuff in general.

The problem is that I had little energy for working on the game today. I do not have the will of working on stuff immediately after I wake up; I need to “buffer”. I only start getting that will at noon, but, even after 1:00 PM, I still had no desire to work on this. I played some electronic games, thus recovering my emotional energy. I then slept, yet, 3 hours later, I still felt tired. I decided to just work anyways. I added enough notes and started drawing the props. However, I just… want to sleep more. Besides, I am typing this sentence at 10:33 PM.

I want to get this game out before Comi-Con, but my health may require me to postpone those plans.

Recklessly Stuck

I am surprised and embarrassed on being stuck in this game. The coding itself did not give me problems this time, but the content did. Worse, I thought that I had developed the idea thoroughly, but I have problems finding out how I should do the exhibits. I got a general idea, but I got trouble turning that idea into specific exhibits.

…I do not like stopping here, especially since I want to have both games done by Comi-Con, but I feel that I need to do more research beforehand. Besides, this is just a temporary detour.

…at least I hope that this is just a temporary detour…