Giter Site home page Giter Site logo

Comments (9)

JupiterRider avatar JupiterRider commented on June 23, 2024 2

Since .NET 6 we have the static class NativeMemory:
https://learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.nativememory?view=net-6.0

NativeMemory.AllocZeroed allocates zeroed memory on the heap (like calloc in C does).

Here is an example:

using System.Numerics;
using System.Runtime.InteropServices;
using Raylib_cs;

Raylib.InitWindow(800, 450, "Test");

var mesh = new Mesh() { triangleCount = 1, vertexCount = 3 };

Span<float> vertices, normals, texcoords;

unsafe
{
    mesh.vertices = (float*)NativeMemory.AllocZeroed(9, sizeof(float));
    mesh.normals = (float*)NativeMemory.AllocZeroed(9, sizeof(float));
    mesh.texcoords = (float*)NativeMemory.AllocZeroed(6, sizeof(float));

    vertices = new Span<float>(mesh.vertices, 9);
    normals = new Span<float>(mesh.normals, 9);
    texcoords = new Span<float>(mesh.texcoords, 6);
}

vertices[3] = 1;
vertices[5] = 2;
vertices[6] = 2;

normals[1] = 1;
normals[4] = 1;
normals[7] = 1;

texcoords[2] = .5f;
texcoords[3] = 1;
texcoords[4] = 1;

Raylib.UploadMesh(ref mesh, false);
var model = Raylib.LoadModelFromMesh(mesh);

var camera = new Camera3D() { position = new(5, 5, 5), up = new() { Y = 1 }, fovy = 45 };

while (!Raylib.WindowShouldClose())
{
    Raylib.UpdateCamera(ref camera, CameraMode.CAMERA_ORBITAL);

    Raylib.BeginDrawing();

    Raylib.ClearBackground(Color.WHITE);
    Raylib.BeginMode3D(camera);
    Raylib.DrawModel(model, Vector3.Zero, 1, Color.RED);
    Raylib.DrawGrid(10, 1);
    Raylib.EndMode3D();

    Raylib.EndDrawing();
}

Raylib.UnloadModel(model);
Raylib.CloseWindow();

Screenshot_20230804_185820

We don't need to call NativeMemory.Free in the end, because unload Raylib.UnloadModel frees the mesh as well.

from raylib-cs.

nickyMcDonald avatar nickyMcDonald commented on June 23, 2024 1

@ChrisDill, @JupiterRider, would it be possible and sensible to add an syntax suger allocator like this?

/// <summary>C++ style memory allocator</summary>
public static T* New<T>(int count) where T : unmanaged
{
    return (T*)MemAlloc(count * sizeof(T));
}

or this:

/// <summary>C++ style memory allocator</summary>
public static T* New<T>(int count) where T : unmanaged
{
    return (T*)NativeMemory.AllocZeroed((nuint)count, (nuint)sizeof(T));
}

The method name can be changed if its not disirable. This could help with changing:

mesh.vertices = (float*)NativeMemory.AllocZeroed((nuint)(3 * mesh.vertexCount), sizeof(float));

To instead look like this:

mesh.vertices = New<float>(3 * mesh.vertexCount);

from raylib-cs.

nickyMcDonald avatar nickyMcDonald commented on June 23, 2024 1

We could simplify the constructor to:

public Mesh(int triangleCount, int vertexCount)
{
    this.triangleCount = triangleCount;
    this.vertexCount = vertexCount;
}

And have all of our allocations be in seperate extention methods (utils) so we can pick and choose which ones we are going to use when generating custom meshes:

/// <summary>Allocate mesh vertices</summary>
public static void AllocVertices(ref this Mesh mesh)
{
    mesh.vertices = New<float>(3 * mesh.vertexCount);
}

/// <summary>Allocate mesh texcoords</summary>
public static void AllocTexcoords(ref this Mesh mesh)
{
    mesh.texcoords = New<float>(2 * mesh.vertexCount);
}

/// <summary>Allocate mesh colors</summary>
public static void AllocColors(ref this Mesh mesh)
{
    mesh.colors = New<byte>(4 * mesh.vertexCount);
}

/// <summary>Allocate mesh indices</summary>
public static void AllocIndices(ref this Mesh mesh)
{
    mesh.indices = New<ushort>(3 * mesh.triangleCount);
}

All of the accessors can be more utils:

/// <summary>Access mesh vertices</summary>
public static Span<T> VerticesAs<T>(this Mesh mesh) where T : unmanaged
{
    return new(mesh.vertices, 3 * mesh.vertexCount * sizeof(float) / sizeof(T));
}

/// <summary>Access mesh texcoords</summary>
public static Span<T> TexcoordsAs<T>(this Mesh mesh) where T : unmanaged
{
    return new(mesh.texcoords, 2 * mesh.vertexCount * sizeof(float) / sizeof(T));
}

/// <summary>Access mesh colors</summary>
public static Span<T> ColorsAs<T>(this Mesh mesh) where T : unmanaged
{
    return new(mesh.colors, 4 * mesh.vertexCount * sizeof(byte) / sizeof(T));
}

/// <summary>Access mesh indices</summary>
public static Span<T> IndicesAs<T>(this Mesh mesh) where T : unmanaged
{
    return new(mesh.indices, 3 * mesh.triangleCount * sizeof(ushort) / sizeof(T));
}

Example of usage:

using Raylib_cs;
using System.Numerics;

Raylib.InitWindow(1280, 960, "Hello World!");
Raylib.SetTargetFPS(60);

Camera3D camera = new(Vector3.One * 1.5f, Vector3.Zero, Vector3.UnitY, 60f, CameraProjection.CAMERA_PERSPECTIVE);
Mesh tetrahedron = new(4, 4);
tetrahedron.AllocVertices();
tetrahedron.AllocTexcoords();
tetrahedron.AllocColors();
tetrahedron.AllocIndices();
Span<Vector3> vertices = tetrahedron.VerticesAs<Vector3>();
Span<Vector2> texcoords = tetrahedron.TexcoordsAs<Vector2>();
Span<Color> colors = tetrahedron.ColorsAs<Color>();
Span<ushort> indices = tetrahedron.IndicesAs<ushort>();

// Coordinates for a regular tetrahedron (wikipedia)
vertices[0] = new(float.Sqrt(8f / 9f), 0f, -1f / 3f);
vertices[1] = new(-float.Sqrt(2f / 9f), float.Sqrt(2f / 3f), -1f / 3f);
vertices[2] = new(-float.Sqrt(2f / 9f), -float.Sqrt(2f / 3f), -1f / 3f);
vertices[3] = Vector3.UnitZ;

texcoords[0] = Vector2.Zero;
texcoords[1] = Vector2.UnitX;
texcoords[2] = Vector2.UnitY;
texcoords[3] = Vector2.One;

colors[0] = Color.PINK;
colors[1] = Color.LIME;
colors[2] = Color.SKYBLUE;
colors[3] = Color.VIOLET;

indices[0] = 2;
indices[1] = 1;
indices[2] = 0;

indices[3] = 1;
indices[4] = 3;
indices[5] = 0;

indices[6] = 2;
indices[7] = 3;
indices[8] = 1;

indices[9] = 0;
indices[10] = 3;
indices[11] = 2;

float rotationAngle = 0f;
Raylib.UploadMesh(ref tetrahedron, false);
Model model = Raylib.LoadModelFromMesh(tetrahedron);

Image image = Raylib.GenImagePerlinNoise(16, 16, 0, 0, 1000f);
Raylib.ImageBlurGaussian(ref image, 2);
Raylib.ImageColorBrightness(ref image, 100);
Raylib.ImageDither(ref image, 4, 4, 4, 4);
Texture2D texture = Raylib.LoadTextureFromImage(image);
Raylib.UnloadImage(image);

Raylib.SetMaterialTexture(ref model, 0, MaterialMapIndex.MATERIAL_MAP_DIFFUSE, ref texture);

while (!Raylib.WindowShouldClose())
{
    Raylib.UpdateCamera(ref camera, CameraMode.CAMERA_ORBITAL);
    rotationAngle = Raymath.Wrap(rotationAngle += 1f, 0f, 360f);

    Raylib.BeginDrawing();
    Raylib.ClearBackground(Color.BLACK);
    Raylib.BeginMode3D(camera);
    Raylib.DrawModelEx(model, Vector3.Zero, Vector3.UnitX, rotationAngle, Vector3.One, Color.WHITE);
    Raylib.EndMode3D();
    Raylib.EndDrawing();
}
Raylib.UnloadModel(model);
Raylib.UnloadTexture(texture);
Raylib.CloseWindow();

Hello World!

from raylib-cs.

ChrisDill avatar ChrisDill commented on June 23, 2024 1

@JupiterRider @n77y The MeshDemo example has now been added and the utils seem to be working as expected. Plan to experiment more with this and maybe apply the same approach to other resource types in the future.

Thanks for all the help on this issue!

from raylib-cs.

nickyMcDonald avatar nickyMcDonald commented on June 23, 2024

Taking @JupiterRider's idea you could add a constructor that looks something like this:

/// <summary>Generate mesh</summary>
public Mesh(int triangleCount, int vertexCount)
{
    this.triangleCount = triangleCount;
    this.vertexCount = vertexCount;
    vertices = (float*)NativeMemory.AllocZeroed((nuint)(3 * this.vertexCount), sizeof(float));
}

Also add extention method's to utils:

/// <summary>Access mesh triangles</summary>
public static Span<T> TrianglesAs<T>(this Mesh mesh) where T : unmanaged
{
    return new(mesh.vertices, 3 * mesh.vertexCount * sizeof(float) / sizeof(T));
}

Utilizing these would look something like this:

using Raylib_cs;
using System.Numerics;

Raylib.InitWindow(1280, 960, "Triangle");
Raylib.SetTargetFPS(60);

Camera3D camera = new(Vector3.One, Vector3.Zero, Vector3.UnitY, 90f, CameraProjection.CAMERA_PERSPECTIVE);
Mesh mesh = new(1, 3);
Span<Vector3> vertices = mesh.TrianglesAs<Vector3>();
vertices[0] = Vector3.UnitZ;
vertices[1] = Vector3.UnitX;
vertices[2] = Vector3.Zero;
Raylib.UploadMesh(ref mesh, false);
Model model = Raylib.LoadModelFromMesh(mesh);

while (!Raylib.WindowShouldClose())
{
    Raylib.UpdateCamera(ref camera, CameraMode.CAMERA_ORBITAL);
    Raylib.BeginDrawing();
    Raylib.ClearBackground(Color.BLACK);
    Raylib.BeginMode3D(camera);
    Raylib.DrawModel(model, Vector3.Zero, 1f, Color.PINK);
    Raylib.DrawGrid(2, 1);
    Raylib.EndMode3D();
    Raylib.EndDrawing();
}
Raylib.UnloadModel(model);
Raylib.CloseWindow();

from raylib-cs.

ChrisDill avatar ChrisDill commented on June 23, 2024

@JupiterRider Unsure if it is better to use MemAlloc, MemFree via Raylib instead. Raylib can be recompiled to change how allocation works internally so using the built in versions can make sure alloc/free calls work with each other correctly.

@n77y Interesting idea! How could this be applied to other mesh fields?

from raylib-cs.

JupiterRider avatar JupiterRider commented on June 23, 2024

@ChrisDill Doesn't matter. They both use calloc in stdlib.h anyways:
https://github.com/raysan5/raylib/blob/master/src/utils.c#L163
https://github.com/raysan5/raylib/blob/master/src/raylib.h#L124

https://source.dot.net/#System.Private.CoreLib/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NativeMemory.Unix.cs,149
https://source.dot.net/#System.Private.CoreLib/src/libraries/Common/src/Interop/Unix/System.Native/Interop.MemAlloc.cs,20
https://github.com/dotnet/runtime/blob/main/src/native/libs/System.Native/pal_memory.c#L63

I don't think its a good Idea for maintainability compiling our own version of raylib or writing to many layers of abstraction.

Raylib-cs should better be a binding only. For everything beyond we could create an additional project called Raylib-cs.Extras or something.

from raylib-cs.

JupiterRider avatar JupiterRider commented on June 23, 2024

Nice work @n77y!
Now make a pull request for that and the pear is peeled :D

U can also apply an example for that here:
https://github.com/ChrisDill/Raylib-cs-Examples

Side notice:
NativeMemory requires at least .Net 6.

from raylib-cs.

ChrisDill avatar ChrisDill commented on June 23, 2024

@n77y Trying out the idea further using your example and I changed my mind on it needing to be separate from the Mesh struct. Updated the pr with a few more suggestions. Once done I will merge it in and add your example for it.

@n77y @JupiterRider Also note that examples have been merged back into the main repo so further development on examples will be done here.

from raylib-cs.

Related Issues (20)

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.