Opportunity to push/promote Ada coming soon (Can this be pinned?)

Hi again Luke, I’m not sure I’ll be capable of submitting something to the jam, but I’ll try to work my way towards it or future ones. I added the FPS section to the tutorial and I think it works. Fun fact, if I remove the frame cap code I get around 2300 FPS, quite something!
I’ve now moved back on to the lazyfoo tutorials as I’m still to much of a newbie, and I’m getting into the binding part of it. I’ll probably have some questions for you soon but I’ll try hard to answer them myself first :slight_smile:

Where’s the FPS code?

Maybe I didn’t express it well. I’ve added the FPS code in your tutorial to my code. It counts the total number of frames and averages it out over the total number of ticks from the beggining. It sort of works.

Yeah, that one’s not right. I thought you meant you fixed it.

I don’t need the first line for my app to work. Added the second fto the doc, it’s in the source. And you definitely need the second to compile.

Yeah, that’s a cut n paste error, fixed.

Thanks.

My pleasure!

I’ve managed to do the “Getting an Image on the Screen” part of the lazyfoo tutorial Lazy Foo' Productions - Getting an Image on the Screen, with my first (I think successful) attempt at a binding. The tutorial uses SDL_LoadBMP( “path/hello_world.bmp”) to create a surface from a file, which I saw was not implemented in the binding. The way I’ve solved it is:

In SDL.Video.Surfaces.Makers I’ve added:

.ads

procedure Create_From_File (Self      : in out Surface;
                            File_Name : in SDL.RWops.UTF_Strings.UTF_String);

.adb

procedure Create_From_File (Self : in out Surface;
                            File_Name : in SDL.RWops.UTF_Strings.UTF_String) is
      function SDL_Load_BMP_RW (Src  : in SDL.RWops.RWops; freesrc : C.int) return Internal_Surface_Pointer with
        Import        => True,
        Convention    => C,
        External_Name => "SDL_LoadBMP_RW";
      Src : SDL.RWops.RWops := SDL.RWops.From_File (File_Name,
                                                    SDL.RWops.Read_Binary);
   begin
      Self.Internal := SDL_Load_BMP_RW (Src, 1);
   end Create_From_File;

Then in the main program, I’ve used it like this:

   if not SDL.Initialise (Flags => SDL.Enable_Screen) then
      return;
   end if;

   SDL.Video.Windows.Makers.Create
     (Win      => Window,
      Title    => "SDL Tutorial",
      Position => SDL.Natural_Coordinates'(X => 20, Y => 20),
      Size     => SDL.Positive_Sizes'(Width, Height),
      Flags    => 0);

   Surface := Window.Get_Surface;

   SDL.Video.Surfaces.Makers.Create_From_File
     (Hello_World_Image,
     "C:\Users\<user name>\Downloads\hello_world.bmp");
   
   Surface.Blit (Hello_World_Image);

   Window.Update_Surface;

   Wait;

   Hello_World_Image.Finalize;
   Surface.Finalize;
   Window.Finalize;
   SDL.Finalise;

The result:

This is very satisfying! :slight_smile:

I assume the routine names and parameters are probably not in line with how you would do it. The usage of the strings, maybe? Please let me know how would you like it done and I could start creating push requests if you like.

Best regards,
Alexis.

1 Like

I’d probably name it Create as you can see it’s from a filename.

What you should do here is with Ada.Strings.UTF_Encoding; and then create the renames, instead of using the symbol inside RWOPs package as that’s really only for ease of writing within that package.

   package UTF_Strings renames Ada.Strings.UTF_Encoding;

Change “n” to “y” in the README.md, remove the -- TODO: SDL_LoadBMP_RW from sdl.video.surfaces spec and then send me a PR and I’ll merge it in.

Also, word of advice for portability, use files local to your application’'s directory, there are functions for doing this. Pull the latest version, alr update, and you’ll see I moved these functions to SDL.Filesystems to match the original API.

And Windows DOS drives and file paths are emulations on top of a unix style path functionality within Windows, it acceps unix style paths and separators, ‘/’.

And FYI, the Blit functions needs reworking, you will likely come to these in that tutorial, iirc. When I first created them, the Blit functions were essentially macros, I think that’s changed now, but I need to look at it, but it’s not a priority right now.

Thank you for all the advice. I’ve created a PR, I hope it’s all OK.

1 Like

Errr… I’ve suddenly started getting this error when building, both build my application and sdlada as stand alone. Not sure if it’s me…

> alr build
Note: Running pre-build actions for sdlada=2.5.124...
make: Entering directory '/c/work/ada/sdlada/build/gnat'
mkdir -p gen/src/
make: Leaving directory '/c/work/ada/sdlada/build/gnat'
Note: Building sdlada=2.5.124/build/gnat/sdlada.gpr...
Compile
   [Ada]          sdl-filesystems.adb
sdl-filesystems.adb:6:42: error: "Strings" not declared in "C"
sdl-filesystems.adb:11:26: error: "Strings" not declared in "C"
sdl-filesystems.adb:13:20: error: "Strings" not declared in "C"
sdl-filesystems.adb:14:16: error: "RWops_Error" is undefined (more references follow)
sdl-filesystems.adb:14:36: error: "Error" not declared in "SDL"
sdl-filesystems.adb:18:57: error: "Strings" not declared in "C"
sdl-filesystems.adb:20:10: error: "SDL_Free" is undefined (more references follow)
sdl-filesystems.adb:31:75: error: "Strings" not declared in "C"
sdl-filesystems.adb:36:25: error: "Strings" not declared in "C"
sdl-filesystems.adb:41:20: error: "Strings" not declared in "C"
sdl-filesystems.adb:42:36: error: "Error" not declared in "SDL"
sdl-filesystems.adb:46:57: error: "Strings" not declared in "C"
sdl-filesystems.ads:9:30: error: "UTF_Strings" is undefined (more references follow)

   compilation of sdl-filesystems.adb failed

gprbuild: *** compilation phase failed
ERROR: Command ["gprbuild", "-s", "-j0", "-p", "-P", "C:\work\ada\sdlada\build/gnat/sdlada.gpr"] exited with code 4
ERROR: Compilation failed.

No, it’s me. Didn’t do an alr build before I committed it. DOH!

Ok, update and try that. Compiles here now.

Phew! Working again, thanks!

1 Like

As you’re going through that GL tutorial, you might want to keep an eye on cgpiogl too.

1 Like

Ah, nice, thank you!

Managed to do step four, handle different key presses and update the window surface with a different bitmap for each keypress. So loaded five bitmaps into an array of surfaces like this (just some excerpts pasted):

   type Key_Press_Surface_Index is
     (Default,
      Up,
      Down,
      Left,
      Right);
   type Key_Press_Surfaces is array (Key_Press_Surface_Index) of
     SDL.Video.Surfaces.Surface;

   --   Load the bitmaps into surfaces
   procedure Load_Media (Surfaces : in out Key_Press_Surfaces) is
      Surface : SDL.Video.Surfaces.Surface;
   begin
      SDL.Video.Surfaces.Makers.Create (Surface,
                                        "../resources/press.bmp");
      Surfaces (Default) := Surface;
      SDL.Video.Surfaces.Makers.Create (Surface,
                                        "../resources/up.bmp");
      Surfaces (Up) :=  Surface;
      SDL.Video.Surfaces.Makers.Create (Surfaces (Down),
                                        "../resources/down.bmp");
      SDL.Video.Surfaces.Makers.Create (Surfaces (Left),
                                        "../resources/left.bmp");
      SDL.Video.Surfaces.Makers.Create (Surfaces (Right),
                                        "../resources/right.bmp");
   end Load_Media;
   ---  Free the surfaces afterwards
   procedure Free_Media (Surfaces : in out Key_Press_Surfaces) is
   begin
      for S of Surfaces loop
         S.Finalize;
      end loop;
   end Free_Media;
   --  Using them
   procedure Handle_Events is
      Finished : Boolean := False;
   begin
      loop
         while SDL.Events.Events.Poll (Event) loop
            case Event.Common.Event_Type is
               when SDL.Events.Quit =>
                  Finished := True;
               when SDL.Events.Keyboards.Key_Down =>         
                  case Event.Keyboard.Key_Sym.Key_Code is
                     when SDL.Events.Keyboards.Code_Escape =>
                        Finished := True;
                     when SDL.Events.Keyboards.Code_Up =>
                        Current_Surface := Surfaces (Up);
                     when SDL.Events.Keyboards.Code_Down =>
                        Current_Surface := Surfaces (Down);
                     when SDL.Events.Keyboards.Code_Left =>
                        Current_Surface := Surfaces (Left);
                     when SDL.Events.Keyboards.Code_Right =>
                        Current_Surface := Surfaces (Right);
                     when others => null;
                  end case;
               when others => null;
            end case;
         end loop;
         
         Window_Surface.Blit (Current_Surface);
         Window.Update_Surface;
         
         exit when Finished;
      end loop;
   end Handle_Events;

Can it be done more succintly?

And I have a programming style question, when in C++ you normally have all these pesky condition checks:

int main( int argc, char* args[] )
{
	//Start up SDL and create window
	if( !init() )
	{
		printf( "Failed to initialize!\n" );
	}
	else
	{
		//Load media
		if( !loadMedia() )
		{
			printf( "Failed to load media!\n" );
		}
		else
		{	
			//Main loop flag
			bool quit = false;

What’s the best way to handle this in Ada? I see you’ve prepared the bindings to raise exceptions, but how would be the best way to handle them?

Thanks a lot!

Not in all cases, in some, like initialisation, they return boolean.

I’ve been debating with myself the exceptions and whether to remove them in favour of return values, luckily it’s mostly SDL.Success or not, or whether to use last_chance_handler and use pragmas to change exceptions into a goto to that function, a la embedded.

There is no other way to do it in Ada. There’s no nullable types, you can do a sort of option with a variant but you still need to check it with an if.

But with short circuit booleans you can cascade the init functions as I do in the starter app/article.

Another way that C programmers used to use was an array of init functions, you go through the array calling the functions and if any fail, you exit with an error message; each one would need to set up a clean up function on a stack as they completed cleanly. You could do that. That’s essentially a defer but not at language level.

1 Like

Ok, I’ll give my thoughts on it as I advance. I just implemented SDL_ConvertSurface, BTW.
Thanks!

1 Like

Ok, I’ve got to part ten of the Lazy Foo tutorial (Lazy Foo' Productions - Color Keying) without needing to implement any new bindings, but now I have a doubt about it’s programming practices. In this part, the author encapsulates SDL_Texture in a class, which I’d like to know what is the best equivalent in Ada, create a new a package or a new OOP type? If the latter, maybe inherit from SDL.Video.Textures.Texture? I think sdlada has most of what is requires already anyway.

And a point that raises serious concerns for me, the class in the tutorial defines a render method like this:

void LTexture::render( int x, int y )
{
    //Set rendering space and render to screen
    SDL_Rect renderQuad = { x, y, mWidth, mHeight };
    SDL_RenderCopy( gRenderer, mTexture, NULL, &renderQuad );
}

Meaning it relies on a global pointer gRenderer which is initialised earlier. This makes me cringe! I would rather add the renderer as a parameter to the procedure than have this kind of dependency. What do you think?

Oh, and Ada looks so much clearer and cleaner…