P = NG

After my previous adventures in rendering .png files to a software framebuffer, I realised that I needed to convert between lodepng’s RGBA 4-bits-per-pixel format to Libretro’s RGB565 format. My studies since my last post brought me to pixconv.c which has a function, conv_rgba4444_argb8888, that does just that type of conversion. I need to give the function the following in this order:

  1. the output variable
  2. the input variable
  3. the dimensions of the image file
  4. the output pitch
  5. the input pitch

In theory, all I had to do was add lodepng and pixconv.c to my project, run a test.png file through those two, and put the resulting data in the framebuffer.

The result was a mess. Learning that <iostream>, a stape at my studies of C++, was worthless when working in C, was actually the easy part. Even if I did not exactly know what type of data type were the variables that held the RGBA4444 and RGB565 arrays (I settled on unsigned char when void did not work), the makefile refused to recognize lodepng_decode32_file and logepng_error_text, even after I put those two types in various places (though not at the same time) inside the actual libretro_test.c file. I learned that this issue comes from the linker, which is related to the makefile.

At this point, I decided to give up at least temporarily. I mean, while there is the possibility that this is the last problem and that I actually have everything else right, I decided that this matter requires advanced knowledge that is specialized on C++. I mean, I have a Master’s Degree in Software Engineering, but my actual usage of the fundamentals of C++ and related languages were all in Integrated Development Environments. I barely know anything more than how to run make (not “CMake”, but “make”)!

This lack of specialized knowledge is also the reason why I am no longer pursing either adapting a current C++ engine to Libretro or, per Radius’ suggestion, using OpenGL. I still would have to deal with compiling the C++ code in those situations.

In light of this, I was looking more seriously at Rust, which has bindings to Libretro. While Rust is not object-oriented in the conventional sense, Rust has features that have just about the same functionality anyway. The problem is checking how the current game engines that use Rust render graphics. After all, I want to use software rendering because I want my games to be played at the full range of consoles that run Retroarch, not just the ones that can handle both versions of OpenGL.

I am also seriously considering going back to Lua per my original plans. Not only does LÖVE have no need of a distinct compilation process but also displays graphics through an API that works great and easy. In fact, the ease of use LÖVE provides is the reason why I picked using LÖVE instead of straight C++ in the first place! The main reason why I am not so sure is because that the reason why I wanted to leave Lua in the first place was because Lua did not have any proper support of object-oriented programming. I would much rather use the real deal, especially since Re-Hoard needs object-oriented programming! Even if there is an alternative, this lack of functionality may hamper heavily my plans of future games!

I tried to see how Lutro, Libretro’s interpreter of LÖVE, displays games written in LÖVE. I mean, LÖVE apparently uses SDL, but that does not seem to be a problem to Lutro. However, I got overwhelmed once again.

Eevee is right; if I were to write from scratch, I would be essentially inventing the universe if I needed to get off the ground. Then there is compilation afterwards.

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.