Giter VIP home page Giter VIP logo

Comments (18)

angelog0 avatar angelog0 commented on June 30, 2024

Just for completeness, I have attached a tar ball (test_case.tar.gz) with a test case in C and rewritten in Fortran. The C code behaves as expected printing (on exiting) the codes of keys pressed and exiting with ESC. The Fortran one prints always 0 for the codes and does not exit if not closing the window.

In comment there is the command line used for the build. The compiler is GCC 8.2.0

from fortran-sdl2.

angelog0 avatar angelog0 commented on June 30, 2024

I wonder if a library as SDL2 can be completely interfaced in Fortran by means of ISO C BINDING. SDL2 contains C unions which seem excluded from ISO C BINDING.

In this page Interoperability of derived types, under point 4, and (here) one can read:

No Fortran type is interoperable with a C union type, struct type that contains a bit field, or struct type that contains a flexible array member.

Maybe, for confirmation, we need to ask Fortran people...

BTW, just found this discussion.

from fortran-sdl2.

interkosmos avatar interkosmos commented on June 30, 2024

The following code lets you quit the game with the Escape key:

do while (.not. done)
    rc = sdl_poll_event(event)

    if (rc > 0) then
        select case (event%type)
            case (SDL_QUIT_TYPE)
                done = .true.
            case (SDL_KEY_DOWN)
                keys = sdl_get_keyboard_state()
                ! Quit if player hits Escape:
                if (keys(SDL_SCANCODE_ESCAPE) == 1) then
                    done = .true.
                end if
        end select
    end if
end do

Yes, the Fortran standard does not define any unions. But you can use transfer() to do simple type casting. See sdl_transfer_event() in sdl2.f90.

from fortran-sdl2.

angelog0 avatar angelog0 commented on June 30, 2024

@interkosmos wrote:

But you can use transfer() to do simple type casting. See sdl_transfer_event()

Hmm... if sdl_poll_event already calls sdl_transfer_event(),

select case (event%type)

                ! SDL_KeyboardEvent
                case (SDL_KEY_DOWN : SDL_KEY_UP)
                    event%key = transfer(event, event%key)

WHY then

write(*,'(A,i0)') 'KEY = ', event%key%key_sym%sym

prints always 0?

I tried also

event%key%key_sym%sym = transfer(event, event%key%key_sym%sym)
           write(*,'(A,i0)') 'KEY = ', event%key%key_sym%sym
           if (event%key%key_sym%sym == ESC) quit = 1

but does not work, prints always 768..

from fortran-sdl2.

angelog0 avatar angelog0 commented on June 30, 2024

@interkosmos wrote:

The following code lets you quit the game with the Escape key:
keys = sdl_get_keyboard_state()

Who is keys? How it is/must be declared?

Just for completeness, compiling with the -Wall option your code, prints these warnings:

gfortran -Wall -std=f2008 `sdl2-config --cflags` ../f03sdl2-master/sdl2.f90 draw_test.f90 -o draw_test `sdl2-config --libs`
../f03sdl2-master/sdl2.f90:1469:47:

         function sdl_get_render_target(renderer) bind(c, name='SDL_GetRenderTarget')
                                               1
Warning: Unused dummy argument 'renderer' at (1) [-Wunused-dummy-argument]
../f03sdl2-master/sdl2.f90:1469:8:

         function sdl_get_render_target(renderer) bind(c, name='SDL_GetRenderTarget')
        1
Warning: Return value of function 'sdl_get_render_target' at (1) not set [-Wreturn-type]
draw_test.f90:181:18:

            keys = sdl_get_keyboard_state()
                  1
Warning: POINTER-valued function appears on right-hand side of assignment at (1) [-Wsurprising]

I think sdl_get_render_target should go in the interface section not in contains section of the module:

$ diff -Naur programming/f03sdl2-master/sdl2.f90~ programming/f03sdl2-master/sdl2.f90
--- programming/f03sdl2-master/sdl2.f90~        2018-09-08 16:19:29.000000000 +0200
+++ programming/f03sdl2-master/sdl2.f90 2018-09-10 01:57:51.391318300 +0200
@@ -977,6 +977,14 @@
             integer(kind=c_int) :: sdl_get_system_ram
         end function sdl_get_system_ram

+        ! SDL_Texture *SDL_GetRenderTarget(SDL_Renderer *renderer)
+        function sdl_get_render_target(renderer) bind(c, name='SDL_GetRenderTarget')
+            use, intrinsic :: iso_c_binding
+            implicit none
+            type(c_ptr), intent(in), value :: renderer
+            type(c_ptr)                    :: sdl_get_render_target
+        end function sdl_get_render_target
+
         ! Uint32 SDL_GetTicks(void)
         function sdl_get_ticks() bind(c, name='SDL_GetTicks')
             use, intrinsic :: iso_c_binding
@@ -1465,14 +1473,6 @@
             call c_f_pointer(surface%format, sdl_get_pixel_format)
         end function

-        ! SDL_Texture *SDL_GetRenderTarget(SDL_Renderer *renderer)
-        function sdl_get_render_target(renderer) bind(c, name='SDL_GetRenderTarget')
-            use, intrinsic :: iso_c_binding
-            implicit none
-            type(c_ptr), intent(in), value :: renderer
-            type(c_ptr)                    :: sdl_get_render_target
-        end function sdl_get_render_target
-
         ! SDL_Surface *SDL_GetWindowSurface(SDL_Window *window)
         function sdl_get_window_surface(window)
             !! Calls `sdl_get_window_surface_()` and converts the returned

from fortran-sdl2.

angelog0 avatar angelog0 commented on June 30, 2024

OK, I think the code you propose for quitting should be

integer(C_INT8_T), pointer :: keys(:) => null()

[...]
do while (.not. done)
    rc = sdl_poll_event(event)

    if (rc > 0) then
        select case (event%type)
            case (SDL_QUIT_TYPE)
                done = .true.
            case (SDL_KEY_DOWN)
                keys => sdl_get_keyboard_state()  ! SEE HERE
                ! Quit if player hits Escape:
                if (keys(SDL_SCANCODE_ESCAPE) == 1) then
                    done = .true.
                end if
        end select
    end if
end do

Notice,

keys => sdl_get_keyboard_state()

an association not an assignement:

keys = sdl_get_keyboard_state()

This change suppress also the warning:

POINTER-valued function appears on right-hand side of assignment

from fortran-sdl2.

interkosmos avatar interkosmos commented on June 30, 2024

Sorry for the incomplete example. The complete one:

integer(kind=8), allocatable :: keys(:)
integer                      :: rc

do while (.not. is_done)
    rc = sdl_poll_event(event)

    if (rc > 0) then
        select case (event%type)
            case (SDL_QUIT_TYPE)
                is_done = .true.
            case (SDL_KEY_DOWN)
                keys = sdl_get_keyboard_state()

                ! Quit if player hits Escape:
                if (is_key(keys, SDL_SCANCODE_ESCAPE)) &
                    is_done = .true.
        end select
    end if
end do

The issue with sdl_get_render_target() was solved already, but not commited. Thank you anyway.

from fortran-sdl2.

interkosmos avatar interkosmos commented on June 30, 2024

I’m still looking for the reason why event%key%key_sym%sym doesn’t contain the corrent value.

from fortran-sdl2.

angelog0 avatar angelog0 commented on June 30, 2024

@interkosmos, last you code still gives warnings when compiled with -Wall flag:

gfortran -Wall -std=f2008 `sdl2-config --cflags` ../f03sdl2-master/sdl2.f90 draw_test.f90 -o draw_test `sdl2-config --libs`
draw_test.f90:182:18:

            keys = sdl_get_keyboard_state()
                  1
Warning: POINTER-valued function appears on right-hand side of assignment at (1) [-Wsurprising]
draw_test.f90:182:0:

            keys = sdl_get_keyboard_state()

Warning: 'keys.offset' may be used uninitialized in this function [-Wmaybe-uninitialized]
draw_test.f90:182:0: Warning: 'keys.dim[0].lbound' may be used uninitialized in this function [-Wmaybe-uninitialized]
draw_test.f90:182:0: Warning: 'keys.dim[0].ubound' may be used uninitialized in this function [-Wmaybe-uninitialized]
draw_test.f90:182:0:

            keys = sdl_get_keyboard_state()

Warning: 'keys.dim[0].lbound' may be used uninitialized in this function [-Wmaybe-uninitialized]
draw_test.f90:182:0: Warning: 'keys.dim[0].ubound' may be used uninitialized in this function [-Wmaybe-uninitialized]
draw_test.f90:182:0: Warning: 'keys.dim[0].ubound' may be used uninitialized in this function [-Wmaybe-uninitialized]
draw_test.f90:182:0: Warning: 'keys.dim[0].lbound' may be used uninitialized in this function [-Wmaybe-uninitialized]

Maybe I am wrong, but I think my proposal

integer(C_INT8_T), pointer :: keys(:) => null()
[...]
keys => sdl_get_keyboard_state()

is the right... (See this at section 11.9)

Any way, may you elaborate about this

OOps, just seen your answer, thanks.

from fortran-sdl2.

interkosmos avatar interkosmos commented on June 30, 2024

Yes, I go d’accord with you. Your proposal seems to be better. See #4 (comment), I’m still clueless.

from fortran-sdl2.

angelog0 avatar angelog0 commented on June 30, 2024

After last change I had to change this code:

integer(C_INT8_T), pointer :: keys(:) => null()
[...]
keys => sdl_get_keyboard_state()

in

integer(C_UINT8_T), pointer :: keys(:) => null()
[...]
! the same
keys => sdl_get_keyboard_state()

The new code build without warnings but does not work, typing ESC does not exit the program.

Are you sure that in `sdl2_aliases' (why another module and not using the existing sdl2_consts?)

integer, parameter :: c_uint8_t            = c_int16_t

is the right thing?

If I remember rightly, Fortran for uint.. types wants int.. types of the same size (int8_t) in this case... but this would break other things, so I think you have to review this carefully...

In other words, uint8_t in C is 1 byte while int16_t is 2 byte.

Just this

integer, parameter :: c_uint8_t            = c_int8_t

fixes the issue, and maybe also event%key%key_sym%sym !!!

from fortran-sdl2.

interkosmos avatar interkosmos commented on June 30, 2024

Thank you very much for all the hints. They have been committed.

from fortran-sdl2.

angelog0 avatar angelog0 commented on June 30, 2024

Sorry but there are still some issue. From the SDL2 Wiki:

int SDL_SetRenderDrawColor(SDL_Renderer* renderer,
                           Uint8         r,
                           Uint8         g,
                           Uint8         b,
                           Uint8         a)

but now I find in your code:

! int SDL_SetRenderDrawColor(SDL_Renderer *renderer, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
        function sdl_set_render_draw_color_(renderer, r, g, b, a) bind(c, name='SDL_SetRenderDrawColor')
            use, intrinsic :: iso_c_binding
            use :: sdl2_consts
            implicit none
            type(c_ptr),              intent(in), value :: renderer
            integer(kind=c_uint16_t), intent(in), value :: r
            integer(kind=c_uint16_t), intent(in), value :: g
            integer(kind=c_uint16_t), intent(in), value :: b
            integer(kind=c_uint16_t), intent(in), value :: a
            integer(kind=c_int)                         :: sdl_set_render_draw_color_
        end function sdl_set_render_draw_color_

[...]

! int SDL_SetRenderDrawColor(SDL_Renderer *renderer, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
        function sdl_set_render_draw_color(renderer, r, g, b, a)
            !! Converts integer arguments to c_uint32_t before calling
            !! `sdl_set_render_draw_color_()`.
            use, intrinsic :: iso_c_binding, only: c_ptr
            use :: sdl2_consts
            implicit none
            type(c_ptr), intent(in) :: renderer
            integer,     intent(in) :: r
            integer,     intent(in) :: g
            integer,     intent(in) :: b
            integer,     intent(in) :: a
            integer                 :: sdl_set_render_draw_color

            sdl_set_render_draw_color = sdl_set_render_draw_color_(renderer, &
                                                                   int(r, kind=c_uint16_t), &
                                                                   int(g, kind=c_uint16_t), &
                                                                   int(b, kind=c_uint16_t), &
                                                                   int(a, kind=c_uint16_t))
        end function sdl_set_render_draw_color

which causes

rc = sdl_set_render_draw_color(renderer,int(r,1),int(g,1),int(b,1), &
         1
Error: Type mismatch in argument 'r' at (1); passed INTEGER(1) to INTEGER(4)

If I remember, the previous implementation didn't use the wrapper and maybe it was better. I think the best should be not to use the wrapper

! int SDL_SetRenderDrawColor(SDL_Renderer *renderer, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
        function sdl_set_render_draw_color(renderer, r, g, b, a) bind(c, name='SDL_SetRenderDrawColor')
            use, intrinsic :: iso_c_binding
            use :: sdl2_consts
            implicit none
            type(c_ptr),              intent(in), value :: renderer
            integer(kind=c_uint8_t), intent(in), value :: r
            integer(kind=c_uint8_t), intent(in), value :: g
            integer(kind=c_uint8_t), intent(in), value :: b
            integer(kind=c_uint8_t), intent(in), value :: a
            integer(kind=c_int)                         :: sdl_set_render_draw_color
        end function sdl_set_render_draw_color

I understand you intent (avoid the explicit conversion by the user), but sometime it would be better to reduce the cost to call a function to call a function...

from fortran-sdl2.

interkosmos avatar interkosmos commented on June 30, 2024

But how do you want to store an integer like 255 in c_int8_t? That will cause an arithmetic overflow.

Without a wrapper function, the programmer always has to do the type conversion manually. Boy, that would be annoying.

from fortran-sdl2.

angelog0 avatar angelog0 commented on June 30, 2024

@interkosmos wrote:

But how do you want to store an integer like 255 in c_int8_t?

Have you tried? Why it worked in your previous implementation? In my test case I have color defined with (255,0,127), (255,255,255), (0,255,255)... and all colors where right..

BTW, I interfaced (most) Windows itself this way without issue.. I think it is how ISO C BINDING works. Maybe we have to ask Fortran people...

Without a wrapper function, the programmer always has to do the type conversion manually. Boy, that would be annoying.

No No.. It is not annoying if you can save the cost of calling function, subroutine... Instead that code not only has the cost of conversion (int(..,kind=...)) but also one more function call. Any way do at your best.

And... hem hem with last your commit there is this failure:

gfortran -std=f2008 -Wall `sdl2-config --cflags` -o music examples/music/music.f90 sdl2.o sdl2_mixer.o sdl2_ttf.o `sdl2-config --libs` -lSDL2_mixer -lSDL2_ttf
examples/music/music.f90:62:9:

     rc = mix_open_audio(MIX_DEFAULT_FREQUENCY, &
         1
Error: Type mismatch in argument 'format' at (1); passed INTEGER(4) to INTEGER(2)
make: *** [Makefile:70: music] Error 1

from fortran-sdl2.

interkosmos avatar interkosmos commented on June 30, 2024

Please see the following example:

program example
    use, intrinsic :: iso_c_binding
    implicit none
    integer(kind=c_int8_t) :: foo = int(127, 1) ! works
    integer(kind=c_int8_t) :: bar = int(255, 1) ! doesn't work

    print *, foo, bar
end program example

IMHO the correct type is therefore c_uint16_t.

from fortran-sdl2.

angelog0 avatar angelog0 commented on June 30, 2024

Also this work (a solution adopted in 2006 interfacing for the first time BGI aka WinBGIm v. 3):

$ cat print_uint8_t.c
#include <stdio.h>
#include <stdint.h>

void print_uint8_t(uint8_t u)
{
  printf("%u\n",u);

}

$ cat test_c_uint8_t.f90
!
! gcc -c print_uint8_t.c
! gfortran -std=f2008 test_c_uint8_t.f90 -o test_c_uint8_t.out print_uint8_t.o
! ./getch_test.out
!

program test_c_uint8_t
  implicit none

  interface
     subroutine print_u8(u) bind(c, name='print_uint8_t')
       use, intrinsic :: iso_c_binding, only: C_CHAR
       character(C_CHAR), intent(in), value :: u
     end subroutine print_u8
  end interface

  call print_u8(achar(127))
  call print_u8(achar(0))
  call print_u8(achar(255))

end program test_c_uint8_t

What I don't like is that c_int16_t is 2 byte while in the original C routine the data passed is 1 byte... The C routine takes only the firs byte of it, but I wonder if this is the main street to adopt for this kind of data. I have asked to Fortran people.

Anyway now your example builds fine.. thanks.

from fortran-sdl2.

MadhuASingh avatar MadhuASingh commented on June 30, 2024

The first assignment in this chapter is easy: create a program with a main function and a separate subfunction called hello, which when called prints "Hello there!". The subfunction does not take any parameters or return any value, just prints the line. Then, to the main function, add a call to the subfunction and two print commands, the first one before the call which says "Lets call the subfunction:", and one after the subfunction call, a print command which prints "Quitting.". If implemented correctly, the program will print the following:

from fortran-sdl2.

Related Issues (19)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.