How do I attach SDL2 to my code?

Greetings everyone!
(Caution - lengthy context ahead!)
A little while ago I started a small project, which aims to be a program that would create animation from a text script written in a specially designed language. For the lack of a better comparison, imagine a virtual machine which has a set of instructions that manipulate objects such as 2D sprites, backgrounds and 3D models, and you as the animator write a program with these instructions describing exactly what you want to see, such as movements, rotations, transformations, etc. The project has been created in Python since the very beginning, but I’ve always understood that a project like that would eventually become computationally intensive and an interpreted language would not be able to sustain it. After much consideration, I’ve chosen Fortran, since its syntax felt most familiar and comfortable to me when compared to C/C++ and alike. I should mention that all of the code is written from scratch, meaning that almost no libraries are used - the only ones I used initially were math, used for trigonometric functions that are utilised in the engine (no matrices are involved in 3D), and pygame, which was used exclusively to provide a video output. Even the codec used to record and playback the resulting animation is original. The codec was the module that I decided to transition first, since the original implementation was lagging when the window was being recorded and I couldn’t optimize the decoder for any sort of considerable speed gain. While researching Fortran, I found that there is a library that might just perfectly suit my needs - SDL2, but that’s where problems began. I wasn’t been able to find a comprehensive guide on how to actually attach and use it, which is further made difficult by my absolute lack of experience with compiled languages and their inherent oddities. Therefore, I would like to ask, how do I install and attach SDL2 to my project? I’m using CodeBlocks under Windows 11, and the only thing that’s needed from SDL2 is opening a window and drawing an image on it from a prepared array which acts as a frame buffer (plus playing a sound at a selected rate from a prepared array of raw sample data). Using any other OS is not an option, installing WSL is possible but not preferred and would only be desirable if no other options exist.

Hello @Jozeff, welcome to Discourse!

You can find a description about how to use SDL2 from Fortran, courtesy of @interkosmos, here: SDL | Programming in Modern Fortran.

Concerning installation on Windows, have you followed the steps at the SDL Wiki (SDL2/Installation - SDL Wiki)? It looks like the first step is to download the binary package from GitHub: Releases · libsdl-org/SDL · GitHub. Next step would be to configure the library path in your IDE.

Since your profile suggests you have an interest in retro tech, you could also give the SDL77 interface a try. Here’s a sample program I got running in about 1 hr (I’m on a Mac):

sdl77_pixels
program sdl77_pixels

    implicit none

    ! SDL77 interface
    external :: galloc, gblit, gcirc, gclose, gcolor, gcolk, &
                gcppal, gcppix, gcreat, gcur, gdelay, gevent, &
                gfill, gfillr, gflush, ggrab, ghline, glayer, &
                gline, gload, glock, gmbut, gmouse, gopen, gpal, &
                gpixel, gsetp, gsshot, gulock, gvideo, gvline, &
                gwarp, gkey, gticks, gtime

    ! External functions
    integer :: gkey
    integer(8) :: gticks, gtime

    integer, parameter :: EVENT_QUIT = 12
    integer, parameter :: kreturn = 13
    integer, parameter :: kspace  = 32
    integer, parameter :: kesc    = 27
    integer, parameter :: kup     = 273
    integer, parameter :: kdown   = 274
    integer, parameter :: kright  = 275
    integer, parameter :: kleft   = 276

    integer, parameter :: pw = 320, ph = 160, blk = 4
    integer, parameter :: wwidth = blk*pw, wheight = blk*ph

    real :: pix(ph,pw)
    integer :: istat, ievent

    ! Open window and hide mouse cursor
    call gopen(wwidth,wheight,"pixel noise"//achar(0),istat)
    if (istat /= 0) stop "Error: failed to open SDL window"
    call gcur(0)

    ! Set background color and fill screen
    call gcolor(0,0,0)
    call gfill()

    main: do

        ! Poll for events
        event: do
            call gevent(ievent,istat)
            if (ievent == EVENT_QUIT) exit main
            if (istat == 0) exit event
        end do event

        ! Respond to key presses
        if (gkey(kup) == 1) then
            call randomize
        else if (gkey(kdown) == 1) then
            call clear
        else if (gkey(kleft) == 1) then
            call left
        else if (gkey(kright) == 1) then
            call right
        else if (gkey(kspace) == 1) then
            call automaton
        else if (gkey(kesc) == 1) then
            exit main
        end if

        ! Draw pixel-blocks
        call render
        call gflush

    end do main

    call gclose()

contains

    subroutine render
        integer :: i, j
        do i = 1,pw
        do j = 1,ph
            if (pix(j,i) > 0.5) then
                call gcolor(255,255,255)
            else
                call gcolor(0,0,0)
            end if
            call gfillr(blk*i-blk,blk*j-blk,blk,blk)
        end do
        end do
    end subroutine

    subroutine randomize
        call random_number(pix)
    end subroutine

    subroutine clear
        pix = 0.0
    end subroutine

    subroutine left
        pix = cshift(pix,blk,dim=2)
    end subroutine

    subroutine right
        pix = cshift(pix,-blk,dim=2)
    end subroutine

    subroutine automaton
        logical, save :: switch = .false.
        integer :: i, j, im, ip, jl, jh, js
        logical :: p, q, r, c

        if (switch) then
            jl = 2
            jh = ph
            js = 1
        else
            jl = ph-1
            jh = 1
            js = -1
        end if

        do j = jl, jh, js
            do i = 1, pw
                ip = modulo(i+1,pw) + 1
                im = modulo(i-1,pw) + 1
                p = pix(j-js,im) > 0.5
                q = pix(j-js,i)  > 0.5
                r = pix(j-js,ip) > 0.5
                c = r .neqv. (q .or. p)
                if (c) then
                    pix(j,i) = 1.0
                else
                    pix(j,i) = 0.0
                end if
            end do
        end do
        switch = .not. switch
    end subroutine

end program

The controls are:

  • up - randomize pixels
  • left/right - pane
  • down - reset
  • space - cellular automation (Rule 110)
  • esc - close program

Hope that helps.

Ivan

2 Likes

I did some miniproject some time ago, feel free to use it as an example: Fortran Game of life

Game of Life was going to be my next idea for a (nightly) Fortran SDL project. I’m glad you’ve done it already. :joy:

I also created a custom SDL2 backend in C with Fortran bindings for the Fortran CHIP8 virtual machine. SDL2 was easier to use than Xlib. Initially I tried using EGGX/ProCall but it lacked the functionality to distinguish key releases from key presses.