Skip to content

v2.0.0-rc-001

Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 02 Jul 05:35
· 64 commits to main since this release

Added

  • Core: backend-neutral Color type — a byte RGBA struct (Mibo.Color) with toVector3/toVector4 conversions and named constants (White, Black, Red, etc.). Shared light/camera definitions use this instead of a backend-specific Color. Each backend provides inlineable op_Implicit conversions to/from its native color type.
  • Core: shared 3D light definitionsAmbientLight3D, DirectionalLight3D, PointLight3D, and SpotLight3D (with their builder modules) now live in Mibo.Core using Mibo.Color + System.Numerics.Vector3. Both backends previously carried byte-for-byte identical copies; now there is one implementation.
  • Core: shared Animation3DState playback clock — the pure state machine (create, play, blendTo, update, etc.) and Animation3DClipsInfo (clip names + keyframe counts) now live in Mibo.Core. The clock operates on ints/floats only — no backend types. Each backend builds Animation3DClipsInfo at load time from its native clip data and delegates playback to the Core functions.
  • Core: mouse captureIInput.SetMouseCapture(MouseCapture) lets games request pointer-locked, unlimited-rotation mouse input via a backend-neutral contract. Raylib uses native DisableCursor/EnableCursor; MonoGame re-centers the mouse inside its own Poll() so no external GameComponent is needed.

Changed

  • Core — Breaking: AmbientLight3D.Color, DirectionalLight3D.Color, PointLight3D.Color, and SpotLight3D.Color are now Mibo.Color (were Raylib_cs.Color / Microsoft.Xna.Framework.Color). Use Mibo.Color.White etc. when constructing lights, or rely on the implicit conversion from your backend's native color. Light Direction/Position fields are now System.Numerics.Vector3 (were native on the MonoGame backend).

  • Core — Breaking: Animation3DClips gains a ClipsInfo: Animation3DClipsInfo field. The Animation3DState playback functions (create/play/blendTo/update/etc.) on both backends now delegate to the Core implementation. The public API is unchanged, but the struct field layout of the backend-specific Animation3DState types is internal — construct states via the module functions.

  • Core: Animation3DState.update blend target wrapping now respects Loop = false consistently across both backends (previously raylib always wrapped the blend target regardless of the loop flag).

  • MonoGame: device-level config callbackMonoGameProgram wraps a Core Program and carries (Game * GraphicsDeviceManager -> unit) callbacks (ofProgram + withConfig) that MiboGame runs in its constructor, after the Core GameConfig but before Initialize / GraphicsDevice creation. Use this for GraphicsProfile, vsync (SynchronizeWithVerticalRetrace), IsFullScreen, Window.AllowUserResizing, Content.RootDirectory, and other properties that need direct device-manager access. MiboGame now takes a MonoGameProgram instead of a raw Program. MonoGameProgram.withInputMapper now operates on the wrapper.

  • MonoGame: host & programMiboGame(program) is the MonoGame game host (subclasses Microsoft.Xna.Framework.Game, drives the shared ElmishLoop). MonoGameProgram.withInputMapper registers the MonoGame-backed input mapper (and calls withInput). MonoGameGameContext accessors (getGraphicsDevice/getContentManager/getGame) retrieve MonoGame handles from the Core GameContext service registry. MonoGame IAssets exposes the typed loaders (Texture/Font/Sound/Model/Effect/ModelAnimations/AnimatedMesh) and extends the portable IAssetCache.

  • Core: IAssetCache — backend-neutral asset cache interface (Get/Create/GetOrCreate/Clear/Dispose) that portable code depends on; the backend IAssets extends it.

  • Docs: migration guidedocs/migration-from-monogame.md, a before/after guide for moving from the original monolithic Mibo package to Mibo.Core + Mibo.MonoGame (program setup, GameContext, input, assets, the renamed 2D/3D rendering stacks, animation, cameras, the content pipeline, and a Raylib-backend appendix).

  • Docs: shader uniform referencedocs/shader-uniforms.md lists the exact uniform names the 3D beginEffect/endEffect scope uploads (matrices, lights, shadows, material, bones, time), the drawMeshEffect and drawImmediate contracts, and the 2D lit-sprite layout, so a custom shader can declare just what it consumes. Worked HLSL + GLSL examples included.

  • MonoGame 3D: per-group custom shadingDraw3D.beginEffect/endEffect shade the draws between them with a user-supplied Effect instead of PBR. The effect inherits the scene's camera, lights, shadows, material, bones, and a time clock by declaring the matching uniform names; uniforms it doesn't declare are skipped. Scopes don't persist across cameras. Lets you render toon/water/vignette alongside the default PBR scene.

  • MonoGame 3D: extensible pipelineForwardPipelineBase (abstract; owns the gather + frame orchestration + a virtual Shade) with ForwardPipeline as the thin PBR subclass. Override Shade to plug a different shading strategy; it receives the per-frame scene (lights, bones, shadow output, time). Register the same way: Renderer3D.create (ForwardPipeline()) view.

  • MonoGame 3D: drawImmediate receives a SceneContext — the raw GraphicsDevice plus the gathered scene (camera, lights, shadows, time). For fully-custom draws (water/refraction, screen-space, multi-pass) that want device control without re-gathering the scene.

  • Raylib 3D: per-group custom shadingDraw3D.beginEffect/endEffect shade the draws between them with a user-supplied Shader instead of PBR. The shader inherits the scene's camera, lights, shadows, material, bones, and a time clock by declaring the matching uniform names; uniforms it doesn't declare are skipped. Scopes don't persist across cameras. Lets you render toon/water/vignette alongside the default PBR scene.- Raylib 3D: extensible pipelineForwardPipelineBase (abstract; owns the gather + frame orchestration + a virtual Shade) with ForwardPbrPipeline as the thin PBR subclass. Override Shade to plug a different shading strategy; it receives the per-frame scene (lights, shadow output, time). Register the same way: Renderer3D.create (ForwardPbrPipeline()) view.

  • Raylib 3D: drawImmediate receives a SceneContext — the gathered scene (camera, view/projection matrices, lights, shadows, time). For fully-custom draws (water/refraction, screen-space, multi-pass) that want the scene data without re-gathering it. Mirrors the MonoGame SceneContext minus the device field (raylib uses global device state).

  • Raylib 3D: time uniform in the scene-data contract. Shaders opt into animation (ripples, flowing textures) by declaring time. IRenderPipeline3D.Execute gains a GameTime argument.

  • MonoGame 3D: time uniform in the scene-data contract. Shaders opt into animation (ripples, flowing textures) by declaring time. IRenderPipeline3D.Execute gains a GameTime argument (MonoGame backend only).

  • MonoGame 3D: PBR shading — models, animated models, primitives, and instanced geometry route through a Cook-Torrance PBR effect (ambient + 1 directional + up to 8 point + up to 4 spot lights, emission, opacity, tiling, optional normal maps). Imported models keep their authored look; a MaterialKey short-circuit skips re-uploading unchanged materials. Per-draw normalMatrix; instanced normals transform by the per-instance world matrix; the instanced shader negates the directional light direction.

  • MonoGame 3D: shadows — directional, point, and spot lights that set CastsShadows render depth into an R32F atlas (sampled with 3×3 PCF; OpenGL uses RasterizerState polygon-offset + a shadowTexelSize uniform since SM3.0 has no dFdx/textureSize). Per-light frustum culling skips casters outside each light's view (accounting for transform scale). Static models, primitives, instanced geometry, and animated models all cast; animated models render depth-only with matching bone semantics (not frustum-culled — a bare mesh part has no reachable bounds). A per-light shadow index replaces the per-fragment caster scan. Configure via ShadowAtlasConfig/ShadowBiasConfig; EnableShadows/DisableShadows/SetShadowOrigin are honored. Only the first shadow-casting directional light is registered (the shader samples slot 0).

  • MonoGame 3D: skeletal animationAnimatedModel plays/blends animation clips loaded at runtime from raw model files (.glb/.gltf/.fbx/…) via AssimpNetter (the content pipeline discards animation data; loading both ModelAnimations + AnimatedMesh for the same path parses once). Draw3D.drawAnimatedModel computes the bone palette and routes through GPU skinning; the caller never handles a Matrix[]. Cross-fade blend targets respect Loop = false. Load via IAssets.ModelAnimations/AnimatedMesh (filesystem paths — copy the raw model to your output directory). Adds the AssimpNetter dependency.

  • MonoGame 3D: instancingDraw3D.drawInstanced renders bulk geometry via hardware instancing (dual vertex stream) through the PBR Instanced technique.

  • MonoGame 3D: billboards + linesDraw3D.drawBillboard/drawBillboardBatch/drawLine3D (billboard UVs normalized [0,1]; line staging pooled).

  • MonoGame 3D coreCamera3D (perspective/orthographic, orbit, screen-point-to-ray), Culling, Primitive3D (unit cube/sphere/cylinder/plane/torus/cone meshes), Material3D, the Draw3D DSL, and a pluggable IRenderPipeline3D. EndCamera resets camera state so draws after it don't use stale matrices.

  • MonoGame: 2D rendering stack — sprites, text, shapes, cameras, custom shaders, render targets, 2D lighting (point/directional/occluders), particles, post-processing, and sprite-sheet animation. Parity with the Raylib Graphics2D surface. Includes: mouse back/forward buttons on the MouseDelta stream; Renderer2D.Draw always closes batches and releases RTs even when a frame throws; per-instance lit-sprite quad buffer; centroid-radiating rounded-rect fill; AddTriangleFan closeLoop for open fans; LightContext2D.Dispose respects caller effect ownership; float-space particle removal; allocation-free occluder upload; multi-pass post-process; RenderTargetPool idle-target cap (window-resize leak).

  • Core: backend-neutral inputKeyCode/MouseButtonCode/GamepadButtonCode/GestureKind + IInput/IInputMapper<'Action> live in Mibo.Core, so input bindings are portable across backends.

  • Core: Cmd.Msg — a zero-allocation Cmd case for Cmd.ofMsg (no delegate wrap).

  • Core: Program builder gains withServiceRegistration for backend-specific service registration.

  • Core: Mibo.Core project — backend-agnostic home for Cmd/Sub/GameTime/Program/GameContext/layout/HeadlessProgram/ElmishLoop. The Raylib backend now references it; namespaces are unchanged. Includes Mibo.Core.Tests.

  • Raylib: RaylibProgram.withInputMapper — the raylib-specific input-mapper builder (decoupled from the shared Core Program).

  • Raylib / MonoGame 3D: Draw3D.modelWith and modelWithPerMesh draw a model with your own Material3D — the whole model, or per sub-mesh — instead of the material baked into the file. One call covers any override shape, so you don't reach for a different API per property. MonoGame also gains animatedModelWith / animatedModelWithPerMesh for skinned models.

  • Docs: multi-backend documentation. The site now covers the Core, Raylib, and MonoGame packages: the rendering, shaders, assets, input, and lighting pages show both backends side-by-side where their APIs diverge (the pipeline types, GLSL vs HLSL effects, loose-file vs content-pipeline assets, and viewport coordinate conventions). The original raylib-only docs are preserved as a frozen archive for the prior release.

  • Raylib 3D — Breaking: IRenderPipeline3D.Execute gains a GameTime argument (surfaced to shaders as the time uniform and passed to drawImmediate callbacks). Custom raylib pipelines must add the parameter. Matches the MonoGame backend.

  • Raylib 3D — Breaking (behavioral): Draw3D.drawImmediate callback changed from unit -> unit to SceneContext -> unit. The callback now receives the frame's gathered scene (camera, view/projection, lights, shadows, time) instead of no data.

  • Raylib — Breaking: Mibo.Elmish.Camera is now a [<Struct>] (was a reference record). It flows through the view function every frame, so stack-allocating it removes per-frame Gen0 pressure. Code that held it by reference or relied on reference-identity semantics needs review.

  • Raylib: 3D point/spot shadow lookup is now an O(N) indexed read instead of an O(N·M) per-fragment caster scan (no visual change; faster with many shadow-casting lights). Only the first shadow-casting directional light is registered.

  • Core — Breaking: Cmd<'Msg> has a new Msg of 'Msg case. Exhaustive pattern matches must handle it (or use a wildcard). Cmd.ofMsg returns Msg instead of wrapping in an Effect.

  • Core — Breaking: input uses backend-neutral codes instead of raylib enums — InputMap.key takes KeyCode (not Raylib_cs.KeyboardKey), InputMap.mouse takes MouseButtonCode (not int), and Trigger.MouseBut/GamepadBut became MouseButton/GamepadButton. Bindings are now portable.

  • Raylib — Breaking: Program.withInputMapper moved to RaylibProgram.withInputMapper (raylib backend only). Call sites change Program.withInputMapper mapRaylibProgram.withInputMapper map.

  • Core — Breaking (behavioral): multiple renderers now draw in the order you add them (previously the last-added drew first). Review your setup if you stack renderers.

Fixed

  • Core: Cmd.batch no longer silently drops a lone NowAndDeferNextFrame effect.
  • Core: HeadlessRunner.StepUntil off-by-one fixed (the predicate is now tested after each step; the loop exits immediately when met).
  • Raylib: pollMouse filters Unknown button codes; InputMapper binds the raylib key once per trigger (was three times).
  • Raylib 3D: textures and model materials now load with mipmaps and trilinear filtering. Loaded surfaces previously rendered with point filtering, so 3D models looked flat and matte compared to other backends.
  • Docs: the MonoGame migration guide no longer claims the backend ships without renderers — it now documents the full default pipeline and 2D/3D stacks that are available.

Removed

  • Raylib: 11 stale duplicate test files from Mibo.Raylib.Tests (leftovers from the Mibo.Core.Tests extraction; never compiled).