interkosmos / fortran-sdl2 Goto Github PK
View Code? Open in Web Editor NEWFortran 2008 interface bindings to SDL 2.0
License: ISC License
Fortran 2008 interface bindings to SDL 2.0
License: ISC License
The voxel example compiles without issues, but I get a seg fault immediately after the sdl2 window is created.
I tried to write a function to quit an SDL2 Fortran app with ESC
key beside the usual quitting,
function quit() result(r)
use sdl2_consts, only: SDL_QUIT_TYPE, SDL_KEY_DOWN, SDL_SCANCODE_ESCAPE
use sdl2_types, only: sdl_event
use sdl2, only: sdl_poll_event
logical :: r
type(sdl_event) :: event
r = .false.
if (sdl_poll_event(event) > 0) then
select case (event%type)
case (SDL_QUIT_TYPE)
r = .true.
case (SDL_KEY_DOWN)
print *, event%key%key_sym%sym
if (event%key%key_sym%sym == SDL_SCANCODE_ESCAPE) r = .true.
end select
end if
end function quit
program main
[...]
do while (.not.quit())
[...]
! Render to window.
call sdl_render_present(renderer)
call sdl_delay(20)
end do
! Quit gracefully.
call sdl_destroy_renderer(renderer)
call sdl_destroy_window(window)
call sdl_quit()
end program
but it does not work for ESC
key: the PRINT
statement prints always 0
(zero
) regardless of the character pressed, so quit()
is .true.
only when one clicks the upper right X
button.
I suspect a bug here...
I notice that some of the functions have trailing underscores - any reason for this?
I also notice that you opted to include the "sdl_" prefix in front of function names (as the c library does). While I see the possibility of conflicts for functions like init and quit, the other function names are really unique. Any reason why you opted to not strip this prefix?
Sorry if these questions come across as confrontational - it's not my intention. I really appreciate the work you've put into this and was just wondering.
One question: could a SDL2_gfx interface added as well? SDL2_gfx is supported by Msys2.
Or other question: in which way have the SDL2 wrappers been generated?
I do not understand why when you change your code you do it in a very not backward compatible way.
Now a lot of my applications do not build any more just because you wanted be more elegant adding kind=c_char...
which in some cases increases the length of the line and you thought to fix it adding the option -ffree-line-length-none
. Would it be better to break the line? For example, here this works without that annoying option:
- character(kind=c_char, len=*), parameter :: SDL_HINT_WINDOW_FRAME_USABLE_WHILE_CURSOR_HIDDEN = 'SDL_WINDOW_FRAME_USABLE_WHILE_CURSOR_HIDDEN'
+ character(kind=c_char, len=*), parameter :: SDL_HINT_WINDOW_FRAME_USABLE_WHILE_CURSOR_HIDDEN = &
+ 'SDL_WINDOW_FRAME_USABLE_WHILE_CURSOR_HIDDEN'
In a module I have
use sdl2, only: SDL_INIT_VIDEO, SDL_RENDERER_SOFTWARE, SDL_WINDOW_SHOWN, &
SDL_WINDOWPOS_UNDEFINED, &
SDL_QUITEVENT, SDL_KEYDOWN, SDLK_ESCAPE, SDLK_q, &
SDL_KEYDOWN, SDL_MOUSEBUTTONDOWN, SDL_MOUSEWHEEL, &
SDL_WINDOWEVENT, SDL_WINDOWEVENT_CLOSE, SDL_WINDOWEVENT_EXPOSED, &
SDL_WINDOWEVENT_SHOWN, &
sdl_event, sdl_point, sdl_rect, &
sdl_create_renderer, sdl_create_window, &
sdl_destroy_renderer, sdl_destroy_window, &
sdl_get_error, sdl_get_mouse_state, &
sdl_init, sdl_poll_event, sdl_quit, &
sdl_render_clear, sdl_render_draw_line, sdl_render_draw_lines, &
sdl_render_draw_point, sdl_render_draw_points, sdl_render_draw_rect, &
sdl_render_draw_rects, sdl_render_fill_rect, sdl_render_fill_rects, &
sdl_render_get_viewport, sdl_render_present, &
sdl_render_set_viewport, sdl_set_render_draw_color
and never pass column 79... (my Emacs is configured to work with 80 columns and 50 rows).
Often you waste a lot of blanks just because you want all the =
(and so on), aligned... really do you think that the resulting code is more readable?
And why renaming the repo f03sdl2
to f08sdl2
? Now I should change all the scripts/Makefiles to build the apps.. Why not using names like fortran_sdl2
, fsdl2
so that they will remain fixed even with other Fortran standard?
Last but not least, the file sdl2.f90
is so big that Emacs has difficulties to handle it... Wouldn't have been better to break it in more file (even logically)?
No, I can't upgrade my local repo to your change. It would take too long to fix things here and I have no time.
In a C
program this statement
printf("%d %d\n",SDLK_SCANCODE_MASK,SDLK_LEFT);
prints
1073741824 1073741904
In Fortran
, using SDL2.f90
:
print *, SDLK_SCANCODE_MASK,SDLK_LEFT, ' --- pressing LEFT: ',event%key%key_sym%sym
prints
0 81 --- pressing LEFT: 1073741903
This causes
select case (event%key%key_sym%sym)
case (SDLK_LEFT)
to fail: in Fortran
, not only the above SDLK...
constants values are wrong, but also what reports event%key%key_sym%sym
(1073741903
instead of 1073741904
) for LEFT
arrow pressed is wrong..
BTW, maybe we need also SDL_GetMouseState
...
One of the basic, and most useful, primitive found in graphics libraries is that to draw points. For what I can see in SDL2
it should be related to SDL_RenderDrawPoint(s)
...
Thanks
I think the right name is sdl2-fortran
... and not because I use that since your previous renaming.
In any case.. final suggestion! promised...
It works in
make
make all
but fails in building the examples as in:
$ make window
make: *** Nessuna regola per generare l'obiettivo "examples//.f90", necessario per "window". Arresto.
(It means: No rule to generate the target "examples//.f90", needed for "window". Stopping.
)
Are we sure that using $*
here
$(WINDOW): $(DIR)/$*/$*.f90 $(SDL_OBJ)
is the right thing?
Maybe you can add this:
--- sdl2.f90.orig 2019-06-21 17:45:31.179456500 +0200
+++ sdl2.f90 2019-07-07 18:33:29.132599700 +0200
@@ -1698,7 +1698,7 @@
integer(kind=c_int) :: sdl_render_draw_point
end function sdl_render_draw_point
- ! int SDL_RenderDrawPoint(SDL_Renderer *renderer, const SDL_Point *points, int count)
+ ! int SDL_RenderDrawPoints(SDL_Renderer *renderer, const SDL_Point *points, int count)
function sdl_render_draw_points(renderer, points, count) bind(c, name='SDL_RenderDrawPoints')
import :: c_int, c_ptr, sdl_point
implicit none
@@ -2046,6 +2046,25 @@
type(c_ptr), intent(in), value :: renderer
end subroutine sdl_render_present
+ ! int SDL_RenderSetViewport(SDL_Renderer* renderer, const SDL_Rect* rect)
+ function sdl_render_set_viewport(renderer, rect) &
+ bind(c, name='SDL_RenderSetViewport')
+ import :: c_int, c_ptr, sdl_rect
+ implicit none
+ type(c_ptr), intent(in), value :: renderer
+ type(sdl_rect), intent(in) :: rect
+ integer(kind=c_int) :: sdl_render_set_viewport
+ end function sdl_render_set_viewport
+
+ ! void SDL_RenderGetViewport(SDL_Renderer* renderer, SDL_Rect* rect)
+ subroutine sdl_render_get_viewport(renderer, rect) &
+ bind(c, name='SDL_RenderGetViewport')
+ import :: c_int, c_ptr, sdl_rect
+ implicit none
+ type(c_ptr), intent(in), value :: renderer
+ type(sdl_rect), intent(inout) :: rect
+ end subroutine sdl_render_get_viewport
+
! void SDL_RestoreWindow(SDL_Window *window)
subroutine sdl_restore_window(window) bind(c, name='SDL_RestoreWindow')
import :: c_ptr
Thanks (also for the Credits!)
Given this issue, I can build some examples putting all sources in the same folder (just the simplest workaround). For example:
gfortran `sdl2-config --cflags` sdl2.f90 window.f90 -o sdl2f-window `sdl2-config --libs`
(this works both on GNU/Linux Mint
and MSYS2/MINGW64
)
But adding the option -std=f2008
fails
gfortran -std=f2008 `sdl2-config --cflags` sdl2.f90 window.f90 -o sdl2f-window `sdl2-config --libs`
sdl2.f90:12:68:
integer(kind=c_int), parameter :: sdl_windowpos_undefined_mask = z'1FFF0000'
1
Error: GNU Extension: BOZ literal at (1) outside a DATA statement and outside INT/REAL/DBLE/CMPLX
sdl2.f90:13:101:
[...]
A solution would be
integer(kind=c_int), parameter :: sdl_windowpos_undefined_mask = int(z'1FFF0000',kind=kind(sdl_windowpos_undefined_mask))
or the simplest
integer(kind=c_int), parameter :: sdl_windowpos_undefined_mask = int(z'1FFF0000')
I would suggest to add the -std=f2008 option and to use UPPERCASE for parameter variables,
integer(kind=c_int), parameter :: SDL_WINDOWPOS_UNDEFINED_MASK = int(z'1FFF0000')
I flag this just for completeness...
I have tested this code
[...]
case (SDL_MOUSEWHEEL)
r = sdl_get_mouse_state(mouse_x,mouse_y)
if (event%wheel%y == 1) then
r = WHEELUP_EVENT
else
r= WHEELDOWN_EVENT
end if
return
[...]
and it works as expected in both Windows MSYS2/MINGW64
and GNU/Linux Mint
but not on macOS
. On this OS event%wheel%x
and event%wheel%y
are always 0
! both if one moves the wheel up or down.
I wonder if this is a defect of the SDL2 libraries installed there (by means of MacPorts
).
Notice I have a similar fortran code based on XBGI and mouse wheel works also on macOS.
As I wrote elsewhere, after recent changes, this code
write(*,'(A,i0)') 'KEY = ', event%key%key_sym%sym
now works and prints the right values (ASCII code) of the key pressed
So we need the definition for SDLK_ESCAPE and friends which seem are not yet implemented. With those constants this code would work (see #4) too:
if (event%key%key_sym%sym == SDLK_ESCAPE) r = .true.
Using this:
image => sdl_load_bmp('card.bmp' // c_null_char)
If the file is not found, sdl_load_bmp returns without defining sdl_surface. Subsequent calls using this undefined sdl_surface will work even though the sdl_surface is invalid. One way to catch this:
rc = image%w ! this will fail with invalid memory reference if the image was .not. loaded
I'm not sure how to address this issue as we have no exceptions in Fortran. I'm thinking maybe having a:
if (.not. associated(ptr)) ...
defined in the sdl2 calling function instead of just returning as in:
ptr = sdl_load_bmp_rw(sdl_rw_from_file(file, 'rb' // c_null_char), 1)
if (.not. c_associated(ptr)) then !return
error stop "file not found"
In its current version, it does not compile due to:
info.f90:(.text+0x19e): undefined reference to `c_f_string_ptr_'
I see you have added -Wall
to build the examples, but I think, then, you have to add the same to build the modules:
--- Makefile~ 2018-09-10 14:29:02.473566200 +0200
+++ Makefile 2018-09-10 14:40:28.729586700 +0200
@@ -35,16 +35,16 @@
sdl2_ttf: $(TTF_OBJ)
$(SDL_OBJ):
- $(FC) -c $(SDL_SRC)
+ $(FC) -Wall -c $(SDL_SRC)
$(IMG_OBJ):
- $(FC) -c $(IMG_SRC)
+ $(FC) -Wall -c $(IMG_SRC)
$(MIX_OBJ):
- $(FC) -c $(MIX_SRC)
+ $(FC) -Wall -c $(MIX_SRC)
$(TTF_OBJ):
- $(FC) -c $(TTF_SRC)
+ $(FC) -Wall -c $(TTF_SRC)
$(WINDOW): $(EXAMPLES)/$(WINDOW)/$(WINDOW).f90 $(SDL_OBJ)
$(FC) $(CFLAGS) -o $@ $? $(LDFLAGS)
This would trigger some warning in sdl2.f90 which can be easily fixed with:
--- sdl2.f90~ 2018-09-10 13:35:02.000000000 +0200
+++ sdl2.f90 2018-09-10 14:47:53.505814100 +0200
@@ -1036,7 +1036,7 @@
function sdl_get_video_driver_(index) bind(c, name='SDL_GetVideoDriver')
use, intrinsic :: iso_c_binding
implicit none
- integer, intent(in) :: index
+ integer(c_int), intent(in) :: index
type(c_ptr) :: sdl_get_video_driver_
end function sdl_get_video_driver_
@@ -1501,7 +1501,6 @@
type(c_ptr) :: ptr
character(kind=c_char), pointer :: ptrs(:)
character(len=10) :: sdl_get_current_video_driver
- integer :: i
ptr = sdl_get_current_video_driver_()
@@ -1521,7 +1520,6 @@
character(len=100) :: sdl_get_error
type(c_ptr) :: ptr
character(kind=c_char), pointer :: ptrs(:)
- integer :: i
ptr = sdl_get_error_()
@@ -1556,7 +1554,6 @@
character(len=100) :: sdl_get_hint
type(c_ptr) :: ptr
character(kind=c_char), pointer :: ptrs(:)
- integer :: i
ptr = sdl_get_hint_(name // c_null_char)
@@ -1589,7 +1586,6 @@
type(c_ptr) :: ptr
character(kind=c_char), pointer :: ptrs(:)
character(len=10) :: sdl_get_video_driver
- integer :: i
ptr = sdl_get_video_driver_(index)
On MSYS2/MINGW64 I have
$ gfortran -v
Using built-in specs.
COLLECT_GCC=C:\msys64\mingw64\bin\gfortran.exe
COLLECT_LTO_WRAPPER=C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/10.1.0/lto-wrapper.exe
Target: x86_64-w64-mingw32
Configured with: ../gcc-10.1.0/configure --prefix=/mingw64 --with-local-prefix=/mingw64/local --build=x86_64-w64-mingw32 --host=x86_64-w64-mingw32 --target=x86_64-w64-mingw32 --with-native-system-header-dir=/mingw64/x86_64-w64-mingw32/include --libexecdir=/mingw64/lib --enable-bootstrap --with-arch=x86-64 --with-tune=generic --enable-languages=c,lto,c++,fortran,ada,objc,obj-c++ --enable-shared --enable-static --enable-libatomic --enable-threads=posix --enable-graphite --enable-fully-dynamic-string --enable-libstdcxx-filesystem-ts=yes --enable-libstdcxx-time=yes --disable-libstdcxx-pch --disable-libstdcxx-debug --disable-isl-version-check --enable-lto --enable-libgomp --disable-multilib --enable-checking=release --disable-rpath --disable-win32-registry --disable-nls --disable-werror --disable-symvers --disable-plugin --with-libiconv --with-system-zlib --with-gmp=/mingw64 --with-mpfr=/mingw64 --with-mpc=/mingw64 --with-isl=/mingw64 --with-pkgversion='Rev3, Built by MSYS2 project' --with-bugurl=https://sourceforge.net/projects/msys2 --with-gnu-as --with-gnu-ld
Thread model: posix
Supported LTO compression algorithms: zlib zstd
gcc version 10.1.0 (Rev3, Built by MSYS2 project)
and rebuilding my apps and your examples I get some warnings regarding stack violation. For example
$ make voxel
gfortran -Wall -std=f2008 -fmax-errors=1 `sdl2-config --cflags` -fPIC -c src/c_util.f90 src/sdl2/sdl2_stdinc.f90 src/sdl2/sdl2_audio.f90 src/sdl2/sdl2_blendmode.f90 src/sdl2/sdl2_cpuinfo.f90 src/sdl2/sdl2_error.f90 src/sdl2/sdl2_events.f90 src/sdl2/sdl2_filesystem.f90 src/sdl2/sdl2_hints.f90 src/sdl2/sdl2_keyboard.f90 src/sdl2/sdl2_log.f90 src/sdl2/sdl2_messagebox.f90 src/sdl2/sdl2_rect.f90 src/sdl2/sdl2_pixels.f90 src/sdl2/sdl2_platform.f90 src/sdl2/sdl2_scancode.f90 src/sdl2/sdl2_surface.f90 src/sdl2/sdl2_render.f90 src/sdl2/sdl2_keycode.f90 src/sdl2/sdl2_mouse.f90 src/sdl2/sdl2_rwops.f90 src/sdl2/sdl2_thread.f90 src/sdl2/sdl2_timer.f90 src/sdl2/sdl2_version.f90 src/sdl2/sdl2_video.f90 src/sdl2/sdl2_opengl.f90 src/sdl2.f90
ar rcs sdl2.a sdl2.o
gfortran -Wall -std=f2008 -fmax-errors=1 `sdl2-config --cflags` -o examples/voxel/voxel examples/voxel/voxel.f90 sdl2.a `sdl2-config --libs`
examples/voxel/voxel.f90:71:61:
71 | type(voxel_type) :: voxels(MAP_WIDTH, MAP_HEIGHT)
| 1
Warning: Array 'voxels' at (1) is larger than limit set by '-fmax-stack-var-size=', moved from stack to static storage. This makes the procedure unsafe when called recursively, or concurrently from multiple threads. Consider using '-frecursive', or increase the '-fmax-stack-var-size=' limit, or change the code to use an ALLOCATABLE array. [-Wsurprising]
I have tried to add the save
attribute but this does not help, the warnings remain. BTW, in my apps the arrays are declered in a module:
module foo
[...]
real(WP) :: d(0:NPOINTS,0:NPOINTS), g(0:NPOINTS,0:NPOINTS), &
[...]
end module foo
gfortran -std=f2008 -O3 -Wall -Wno-unused-dummy-argument -c SDL2_flux_stream.f90
SDL2_flux_stream.f90:146:42:
146 | real(WP) :: d(0:NPOINTS,0:NPOINTS), g(0:NPOINTS,0:NPOINTS), &
| 1
Warning: Array 'd' at (1) is larger than limit set by '-fmax-stack-var-size=', moved from stack to static storage. This makes the procedure unsafe when called recursively, or concurrently from multiple threads. Consider using '-frecursive', or increase the '-fmax-stack-var-size=' limit, or change the code to use an ALLOCATABLE array. [-Wsurprising]
Any idea how to fix these warnings without increase the stack etc.?
Hi Philipp,
In sdl2_image.f90, line 27, you specify the c procedure binding label IMG_LoadTexture
function img_load(file_name) bind(c, name='IMG_LoadTexture')
If I'm not mistaken the correct c procedure binding should be IMG_Load?
Great work btw. I enjoy playing around with it.
Best wishes
Sebastian
Try this:
make msgbox
./msgbox
the output is
Program received signal SIGSEGV: Segmentation fault - invalid memory reference.
Backtrace for this error:
#0 0xffffffff
#1 0xffffffff
#2 0xffffffff
#3 0xffffffff
#4 0xffffffff
#5 0xffffffff
#6 0xffffffff
#7 0xffffffff
#8 0xffffffff
#9 0xffffffff
#10 0xffffffff
#11 0xffffffff
#12 0xffffffff
#13 0xffffffff
#14 0xffffffff
#15 0xffffffff
#16 0xffffffff
Indeed you call sdl_show_simple_message_box(...,window)
before window
is defined... On which system have you tested it?
This fixes the issue:
$ diff -Naur examples/msgbox/msgbox.f90~ examples/msgbox/msgbox.f90
--- examples/msgbox/msgbox.f90~ 2018-09-20 13:22:11.550268400 +0200
+++ examples/msgbox/msgbox.f90 2018-09-20 13:27:30.862742700 +0200
@@ -31,12 +31,6 @@
stop
end if
- ! Show message box.
- rc = sdl_show_simple_message_box(SDL_MESSAGEBOX_INFORMATION, &
- MSG_TITLE // c_null_char, &
- MSG_TEXT // c_null_char, &
- window)
-
! Create the SDL window.
window = sdl_create_window('SDL2 Fortran' // c_null_char, &
SDL_WINDOWPOS_UNDEFINED, &
@@ -45,6 +39,12 @@
HEIGHT, &
SDL_WINDOW_SHOWN)
+ ! Show message box.
+ rc = sdl_show_simple_message_box(SDL_MESSAGEBOX_INFORMATION, &
+ MSG_TITLE // c_null_char, &
+ MSG_TEXT // c_null_char, &
+ window)
+
if (.not. c_associated(window)) then
print *, 'SDL Error: ', sdl_get_error()
stop
Ooops, thanks for the enum
...
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.