v2.0.0-rc-001
Pre-releaseAdded
- Core: backend-neutral
Colortype — a byte RGBA struct (Mibo.Color) withtoVector3/toVector4conversions and named constants (White,Black,Red, etc.). Shared light/camera definitions use this instead of a backend-specificColor. Each backend provides inlineableop_Implicitconversions to/from its native color type. - Core: shared 3D light definitions —
AmbientLight3D,DirectionalLight3D,PointLight3D, andSpotLight3D(with their builder modules) now live inMibo.CoreusingMibo.Color+System.Numerics.Vector3. Both backends previously carried byte-for-byte identical copies; now there is one implementation. - Core: shared
Animation3DStateplayback clock — the pure state machine (create,play,blendTo,update, etc.) andAnimation3DClipsInfo(clip names + keyframe counts) now live inMibo.Core. The clock operates on ints/floats only — no backend types. Each backend buildsAnimation3DClipsInfoat load time from its native clip data and delegates playback to the Core functions. - Core: mouse capture —
IInput.SetMouseCapture(MouseCapture)lets games request pointer-locked, unlimited-rotation mouse input via a backend-neutral contract. Raylib uses nativeDisableCursor/EnableCursor; MonoGame re-centers the mouse inside its ownPoll()so no externalGameComponentis needed.
Changed
-
Core — Breaking:
AmbientLight3D.Color,DirectionalLight3D.Color,PointLight3D.Color, andSpotLight3D.Colorare nowMibo.Color(wereRaylib_cs.Color/Microsoft.Xna.Framework.Color). UseMibo.Color.Whiteetc. when constructing lights, or rely on the implicit conversion from your backend's native color. LightDirection/Positionfields are nowSystem.Numerics.Vector3(were native on the MonoGame backend). -
Core — Breaking:
Animation3DClipsgains aClipsInfo: Animation3DClipsInfofield. TheAnimation3DStateplayback 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-specificAnimation3DStatetypes is internal — construct states via the module functions. -
Core:
Animation3DState.updateblend target wrapping now respectsLoop = falseconsistently across both backends (previously raylib always wrapped the blend target regardless of the loop flag). -
MonoGame: device-level config callback —
MonoGameProgramwraps a CoreProgramand carries(Game * GraphicsDeviceManager -> unit)callbacks (ofProgram+withConfig) thatMiboGameruns in its constructor, after the CoreGameConfigbut beforeInitialize/GraphicsDevicecreation. Use this forGraphicsProfile, vsync (SynchronizeWithVerticalRetrace),IsFullScreen,Window.AllowUserResizing,Content.RootDirectory, and other properties that need direct device-manager access.MiboGamenow takes aMonoGamePrograminstead of a rawProgram.MonoGameProgram.withInputMappernow operates on the wrapper. -
MonoGame: host & program —
MiboGame(program)is the MonoGame game host (subclassesMicrosoft.Xna.Framework.Game, drives the sharedElmishLoop).MonoGameProgram.withInputMapperregisters the MonoGame-backed input mapper (and callswithInput).MonoGameGameContextaccessors (getGraphicsDevice/getContentManager/getGame) retrieve MonoGame handles from the CoreGameContextservice registry. MonoGameIAssetsexposes the typed loaders (Texture/Font/Sound/Model/Effect/ModelAnimations/AnimatedMesh) and extends the portableIAssetCache. -
Core:
IAssetCache— backend-neutral asset cache interface (Get/Create/GetOrCreate/Clear/Dispose) that portable code depends on; the backendIAssetsextends it. -
Docs: migration guide —
docs/migration-from-monogame.md, a before/after guide for moving from the original monolithicMibopackage toMibo.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 reference —
docs/shader-uniforms.mdlists the exact uniform names the 3DbeginEffect/endEffectscope uploads (matrices, lights, shadows, material, bones,time), thedrawMeshEffectanddrawImmediatecontracts, 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 shading —
Draw3D.beginEffect/endEffectshade the draws between them with a user-suppliedEffectinstead of PBR. The effect inherits the scene's camera, lights, shadows, material, bones, and atimeclock 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 pipeline —
ForwardPipelineBase(abstract; owns the gather + frame orchestration + a virtualShade) withForwardPipelineas the thin PBR subclass. OverrideShadeto 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:
drawImmediatereceives aSceneContext— the rawGraphicsDeviceplus 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 shading —
Draw3D.beginEffect/endEffectshade the draws between them with a user-suppliedShaderinstead of PBR. The shader inherits the scene's camera, lights, shadows, material, bones, and atimeclock 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 pipeline —ForwardPipelineBase(abstract; owns the gather + frame orchestration + a virtualShade) withForwardPbrPipelineas the thin PBR subclass. OverrideShadeto 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:
drawImmediatereceives aSceneContext— 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 MonoGameSceneContextminus the device field (raylib uses global device state). -
Raylib 3D:
timeuniform in the scene-data contract. Shaders opt into animation (ripples, flowing textures) by declaringtime.IRenderPipeline3D.Executegains aGameTimeargument. -
MonoGame 3D:
timeuniform in the scene-data contract. Shaders opt into animation (ripples, flowing textures) by declaringtime.IRenderPipeline3D.Executegains aGameTimeargument (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
MaterialKeyshort-circuit skips re-uploading unchanged materials. Per-drawnormalMatrix; 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
CastsShadowsrender depth into anR32Fatlas (sampled with 3×3 PCF; OpenGL usesRasterizerStatepolygon-offset + ashadowTexelSizeuniform since SM3.0 has nodFdx/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 viaShadowAtlasConfig/ShadowBiasConfig;EnableShadows/DisableShadows/SetShadowOriginare honored. Only the first shadow-casting directional light is registered (the shader samples slot 0). -
MonoGame 3D: skeletal animation —
AnimatedModelplays/blends animation clips loaded at runtime from raw model files (.glb/.gltf/.fbx/…) via AssimpNetter (the content pipeline discards animation data; loading bothModelAnimations+AnimatedMeshfor the same path parses once).Draw3D.drawAnimatedModelcomputes the bone palette and routes through GPU skinning; the caller never handles aMatrix[]. Cross-fade blend targets respectLoop = false. Load viaIAssets.ModelAnimations/AnimatedMesh(filesystem paths — copy the raw model to your output directory). Adds theAssimpNetterdependency. -
MonoGame 3D: instancing —
Draw3D.drawInstancedrenders bulk geometry via hardware instancing (dual vertex stream) through the PBRInstancedtechnique. -
MonoGame 3D: billboards + lines —
Draw3D.drawBillboard/drawBillboardBatch/drawLine3D(billboard UVs normalized[0,1]; line staging pooled). -
MonoGame 3D core —
Camera3D(perspective/orthographic, orbit, screen-point-to-ray),Culling,Primitive3D(unit cube/sphere/cylinder/plane/torus/cone meshes),Material3D, theDraw3DDSL, and a pluggableIRenderPipeline3D.EndCameraresets 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
Graphics2Dsurface. Includes: mouse back/forward buttons on theMouseDeltastream;Renderer2D.Drawalways closes batches and releases RTs even when a frame throws; per-instance lit-sprite quad buffer; centroid-radiating rounded-rect fill;AddTriangleFancloseLoopfor open fans;LightContext2D.Disposerespects caller effect ownership; float-space particle removal; allocation-free occluder upload; multi-pass post-process;RenderTargetPoolidle-target cap (window-resize leak). -
Core: backend-neutral input —
KeyCode/MouseButtonCode/GamepadButtonCode/GestureKind+IInput/IInputMapper<'Action>live inMibo.Core, so input bindings are portable across backends. -
Core:
Cmd.Msg— a zero-allocationCmdcase forCmd.ofMsg(no delegate wrap). -
Core:
Programbuilder gainswithServiceRegistrationfor backend-specific service registration. -
Core:
Mibo.Coreproject — backend-agnostic home forCmd/Sub/GameTime/Program/GameContext/layout/HeadlessProgram/ElmishLoop. The Raylib backend now references it; namespaces are unchanged. IncludesMibo.Core.Tests. -
Raylib:
RaylibProgram.withInputMapper— the raylib-specific input-mapper builder (decoupled from the shared CoreProgram). -
Raylib / MonoGame 3D:
Draw3D.modelWithandmodelWithPerMeshdraw a model with your ownMaterial3D— 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 gainsanimatedModelWith/animatedModelWithPerMeshfor 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.Executegains aGameTimeargument (surfaced to shaders as thetimeuniform and passed todrawImmediatecallbacks). Custom raylib pipelines must add the parameter. Matches the MonoGame backend. -
Raylib 3D — Breaking (behavioral):
Draw3D.drawImmediatecallback changed fromunit -> unittoSceneContext -> unit. The callback now receives the frame's gathered scene (camera, view/projection, lights, shadows,time) instead of no data. -
Raylib — Breaking:
Mibo.Elmish.Camerais 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 newMsg of 'Msgcase. Exhaustive pattern matches must handle it (or use a wildcard).Cmd.ofMsgreturnsMsginstead of wrapping in anEffect. -
Core — Breaking: input uses backend-neutral codes instead of raylib enums —
InputMap.keytakesKeyCode(notRaylib_cs.KeyboardKey),InputMap.mousetakesMouseButtonCode(notint), andTrigger.MouseBut/GamepadButbecameMouseButton/GamepadButton. Bindings are now portable. -
Raylib — Breaking:
Program.withInputMappermoved toRaylibProgram.withInputMapper(raylib backend only). Call sites changeProgram.withInputMapper map→RaylibProgram.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.batchno longer silently drops a loneNowAndDeferNextFrameeffect. - Core:
HeadlessRunner.StepUntiloff-by-one fixed (the predicate is now tested after each step; the loop exits immediately when met). - Raylib:
pollMousefiltersUnknownbutton codes;InputMapperbinds 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 theMibo.Core.Testsextraction; never compiled).