Recent

Author Topic: SDL2 image rotation Problem  (Read 6939 times)

Pe3s

  • Hero Member
  • *****
  • Posts: 590
SDL2 image rotation Problem
« on: December 13, 2024, 09:54:47 pm »
Hello forumers I am learning SDL and I have encountered a problem after loading the image format “portrait” rotation and fitting the image to the window margins appear at the top and bottom , when loading the image format landscape the problem does not occur how can I correct the error in the code ?
Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8. Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ComCtrls, ExtCtrls,
  9.   StdCtrls, SDL2, SDL2_image, Math;
  10.  
  11. type
  12.  
  13.   { TForm1 }
  14.  
  15.   TForm1 = class(TForm)
  16.     Button1: TButton;
  17.     Button2: TButton;
  18.     Button3: TButton;
  19.     Button4: TButton;
  20.     Button5: TButton;
  21.     Button6: TButton;
  22.     Button7: TButton;
  23.     OpenDialog1: TOpenDialog;
  24.     Panel1: TPanel;
  25.     Panel2: TPanel;
  26.     StatusBar1: TStatusBar;
  27.     procedure Button1Click(Sender: TObject);
  28.     procedure Button2Click(Sender: TObject);
  29.     procedure Button3Click(Sender: TObject);
  30.     procedure Button4Click(Sender: TObject);
  31.     procedure Button5Click(Sender: TObject);
  32.     procedure Button6Click(Sender: TObject);
  33.     procedure Button7Click(Sender: TObject);
  34.     procedure FormDestroy(Sender: TObject);
  35.     procedure FormResize(Sender: TObject);
  36.     procedure FormShow(Sender: TObject);
  37.     procedure Panel1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  38.     procedure Panel1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
  39.     procedure Panel1MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  40.     procedure Panel1Paint(Sender: TObject);
  41.   private
  42.     SDLWindow: PSDL_Window;
  43.     SDLRenderer: PSDL_Renderer;
  44.     CurrentTexture: PSDL_Texture;
  45.  
  46.     OffsetX, OffsetY, ZoomLevel, MinZoom, MaxZoom, FRotationAngle: Double;
  47.     IsPanning: Boolean;
  48.     LastMouseX, LastMouseY, ImgWidth, ImgHeight: Integer;
  49.  
  50.     procedure InitializeSDL;
  51.     procedure ShutdownSDL;
  52.     procedure LoadAndDisplayImage(const FileName: string);
  53.     procedure RenderImage;
  54.     procedure CenterImage;
  55.     procedure Zoom(Delta: Double; FocusX, FocusY: Integer);
  56.     procedure FitImage;
  57.  
  58.   public
  59.  
  60.   end;
  61.  
  62. var
  63.   Form1: TForm1;
  64.  
  65. implementation
  66.  
  67. {$R *.lfm}
  68.  
  69. { TForm1 }
  70.  
  71. procedure TForm1.FormShow(Sender: TObject);
  72. begin
  73.    InitializeSDL;
  74.   ZoomLevel := 1.0;
  75.   OffsetX := 0;
  76.   OffsetY := 0;
  77.   IsPanning := False;
  78.  
  79.    ImgWidth := 0;  // No image loaded yet
  80.   ImgHeight := 0; // No image loaded yet
  81.   CurrentTexture := nil;
  82. end;
  83.  
  84. procedure TForm1.Panel1MouseDown(Sender: TObject; Button: TMouseButton;
  85.   Shift: TShiftState; X, Y: Integer);
  86. begin
  87.   if Button = mbLeft then
  88.   begin
  89.     IsPanning := True;
  90.     LastMouseX := X;
  91.     LastMouseY := Y;
  92.   end;
  93. end;
  94.  
  95. procedure TForm1.Panel1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
  96. begin
  97.   if IsPanning then
  98.   begin
  99.     OffsetX := OffsetX + (X - LastMouseX);
  100.     OffsetY := OffsetY + (Y - LastMouseY);
  101.  
  102.     LastMouseX := X;
  103.     LastMouseY := Y;
  104.  
  105.     RenderImage;
  106.   end;
  107. end;
  108.  
  109. procedure TForm1.Panel1MouseUp(Sender: TObject; Button: TMouseButton;
  110.   Shift: TShiftState; X, Y: Integer);
  111. begin
  112.     if Button = mbLeft then
  113.     IsPanning := False;
  114. end;
  115.  
  116. procedure TForm1.Panel1Paint(Sender: TObject);
  117. begin
  118.    // Draw a red rectangle (example)
  119.   SDL_SetRenderDrawColor(sdlRenderer, 0, 0, 0, 255);
  120.   SDL_RenderFillRect(sdlRenderer, nil); // Full screen fill
  121.   SDL_RenderPresent(sdlRenderer);
  122.  
  123.    RenderImage;
  124. end;
  125.  
  126. procedure TForm1.FormDestroy(Sender: TObject);
  127. begin
  128.   ShutdownSDL;
  129. end;
  130.  
  131. procedure TForm1.FormResize(Sender: TObject);
  132.  var
  133.   PanelWidth, PanelHeight: Integer;
  134. begin
  135.   PanelWidth := Panel1.Width;
  136.   PanelHeight := Panel1.Height;
  137.  
  138.   // Skip fitting or rendering if no image is loaded
  139.   if (ImgWidth = 0) or (ImgHeight = 0) then Exit;
  140.  
  141.   // Check for valid dimensions before fitting or rendering
  142.   if (PanelWidth > 0) and (PanelHeight > 0) then
  143.   begin
  144.     FitImage; // Automatically fit the image on resize
  145.   end;
  146. end;
  147.  
  148. procedure TForm1.Button1Click(Sender: TObject);
  149. begin
  150.    if OpenDialog1.Execute then
  151.     LoadAndDisplayImage(OpenDialog1.FileName);
  152. end;
  153.  
  154. procedure TForm1.Button2Click(Sender: TObject);
  155. begin
  156.  Zoom(1, Panel1.Width div 2, Panel1.Height div 2); // Zoom in towards the center
  157. end;
  158.  
  159. procedure TForm1.Button3Click(Sender: TObject);
  160. begin
  161.    Zoom(-1, Panel1.Width div 2, Panel1.Height div 2); // Zoom out towards the cente
  162. end;
  163.  
  164. procedure TForm1.Button4Click(Sender: TObject);
  165. begin
  166.   ZoomLevel:= 1.0;
  167.   CenterImage;
  168.   RenderImage;
  169. end;
  170.  
  171. procedure TForm1.Button5Click(Sender: TObject);
  172. begin
  173.      FitImage; // Reset zoom and center the image
  174. end;
  175.  
  176. procedure TForm1.Button6Click(Sender: TObject);
  177. begin
  178.   FRotationAngle := (FRotationAngle -90) mod 360;
  179.   RenderImage;
  180. end;
  181.  
  182. procedure TForm1.Button7Click(Sender: TObject);
  183. begin
  184.   FRotationAngle := (FRotationAngle +90) mod 360;
  185.   RenderImage;
  186. end;
  187.  
  188. procedure TForm1.InitializeSDL;
  189. begin
  190.   if SDL_Init(SDL_INIT_VIDEO) < 0 then
  191.     raise Exception.Create('Nie udało się zainicjować SDL: ' + SDL_GetError);
  192.  
  193.   SDLWindow := SDL_CreateWindowFrom(Pointer(Panel1.Handle));
  194.   if SDLWindow = nil then
  195.     raise Exception.Create('Nie udało się utworzyć okna SDL: ' + SDL_GetError);
  196.  
  197.   SDLRenderer := SDL_CreateRenderer(sdlWindow, -1, SDL_RENDERER_ACCELERATED or SDL_RENDERER_PRESENTVSYNC);
  198.   if SDLRenderer = nil then
  199.     raise Exception.Create('Nie można utworzyć renderowania SDL: ' + SDL_GetError);
  200.  
  201.   ZoomLevel := 1.0; // Initialize zoom level
  202.  
  203. end;
  204.  
  205. procedure TForm1.ShutdownSDL;
  206. begin
  207.    if CurrentTexture <> nil then
  208.     SDL_DestroyTexture(CurrentTexture);
  209.   if SDLRenderer <> nil then
  210.     SDL_DestroyRenderer(SDLRenderer);
  211.   if SDLWindow <> nil then
  212.     SDL_DestroyWindow(SDLWindow);
  213.   IMG_Quit;
  214.   SDL_Quit;
  215. end;
  216.  
  217. procedure TForm1.LoadAndDisplayImage(const FileName: string);
  218.   var
  219.   PanelWidth, PanelHeight: Integer;
  220.   FitZoom: Double;
  221. begin
  222.   if CurrentTexture <> nil then
  223.     SDL_DestroyTexture(CurrentTexture);
  224.  
  225.   CurrentTexture := IMG_LoadTexture(SDLRenderer, PChar(FileName));
  226.   if CurrentTexture = nil then
  227.     raise Exception.Create('Nie udało się wczytać tekstury: ' + IMG_GetError);
  228.  
  229.   // Query the texture for its dimensions
  230.   SDL_QueryTexture(CurrentTexture, nil, nil, @ImgWidth, @ImgHeight);
  231.  
  232.  
  233.   // Calculate initial zoom to fit the image in the panel
  234.   PanelWidth := Panel1.Width;
  235.   PanelHeight := Panel1.Height;
  236.   FitZoom := Min(PanelWidth / ImgWidth, PanelHeight / ImgHeight);
  237.  
  238.   // Set zoom level and center offsets
  239.   ZoomLevel := FitZoom;
  240.   OffsetX := (PanelWidth - Round(ImgWidth * ZoomLevel)) div 2;
  241.   OffsetY := (PanelHeight - Round(ImgHeight * ZoomLevel)) div 2;
  242.  
  243.   // Set zoom limits
  244.   MinZoom := FitZoom * 0.5; // Allow zooming out to 50% of fit size
  245.   MaxZoom := 3.0; // Allow zooming in up to 300%
  246.  
  247.   RenderImage;
  248.   FitImage;
  249. end;
  250.  
  251. procedure TForm1.RenderImage;
  252.   var
  253.     DstRect: TSDL_Rect;
  254.     PanelWidth, PanelHeight: Integer;
  255.   begin
  256.     if CurrentTexture = nil then Exit; // No texture to render
  257.  
  258.     PanelWidth := Panel1.Width;
  259.     PanelHeight := Panel1.Height;
  260.  
  261.     if (PanelWidth <= 0) or (PanelHeight <= 0) then Exit; // Avoid rendering if panel is invalid
  262.  
  263.     // Calculate destination rectangle with zoom and offsets
  264.     DstRect.w := Round(ImgWidth * ZoomLevel);
  265.     DstRect.h := Round(ImgHeight * ZoomLevel);
  266.  
  267.     // Constrain panning to avoid blank spaces
  268.     if DstRect.w <= PanelWidth then
  269.       OffsetX := (PanelWidth - DstRect.w) / 2
  270.     else
  271.       OffsetX := Max(Min(OffsetX, 0), PanelWidth - DstRect.w);
  272.  
  273.     if DstRect.h <= PanelHeight then
  274.       OffsetY := (PanelHeight - DstRect.h) / 2
  275.     else
  276.       OffsetY := Max(Min(OffsetY, 0), PanelHeight - DstRect.h);
  277.  
  278.     DstRect.x := Round(OffsetX);
  279.     DstRect.y := Round(OffsetY);
  280.  
  281.     SDL_RenderClear(SDLRenderer);
  282.  
  283.     // Render the image
  284.     SDL_RenderCopyEx(SDLRenderer, CurrentTexture, nil, @DstRect, FRotationAngle, nil, SDL_FLIP_NONE);
  285.     SDL_RenderPresent(SDLRenderer);
  286. end;
  287.  
  288. procedure TForm1.CenterImage;
  289.  var
  290.   PanelWidth, PanelHeight: Integer;
  291. begin
  292.   if (ImgWidth = 0) or (ImgHeight = 0) or (CurrentTexture = nil) then Exit;
  293.  
  294.   PanelWidth := Panel1.Width;
  295.   PanelHeight := Panel1.Height;
  296.  
  297.   // Reset offsets to center the image
  298.   OffsetX := (PanelWidth - ImgWidth * ZoomLevel) / 2;
  299.   OffsetY := (PanelHeight - ImgHeight * ZoomLevel) / 2;
  300.  
  301.   RenderImage;
  302. end;
  303.  
  304. procedure TForm1.Zoom(Delta: Double; FocusX, FocusY: Integer);
  305.  var
  306.   OldZoom: Double;
  307.   PanelWidth, PanelHeight: Integer;
  308.   ImageCenterX, ImageCenterY: Double;
  309. begin
  310.   if (ImgWidth = 0) or (ImgHeight = 0) or (CurrentTexture = nil) then Exit;
  311.  
  312.   OldZoom := ZoomLevel;
  313.   PanelWidth := Panel1.Width;
  314.   PanelHeight := Panel1.Height;
  315.  
  316.   // Adjust zoom level with bounds
  317.   ZoomLevel := Max(MinZoom, Min(MaxZoom, ZoomLevel + Delta * 0.1));
  318.  
  319.   // Compute focus point scaling
  320.   if ZoomLevel <> OldZoom then
  321.   begin
  322.     ImageCenterX := (FocusX - OffsetX) / OldZoom;
  323.     ImageCenterY := (FocusY - OffsetY) / OldZoom;
  324.  
  325.     OffsetX := FocusX - ImageCenterX * ZoomLevel;
  326.     OffsetY := FocusY - ImageCenterY * ZoomLevel;
  327.   end;
  328.  
  329.   // Update caption
  330.   Form1.Caption := Format('Zoom: %.0f%%', [ZoomLevel * 100]);
  331.  
  332.   RenderImage;
  333. end;
  334.  
  335. procedure TForm1.FitImage;
  336.  var
  337.   RotatedWidth, RotatedHeight: Double;
  338.   ScalingFactor: Double;
  339.   AngleRadians: Double;
  340. begin
  341.   if (ImgWidth = 0) or (ImgHeight = 0) or (CurrentTexture = nil) then Exit;
  342.  
  343.   // Normalize the rotation angle to the range [0, 360)
  344.   AngleRadians := DegToRad((FRotationAngle mod 360 + 360) mod 360);
  345.  
  346.   // Calculate rotated bounding box dimensions
  347.   RotatedWidth := Abs(ImgWidth * Cos(AngleRadians)) + Abs(ImgHeight * Sin(AngleRadians));
  348.   RotatedHeight := Abs(ImgWidth * Sin(AngleRadians)) + Abs(ImgHeight * Cos(AngleRadians));
  349.  
  350.   // Calculate scaling factor to fit the panel's height
  351.   ScalingFactor := Panel1.Height / RotatedHeight;
  352.  
  353.   // Update the zoom level to maintain proportional scaling
  354.   ZoomLevel := ScalingFactor;
  355.  
  356.   // Recalculate offsets to ensure proper centering
  357.   CenterImage;
  358. end;
  359.  
  360. end.
  361.  
  362.  
  363.  
Greetings
« Last Edit: December 30, 2024, 06:39:55 pm by Pe3s »

bobihot

  • New Member
  • *
  • Posts: 37
Re: SDL2 Fit image rotation bug
« Reply #1 on: December 13, 2024, 10:31:27 pm »
Try with
Lazarus-SDL3.0-Packages_and_Examples

https://github.com/sechshelme/Lazarus-SDL3.0-Packages_and_Examples

Me also interested, because I was used on Delphi. But I do not try now.
Thanks

Pe3s

  • Hero Member
  • *****
  • Posts: 590
Re: SDL2 Fit image rotation bug
« Reply #2 on: December 14, 2024, 07:18:57 pm »
This is not an SDL bug rather my code.
The loaded image in landscape aspect ratio works , but when I load a portrait there is a problem when rotating.

Pe3s

  • Hero Member
  • *****
  • Posts: 590
Re: SDL2 Fit image rotation bug
« Reply #3 on: December 18, 2024, 12:08:48 pm »
How can I dynamically swap the height with the width and update the sdl window ?
So that the rotated image will adjust to the window

Roland57

  • Sr. Member
  • ****
  • Posts: 487
    • msegui.net
Re: SDL2 Fit image rotation bug
« Reply #4 on: December 19, 2024, 02:21:28 am »
Hello!

By the way, I can compile your project, but I get this error when I try to run it:

[roland@localhost sdl_image]$ ./project1
The program 'project1' received an X Window System error.
This probably reflects a bug in the program.
The error was 'BadWindow (invalid Window parameter)'.
  (Details: serial 88 error_code 3 request_code 20 minor_code 0)
  (Note to programmers: normally, X errors are reported asynchronously;
   that is, you will receive the error a while after causing it.
   To debug your program, run it with the --sync command line
   option to change this behavior. You can then get a meaningful
   backtrace from your debugger if you break on the gdk_x_error() function.)


I took a look at your code. The logic is too complicated for me.  :)
« Last Edit: December 19, 2024, 03:16:36 am by Roland57 »
My projects are on Gitlab and on Codeberg.

Pe3s

  • Hero Member
  • *****
  • Posts: 590
Re: SDL2 Fit image rotation bug
« Reply #5 on: December 19, 2024, 02:30:31 pm »
Under Windows it compiles and runs correctly

Fred vS

  • Hero Member
  • *****
  • Posts: 3455
    • StrumPract is the musicians best friend
Re: SDL2 Fit image rotation bug
« Reply #6 on: December 19, 2024, 03:15:56 pm »
Hello!

By the way, I can compile your project, but I get this error when I try to run it:

[roland@localhost sdl_image]$ ./project1
The program 'project1' received an X Window System error.
This probably reflects a bug in the program.
The error was 'BadWindow (invalid Window parameter)'.
  (Details: serial 88 error_code 3 request_code 20 minor_code 0)
  (Note to programmers: normally, X errors are reported asynchronously;
   that is, you will receive the error a while after causing it.
   To debug your program, run it with the --sync command line
   option to change this behavior. You can then get a meaningful
   backtrace from your debugger if you break on the gdk_x_error() function.)


I took a look at your code. The logic is too complicated for me.  :)

Hello Roland.

On Linux, maybe you can try with msegui:
https://github.com/mse-org/mseide-msegui/discussions/94

 ;)

Fre;D
I use Lazarus 2.2.0 32/64 and FPC 3.2.2 32/64 on Debian 11 64 bit, Windows 10, Windows 7 32/64, Windows XP 32,  FreeBSD 64.
Widgetset: fpGUI, MSEgui, Win32, GTK2, Qt.

https://github.com/fredvs
https://gitlab.com/fredvs
https://codeberg.org/fredvs

Pe3s

  • Hero Member
  • *****
  • Posts: 590
Re: SDL2 image rotation
« Reply #7 on: December 30, 2024, 07:40:26 am »
Below I present a visualization of image rotation as SDL performs it.
The problem that I can't solve is this image rotation with swapping image dimensions.
« Last Edit: December 30, 2024, 06:05:42 pm by Pe3s »

Pe3s

  • Hero Member
  • *****
  • Posts: 590
Re: SDL2 image rotation Problem
« Reply #8 on: January 03, 2025, 07:52:38 am »
Below are two images the first loaded not rotated and the second rotated with incorrect proportions which I am trying to fix

Seenkao

  • Hero Member
  • *****
  • Posts: 649
    • New ZenGL.
Re: SDL2 image rotation Problem
« Reply #9 on: January 04, 2025, 12:11:05 am »
Pe3s, вам ни кто не сможет помочь, хотя бы по простой причине, что непонятно, как вы поворачиваете свой объект. Даже люди использующие SDL вряд ли смогут вам помочь.

Поворот может быть выполнен несколькими способами:
- повернули весь экран.
- повернули текстуру.
- повернули объект.
- какой-то другой способ?

Если вы повернули весь экран, то это означает, что вы не учитываете при повороте ни какого масштаба. И просто повернули экран так, будь-то он  квадратный, а не прямоугольный (надо либо обрезать, либо масштабировать экран), для прямоугольного экрана, при повороте, надо пересчитывать все объекты согласно поворота и согласно центра экрана.

Если вы повернули объект или текстуру, то вероятно вы та же проблема что и выше, только тут вам для поворота надо пересчитывать координаты объекта или текстуры соответственно (помнить, что вы поворачиваете не квадрат, а прямоугольник).

Без вашего кода, сложно что-то вообще говорить о вашей проблеме.

------------------------------------------------
Google translate:
Pe3s, no one can help you, at least for the simple reason that it is not clear how you rotate your object. Even people using SDL are unlikely to be able to help you.

Rotation can be done in several ways:
- rotated the entire screen.
- rotated the texture.
- rotated the object.
- some other way?

If you rotated the entire screen, this means that you do not take into account any scale when rotating. And you simply rotated the screen, whether it is square, and not rectangular (you either need to crop or scale the screen), for a rectangular screen, when rotating, you need to recalculate all objects according to the rotation and according to the center of the screen.

If you rotated an object or texture, then you probably have the same problem as above, only here you need to recalculate the coordinates of the object or texture accordingly (remember that you are rotating not a square, but a rectangle).

Without your code, it is difficult to say anything about your problem.
Rus: Стремлюсь к созданию минимальных и достаточно быстрых приложений.

Eng: I strive to create applications that are minimal and reasonably fast.
Working on ZenGL

Pe3s

  • Hero Member
  • *****
  • Posts: 590
Re: SDL2 image rotation Problem
« Reply #10 on: January 05, 2025, 08:02:07 am »
@Seenkao, If you are able to help, please provide the entire code

Pe3s

  • Hero Member
  • *****
  • Posts: 590
Re: SDL2 image rotation Problem
« Reply #11 on: January 11, 2025, 06:08:53 pm »
Can anyone help or is it over with the code questions :)

Fred vS

  • Hero Member
  • *****
  • Posts: 3455
    • StrumPract is the musicians best friend
Re: SDL2 image rotation Problem
« Reply #12 on: January 12, 2025, 09:05:55 pm »
Can anyone help or is it over with the code questions :)
Maybe if you add a valid tar it would be easier. (and dont use space " " but "_" instead :-X )
Code: Pascal  [Select][+][-]
  1. $ tar -xvzf Image_Browser_0.3.rar
  2.  
  3. gzip: stdin: not in gzip format
  4. tar: Child returned status 1
  5. tar: Error is not recoverable: exiting now

About rotation of image, I cannot see your code but if you use that method to load it:
Code: Pascal  [Select][+][-]
  1. SDL_LoadBMPFromFile('aimage.bmp');
A workaround would be to use BGRABitmap and do the rotation of the original file or already loaded bitmap and save it as tempory bmp.
Then reload the new rotated image with SDL_LoadBMPFromFile('arotatedimage.bmp') then delete it.
But I agree it is a workaround.

Note that I am a new explorer of SDL2 and I tested it only using MSEgui.
https://github.com/mse-org/mseide-msegui/discussions/94
« Last Edit: January 12, 2025, 09:11:23 pm by Fred vS »
I use Lazarus 2.2.0 32/64 and FPC 3.2.2 32/64 on Debian 11 64 bit, Windows 10, Windows 7 32/64, Windows XP 32,  FreeBSD 64.
Widgetset: fpGUI, MSEgui, Win32, GTK2, Qt.

https://github.com/fredvs
https://gitlab.com/fredvs
https://codeberg.org/fredvs

TRon

  • Hero Member
  • *****
  • Posts: 3778
Re: SDL2 image rotation Problem
« Reply #13 on: January 12, 2025, 09:14:15 pm »
gzip: stdin: not in gzip format
tar: Child returned status 1
tar: Error is not recoverable: exiting now
You could use either 7z or (un)rar to extract rar archives. tar is not able to do that.
I do not have to remember anything anymore thanks to total-recall.

Fred vS

  • Hero Member
  • *****
  • Posts: 3455
    • StrumPract is the musicians best friend
Re: SDL2 image rotation Problem
« Reply #14 on: January 12, 2025, 09:30:11 pm »
gzip: stdin: not in gzip format
tar: Child returned status 1
tar: Error is not recoverable: exiting now
You could use either 7z or (un)rar to extract rar archives. tar is not able to do that.

Hello TRon.
unrar did the trick, thanks (but 7z failed, all the files have 0kb).
« Last Edit: January 12, 2025, 10:01:41 pm by Fred vS »
I use Lazarus 2.2.0 32/64 and FPC 3.2.2 32/64 on Debian 11 64 bit, Windows 10, Windows 7 32/64, Windows XP 32,  FreeBSD 64.
Widgetset: fpGUI, MSEgui, Win32, GTK2, Qt.

https://github.com/fredvs
https://gitlab.com/fredvs
https://codeberg.org/fredvs

 

TinyPortal © 2005-2018