Giter Site home page Giter Site logo

fosterframework / foster Goto Github PK

View Code? Open in Web Editor NEW
347.0 10.0 29.0 57.16 MB

A small C# game framework

License: MIT License

C# 69.00% CMake 0.73% C 30.27%
2d cross-platform csharp dotnet game-development game-engine game-framework gamedev graphics

foster's Introduction

Foster logo

Foster

Foster is a small cross-platform 2D game framework in C#.

โ˜… very work in progress! likely to have frequent, breaking changes! please use at your own risk! โ˜…

To use the framework either

  • add a refence to the NuGet package,
  • or clone this repository and add a reference to Foster/Framework/Foster.Framework.csproj.

There is a Samples repo which contains various demos and examples that can help you get started.

Check out Discussons or Discord to get involved.

Dependencies

Platform Library

Rendering

  • Implemented in OpenGL for Linux/Mac/Windows and D3D11 for Windows.
  • Separate Shaders are required depending on which rendering API you're targetting.
  • Planning to replace the rendering implementation with SDL3 GPU when it is complete.

Notes

  • Taken a lot of inspiration from other Frameworks and APIs, namely FNA.
  • This is the second iteration of this library. The first can be found here.
  • Contributions are welcome! However, anything that adds external dependencies or complicates the build process will not be accepted.

foster's People

Contributors

amerkoleci avatar andymandias avatar cerealpxl avatar codecat avatar krelyshy avatar kuujoo avatar luihabl avatar maddythorson avatar mimoja avatar mrbrixican avatar noelfb avatar photex avatar psygamer avatar saplonily avatar tapir2342 avatar techiesplash avatar theofficialgman avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

foster's Issues

QOI format support

The Quite OK Image Format is pretty nifty from a content pipeline perspective (even GameMaker uses it internally), and with such a complete reference c implementation it should be trivial to implement. Ideally it should attempt to intercept before/after stb_load_from_memory().

Content / UserStorage APIs

Consoles often require very specific mounting for file access and save data. I think there should be 2 utility classes that can be used to simplify this. Obviously if the user doesn't care about non-desktop portability they can just ignore these:

The Content class lets the user enumerate and read files from a Content directory. I think the App should create a default one. On Desktop platforms this would find files beside the .exe location, for example new Content("Assets") would work over files in the Assets directory adjacent to the YourGame.exe.

public class Content
{
	public Content(string directory);

	public IEnumerator<string> EnumerateFiles(string relativePath, string searchPattern, bool recursive);
	public IEnumerator<string> EnumerateDirectories(string relativePath, string searchPattern, bool recursive);

	public bool FileExists(string relativePath);
	public bool DirectoryExists(string relativePath);
	public Stream OpenRead(string relativePath);
}

User Storage is simpler and should be a singleton... it just reads / writes data to user files and can see if they exist. On Desktop this would use App.UserPath. I don't think there's any need to enumerate files here.

public class UserStorage
{
	public static bool Exists(string path);
	public static byte[] Read(string path);
	public static void Write(string path, byte[] data);
}

Clarify Premultiplied Alpha

One of the biggest issues people immediately run into is rendering with/without premultiplied Alpha. By default the Sprite Batcher uses Premultiplied alpha, and the Color struct multiply operator does the same. I think these assumptions are correct and should be the default, but it needs to be more clear that any images loaded that are not already premultiplied must do so.

I'm not sure if this is just a documentation / FAQ issue, or something that should change in the actual API

Finalize/Dispose patterns

We probably want to standardize/adjust the way we handle unmanaged resource lifecycles.

.NET makes no guarantee that finalizers will actually run on application exit.

Currently, the following classes implement the dispose/finalize pattern: Mesh, Shader, Target, Texture, Batcher, Font, Image

Mesh, Shader, Target, Texture are specifically graphics resources, which we ideally want to ensure get disposed before the application exits. Monogame/FNA track them with weak references and dispose them on application exit. Additionally, FNA will keep track when a finalizer is hit during run and delay release calls until it can guarantee it will be called on the main thread during present.

Batcher, Font, and Image aren't as significant since they just point to blocks of memory, which should be freed automatically on application termination anyways.

We should also look into using GC.SuppressFinalize where possible to further reduce true object lifetime.

Drawing transparent textures

I seem to be unable to draw transparent textures properly. The transparency byte is 11 according to Aseprite, but it shows as almost opaque:

image

From my XNA days I remember there was some kind of "premultiplied alpha" setting that can be used for rendering to fix something similar - does Foster have anything like that that I'm missing?

App.ContentScale always returns (2,2)

I imagine this is probably meant to return a value depending on the system/monitor.

I'm writing an ImGui.NET renderer for Foster and I imagine this is necessary to accurately display on a Mac (I do not own a Mac so I can't verify this).

libFosterPlatform.dylib not built for Arm on macOS

Hey, just wanted to report that I tried to run one of the samples (TinyLink) on macOS with M1 and I got an error where it looks like the platform lib is not built for arm. Not sure if the lib is meant to be built for that platform as well, but just wanted to point out.

The error that I got was:

Unhandled exception. System.DllNotFoundException: Unable to load shared library 'FosterPlatform' or one of its dependencies. In order to help diagnose loading problems, consider setting the DYLD_PRINT_LIBRARIES environment variable: 
(...)
dlopen([path]/Foster/Samples/TinyLink/bin/Debug/net7.0/libFosterPlatform.dylib, 0x0001): tried:
'[path]/Foster/Samples/TinyLink/bin/Debug/net7.0/libFosterPlatform.dylib' (mach-o file, but is an incompatible architecture (have 'x86_64', need 'arm64')), 
'[path]/Foster/Samples/TinyLink/bin/Debug/net7.0/libFosterPlatform.dylib' (no such file), 
'[path]/Foster/Samples/TinyLink/bin/Debug/net7.0/libFosterPlatform.dylib' (mach-o file, but is an incompatible architecture (have 'x86_64', need 'arm64'))
(...)

As per this answer, maybe there is an easy solution by building a universal binary just setting CMAKE_OSX_ARCHITECTURES=arm64;x86_64 on the cmake file.

Investigate Action to build native Platform libs

Right now I manually build the native Platform libs for Linux/Windows (and in theory MacOS but so far I have not), and then they're included in the repo directly. I like having them in the repo because it doesn't require downloading, building, or copying library files around when someone freshly clones the project.

However, this does mean that occasionally the compiled libraries are outdated depending on which platforms I happen to rebuild. Ideally there would be some way to automatically rebuild the native Platform libs for Linux/Windows/Mac whenever they actually change. The downside is that it feels like you could end up with double-commits for any changes (ex. commit changes to native API, action runs and rebuilds libs and then commits those?).

So I'm not sure if there's a suitable answer that both 1) keeps the libraries inside the repo for ease-of-use and 2) doesn't get overly complicated with lots of double-commits and stuff.

[macOS intel x64]Sample project TinyLink crashed with an Assert : `Application is already running`

OS: macOS 13.4 intel x64
I tried two samples (Froggymark, TinyLink), all crashed at the same assertion Application is already running
------ error:
Process terminated. Assertion failed.
Application is already running
at Foster.Framework.App.Run(String applicationName, Int32 width, Int32 height, Boolean fullscreen) in /Users/test1/Downloads/Foster-main/Framework/App.cs:line 224
at TinyLink.Program.Main() in /Users/test1/Downloads/Foster-main/Samples/TinyLink/Source/Manager.cs:line 12
zsh: abort

Get Display Size to determine if Window can fit

Without knowing the Display Size there's no way to tell if you're requesting a Window size that is too big for the display. For example, setting the Window to 1920x1080 on a display of the same size can make the window handle to basically be unusable.

Consider adding editorconfig

This will make contributions follow your code preference, you can grab one from dotnet runtime for example.

Thanks!

Dynamic Sprite Font

I think it could be useful to dynamically render more characters as requested. In languages with a lot of characters (Chinese, Japanese, etc) it can make more sense to render characters as needed, instead of having to determine everything upfront.

This would probably work by creating some kind of queue to render characters off the main thread as requested, and then updating the SpriteFont's Texture each frame if there are more characters that have finished being rendered. If you draw a character that hasn't been rendered yet, it could add it to the queue and then just show nothing until a future frame. If you want to avoid a few frames of text "pop in" there could be some way to request characters ahead of time.

I'm not sure if this should just be part of SpriteFont, or a different DynamicSpriteFont class entirely. It needs to be more complicated (ex. rendering characters off the main thread, updating the main texture on the main thread each frame, etc).

Alternatively, if this feels overly complex for the framework, this could just be entirely left up to the end user. SpriteFont already has a way to add user-created characters.


I'm also potentially interested in adding MSDF fonts, which I have working nicely in some non-Foster projects. But they require including a C++ library, and don't work with a lot of fonts without modification.

Mesh changes

Hey, awesome work on this library! When I saw that you recreated it, it was a very nice surprise to start the weekend.

However, I noticed some differences from the original implementation:

  • First, mesh vertex/index buffer updates use glBufferData instead of glBufferSubData when possible. This has a pretty significant performance penalty (2x slower in drawing 500k textures compared to the original library).
  • In line with this, the original library provided a way to partially update buffers, an extremely useful piece of functionality that allows for some niche optimizations.
  • Finally, I saw that the instance component of meshes was omitted. I haven't used instanced rendering yet, but it does feel like a good feature to have.

If these omissions were to make the initial c implementation easier and is something that you already intended to refactor at some point, please disregard this issue.

Thanks once again for working on this great library!

Module shutdown order

Currently, we shutdown modules in the same order we register them. This may not be ideal in cases where a module may depend on modules registered before it in its shutdown method (one notable example is a game module cleaning up audio resources dependent on an earlier registered audio module). To support such scenarios, it may be best to shutdown modules in reverse order.

Care must be taken for the unlikely edge case of modules being registered during shutdown (perhaps this should be disallowed entirely).

Add `Batcher.ImageStretch`

I need an ImageStretch method to render images stretched. So far I've been using the following extension method:

public static void ImageStretched(this Batcher batch, in Subtexture subtex, in Rect rect, Color color)
{
	batch.SetTexture(subtex.Texture);
	batch.Quad(
		rect.TopLeft, rect.TopRight, rect.BottomRight, rect.BottomLeft,
		subtex.TexCoords0, subtex.TexCoords1, subtex.TexCoords2, subtex.TexCoords3,
		color
	);
}

The following could be a good starting point for a PR, but decided not to make a PR right away because I wasn't sure which overloads the method should have.

public void ImageStretch(in Subtexture subtex, in Rect rect, Color color)
{
	SetTexture(subtex.Texture);
	Quad(
		rect.TopLeft, rect.TopRight, rect.BottomRight, rect.BottomLeft,
		subtex.TexCoords0, subtex.TexCoords1, subtex.TexCoords2, subtex.TexCoords3,
		color);
}

public void ImageStretch(in Subtexture subtex, in Rect rect, Color c0, Color c1, Color c2, Color c3)
{
	SetTexture(subtex.Texture);
	Quad(
		rect.TopLeft, rect.TopRight, rect.BottomRight, rect.BottomLeft,
		subtex.TexCoords0, subtex.TexCoords1, subtex.TexCoords2, subtex.TexCoords3,
		c0, c1, c2, c3);
}

Room for more render performance

There is room for much more performance in respect to degenerate and standard cases where Graphics.Submit must be called frequently:

  • Drawing different textures in alternating pattern
  • Drawing many models/meshes

The main detractor from performance in those scenarios is redundant calls to OpenGL methods.

  • FosterDraw_OpenGL calls a lot of methods to set values that may already be set correctly (glUseProgram, glBindFramebuffer, glTexParameteri, glEnable, etc).
  • Unfortunately OpenGL drivers don't make a strong effort (at least on my machine) to prevent redundant calls from having nontrivial overhead.

Luckily, most redundant calls are pretty simple to catch, as we can just keep track of what we set/used previously and ignore the call if the same parameters will be used. This method was used in the original Foster to great effect.

I have personally tested this and received a 4x speedup in the Froggymark sample (using built in Batcher) when drawing alternating textures (causing a draw call each). I (very roughly) implemented the following adjustments:

  • glUseProgram calls in FosterDraw_OpenGL and FosterShaderSetUniform_OpenGL are ignored if the shader has already been set
  • glTexParameteri calls are ignored if the texture has already been set to use those parameters
  • ignore calls relating to the following global state if they are using previous values:
    • frame buffer
    • blend state
    • depth state
    • cull state
    • viewport
    • scissor
  • removed glBindVertexArray(0) from end and avoid redundantly calling fgl.glBindVertexArray(mesh->id)

There are a few more possible tweaks, but they will require more involved solutions:

  • avoid glActiveTexture, glBindTexture, and possibly glUniform1iv calls if textures/slots haven't changed
  • avoid setting uniforms if their value is unchanged from last set (this may not be worth it, needs testing)

Windows native library builds to the wrong directory

The CMake project has

set_target_properties(FosterPlatform
	PROPERTIES
	ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/libs/${FosterTarget}"
	LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/libs/${FosterTarget}"
	RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/libs/${FosterTarget}"
)

And this works for Linux/macOS, however on Windows the result project appends a /Release or /Debug to the output path, which isn't what Framework .csproj looks for. Is there a way to update this in CMake to not append configuration to the end on Windows?

Alternatively could make the Framework .csproj just copy from the Release subfolder instead.

Refactor rendering to use SDL3 GPU

This is more of just a long term intention of replacing the current custom rendering API implementations with SDL3's GPU api, once it is ready.

This will likely require breaking changes to the C# Shader API as I believe the plan is for SDL3 to have a custom shader language.

Move samples to their own repo

This shouldn't take much work but just marking this down to state my intention to create a new repo and move the Samples out of here.

Some considerations:

  • Will probably use the NuGet package in the samples to make them easy to test
  • However, it would be nice to be able to easily swap to a local copy of Foster to test the samples with any changes. Maybe conditional references or something? Separate .sln? Not sure.

Text word wrapping

I don't see an API for drawing word wrapped text. This might be something that can be easily achieved externally, but perhaps would be nice to have built-in to Foster.

Investigate NuGet Package?

I haven't used NuGet before but for a lot of people it's obviously the nicest ways to use C# projects. I've been meaning to look into how to implement/set this up but it hasn't been a priority yet. Making an issue for it to remind myself to look into it in the near future.

Nintendo and Sony Detection wrong (uses vendor and product instead of just vendor)

Vendor detection is bugged due to combining vendor and product in order to determine the current vendor.

Only vendor should be used
eg (official USB vendor id)
Sony 054c
Nintendo 057e
Xbox 045e and 0738

those get translated in SDL GUID and the two characters sets get swapped

this bug causes many controllers to be detected as the wrong type (eg: Nintendo Switch Combined Joy-Cons with Joycond on Linux since they have a GUID of Joystick GUID: 06004cfc7e0500000820000000000000 end up returning Gamepads.Xbox ).

public Gamepads Gamepad
{
get
{
var vendor = ((Vendor >> 8) & 0x00FF) | ((Vendor << 8) & 0xFF00);
var product = ((Product >> 8) & 0x00FF) | ((Product << 8) & 0xFF00);
var id = (vendor << 16) | product;
if (id == 0x4c05c405 || id == 0x4c05cc09)
return Gamepads.DualShock4;
if (id == 0x4c05e60c)
return Gamepads.DualSense;
if (id == 0x7e050920 || id == 0x7e053003)
return Gamepads.Nintendo;
return Gamepads.Xbox;
}
}

Please change this to only use the vendor and not the vendor and product id.
also, the entire purpose of the SDL2 gamecontrollerdb mapping system is to abstract that away.

Upgrade to .NET 8.0

Going to wait for the official launch, but when it does release this month I'm going to update to .NET 8.0 as it is a long-term support release.

Shader Material Concept for Batcher

This is mostly intended for the Batcher, but right now Pushing/Popping Shaders is a bit weird if you intend to modify parameters, due to the actual draw calls being deferred to later.

For example, in this scenario both rectangles are drawn with the 2nd parameter assignment of 25.0f:

custom["Wavy"].Set(10.0f);
batch.PushShader(custom);
batch.Rect(new Rect(0, 0, 32, 32), Color.Red);
batch.Pop();

// ...

custom["Wavy"].Set(25.0f);
batch.PushShader(custom);
batch.Rect(new Rect(32, 32, 32, 32), Color.Red);
batch.Pop();

// ...
batch.Render();

I don't think this is very intuitive, and have run into it multiple times in my own use case. Thus, I think the idea of a "Material" which wraps a Shader & Parameter values might make a lot of sense. When the Material is actually used it applies any modified parameters to the current Shader.

I see a few ways for how this could be implemented:

  • Specific to the Batcher, and when you push a Shader it copies all the parameters into the batch state so that when it draws it assigns those values to the Shader before drawing. This is the most automatic approach but is kind of hidden. This however has concerns around GC/Allocations which I want to avoid.
  • Class-based approach, where the user creates a Material class and then sets values on it, and Pushes/Pops that to the Batcher. I find this option a little weird because it has the same problem as the example above - you could set some Material values, draw some stuff, then set other values, and draw some more, and it wouldn't be obvious the last Material values are the ones that will be used.

Audio

Just wanted to know whether audio support is a planned addition to this library. Audio is arguably a necessary component of most games, and I think it's something that's generally expected of most game frameworks. If you are interested, I have a feature writeup:


When it comes to cross platform game audio libraries/wrappers, the big names are essentially OpenAL(Soft), SDL_Mixer, SoLoud, FMOD, Wwise, and BASS. The first two are pretty dated, and the latter three are commercially licensed, which I don't think fits the theme of this repository. SoLoud is great, but I had a few concerns (see note 1).

Thus, I suggest a relatively thin wrapper around cute_sound. I like it for the following reasons:

  • hooks into sdl for non standard platforms
  • single header (technically two with ogg vorbis), very lightweight
  • has instanced audio (which allows control after an instance has been played)
  • has the ability to get/set current sample position (very important for rhythm games, haha)
  • simple music fade support

The following implementation details would be pretty important

  • separate namespace (~Foster.Framework.Audio) and optionally enabled (via App.Run), to avoid conflicts if a user decides to use another audio library (see note 2)

I know you used cute_sound with blah, so your opinion would obviously mean more than these superficial observations.

If this is something that is interesting to you, I'd be more than happy to take an initial crack at it.

note 1: SoLoud is an extremely honorable mention. It's pretty weird to build, but I have managed it. It's also a very fully featured library with effects, buses, and 3d spatialization, which may or may not be overkill. However, the effect on binary size would probably be considerable (it's actually pretty light < 1MB, forgot I published more than just the binary as an artifact) and it would most definitely constitute a dependency.

note 2: A one size fits all approach will simply not meet the complex needs of all games. Similar to animation, sprite, and ECS implementations, the correct audio implementation largely depends on the use case. If we cover 90-99% of simple 2D use cases with a lightweight abstraction and don't get in a user's way if they decide to use something different, that would be good enough.

Fix edge case with expanding Mesh buffers at an offset

In OpenGL when Mesh buffers are expanded they clear the data. However, the API is implemented in such a way that this is not obvious as it's a single method that both uploads sub areas and expands the buffer. This should probably be split into two methods or otherwise somehow clarified.

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.