M0n7y5/raylib-beef

Some notes for Linux

Closed this issue · 6 comments

OK, so I decided to use this library with linux. But, as with many other things it didn't work right away. So, I've decided to write this as a note for others who might want to do the same.

  1. Install raylib (duh!)
    The binaries for raylib in the release don't work on linux. Luckily, raylib is quite easy to get-just follow the instructions here.

2)Get rid of Windows dependencies in the binding
There are 4 Windows.IntBool s in Types/PhysicsBodyData.bf. I replaced them with int32 to maintain the size of the struct, but this might have broken something in the physics system-NOT TESTED.

3)Add linker flags to the BeefProj.toml file of YOUR project - not the library.

[Configs.Debug.Linux64]
OtherLinkFlags = "$(LinkFlags) -lraylib -lglfw -lGL -lopenal -lm -pthread -ldl"

Adding this should solve any linker errors, and the project should now compile and run.

Oh yeah i forgot to add some info about non windows OS support. I am gonna do that ASAP.

Yeah... About that-while the example on the readme works fine, the overall bindings are... problematic.

I transpiled the "2d camera" demo from https://www.raylib.com/examples, and it didn't work. Here's the transpiled code:

using raylib_beef;
using raylib_beef.Types;
using System;

namespace raylibtest
{
	public static class Program : Raylib
	{
		const int MAX_COLUMNS = 20;
		const int MAX_BUILDINGS = 100;

		public static void Main()
		{
			// Initialization
			//--------------------------------------------------------------------------------------
			const int screenWidth = 800;
			const int screenHeight = 450;

			InitWindow(screenWidth, screenHeight, "raylib [core] example - 2d camera");

			Rectangle player = Rectangle(400, 280, 40, 40);
			Rectangle[] buildings= scope Rectangle[MAX_BUILDINGS];
			Color[] buildColors = scope Color[MAX_BUILDINGS];

			int spacing = 0;

			for (int i = 0; i < MAX_BUILDINGS; i++)
			{
			    buildings[i].width = GetRandomValue(50, 200);
			    buildings[i].height = GetRandomValue(100, 800);
			    buildings[i].y = screenHeight - 130 - buildings[i].height;
			    buildings[i].x = -6000 + spacing;

			    spacing += (int)buildings[i].width;

			    buildColors[i] = .((uint8)GetRandomValue(200, 240), (uint8)GetRandomValue(200, 240), (uint8)GetRandomValue(200, 250), 255);
			}

			Camera2D camera;
			camera.target = .(player.x + 20, player.y + 20);
			camera.offset = .(screenWidth/2, screenHeight/2);
			camera.rotation = 0.0f;
			camera.zoom = 1.0f;

			SetTargetFPS(60);                   // Set our game to run at 60 frames-per-second
			//--------------------------------------------------------------------------------------

			// Main game loop
			while (!WindowShouldClose())        // Detect window close button or ESC key
			{
			    // Update
			    //----------------------------------------------------------------------------------
			    
			    // Player movement
			    if (IsKeyDown(.KEY_RIGHT)) player.x += 2;
			    else if (IsKeyDown(.KEY_LEFT)) player.x -= 2;

			    // Camera target follows player
			    camera.target = .(player.x + 20, player.y + 20);

			    // Camera rotation controls
			    if (IsKeyDown(.KEY_A)) camera.rotation--;
			    else if (IsKeyDown(.KEY_S)) camera.rotation++;

			    // Limit camera rotation to 80 degrees (-40 to 40)
			    if (camera.rotation > 40) camera.rotation = 40;
			    else if (camera.rotation < -40) camera.rotation = -40;

			    // Camera zoom controls
			    camera.zoom += ((float)GetMouseWheelMove()*0.05f);

				Console.WriteLine(GetMouseWheelMove());

			    if (camera.zoom > 3.0f) camera.zoom = 3.0f;
			    else if (camera.zoom < 0.1f) camera.zoom = 0.1f;

			    // Camera reset (zoom and rotation)
			    if (IsKeyPressed(.KEY_R))
			    {
			        camera.zoom = 1.0f;
			        camera.rotation = 0.0f;
			    }
			    //----------------------------------------------------------------------------------

			    // Draw
			    //----------------------------------------------------------------------------------
			    BeginDrawing();

			        ClearBackground(.RAYWHITE);
					Console.WriteLine(camera.offset.ToString());
					Console.WriteLine(camera.target.ToString());
					Console.WriteLine(camera.rotation);
					Console.WriteLine(camera.zoom);
			        BeginMode2D(camera);

			            DrawRectangle(-6000, 320, 13000, 8000, .DARKGRAY);

			            for (int i = 0; i < MAX_BUILDINGS; i++)
						{
							DrawRectangle((int)buildings[i].x, (int)buildings[i].y, (int)buildings[i].width, (int)buildings[i].height, buildColors[i]);
						}

			            DrawRectangleRec(player, .RED);

			            DrawLine((int)camera.target.x, -screenHeight*10, (int)camera.target.x, screenHeight*10, .GREEN);
			            DrawLine(-screenWidth*10, (int)camera.target.y, screenWidth*10, (int)camera.target.y, .GREEN);

			        EndMode2D();

			        DrawText("SCREEN AREA", 640, 10, 20, .RED);

			        DrawRectangle(0, 0, screenWidth, 5, .RED);
			        DrawRectangle(0, 5, 5, screenHeight - 10, .RED);
			        DrawRectangle(screenWidth - 5, 5, 5, screenHeight - 10, .RED);
			        DrawRectangle(0, screenHeight - 5, screenWidth, 5, .RED);

			        DrawRectangle( 10, 10, 250, 113, Fade(.SKYBLUE, 0.5f));
			        DrawRectangleLines( 10, 10, 250, 113, .BLUE);

			        DrawText("Free 2d camera controls:", 20, 20, 10, .BLACK);
			        DrawText("- Right/Left to move Offset", 40, 40, 10, .DARKGRAY);
			        DrawText("- Mouse Wheel to Zoom in-out", 40, 60, 10, .DARKGRAY);
			        DrawText("- A / S to Rotate", 40, 80, 10, .DARKGRAY);
			        DrawText("- R to reset Zoom and Rotation", 40, 100, 10, .DARKGRAY);

			    EndDrawing();


				//Console.WriteLine(buildings[50].width);
			    //----------------------------------------------------------------------------------
			}

			// De-Initialization
			//--------------------------------------------------------------------------------------
			CloseWindow();        // Close window and OpenGL context
			//--------------------------------------------------------------------------------------

		}
	}
}

it compiles fine, and the draw calls outside the BeginMode2D() block go through:
image

So, after some digging around with gdb, I think I found the issue - structs such as the Camera2D, or Vector2 get really messed up when they go through. Inspecting the camera struct right before
the BeginMode2D(), this is what gdb says is in it:
{<System::ValueType$part> = {<No data fields>}, offset = {<System::ValueType$part> = {<No data fields>}, x = 400, y = 225}, target = {<System::ValueType$part> = {<No data fields>}, x = 420, y = 300}, rotation = 0, zoom = 1}
and, if I inspect the struct right after its been passed across to a raylib function, here's whats in it now:
{offset = {x = 1.14273087e-40, y = 0}, target = {x = 1.56384909e-42, y = 0}, rotation = 1.56384909e-42, zoom = 0}
So, yeah. Also, one last thing I noticed was that when using the GetMouseWheelMove() function, an upwards scroll returned one, as it should, but when scrolling down it returned 4294967295, which just so happens to be the largest possible value for uint32, meaning it returns an unsigned integer despite being marked as signed, making a scroll down snap the zoom value to 3, because of the check.

There's a good chance these bugs are in beef, or raylib in linux has issues with interop(natively compiling the original examples has no issues), but since I experienced these issues here, I've decided to put them here as well.

And.. Good news! I figured out why the zoom wasn't working! It was because when specifying int, Beef makes it the native size - 64 bits, while the C library is using 32 bit integers. so, using 32 bit integers solved the issue.

You can submit pull request if you want

I will, but I'll do it after I can get the camera to work.

Turns out the bug is in beef. Made an issue @beefytech/Beef#267