public void Bind([MaybeNull] WorldCamera camera, RenderingDevice device, IList <Light3d> lights, MdfRenderOverrides overrides = null) { device.SetMaterial(mDeviceMaterial); BindShader(camera, device, lights, overrides); }
public void DrawQuad(IGameViewport viewport, ReadOnlySpan <ShapeVertex3d> corners, IMdfRenderMaterial material, PackedLinearColorA color) { _discVertexBuffer.Resource.Update(corners); _discBufferBinding.Resource.Bind(); MdfRenderOverrides overrides = new MdfRenderOverrides(); overrides.overrideDiffuse = true; overrides.overrideColor = color; material.Bind(viewport, _device, null, overrides); _device.SetIndexBuffer(_discIndexBuffer); _device.DrawIndexed(PrimitiveType.TriangleList, 4, 2 * 3); }
public void Render(IGameViewport viewport, IAnimatedModel model, AnimatedModelParams animParams, IList <Light3d> lights, MdfRenderOverrides materialOverrides = null) { var renderData = GetOrCreateState(model); var materialIds = model.GetSubmeshes(); for (var i = 0; i < materialIds.Length; ++i) { var material = materialIds[i]; var submesh = animParams.rotation3d ? model.GetSubmeshForParticles(animParams, i) : model.GetSubmesh(animParams, i); // Usually this should not happen, since it means there's // an unbound replacement material if (material == null) { continue; } material.Bind(viewport, mDevice, lights, materialOverrides); // Do we have to recalculate the normals? if (material.GetSpec().recalculateNormals) { RecalcNormals( submesh.VertexCount, submesh.Positions, submesh.Normals, submesh.PrimitiveCount, submesh.Indices ); } var submeshData = GetSubmeshData(renderData, i, submesh); submeshData.binding.Resource.Bind(); mDevice.SetIndexBuffer(submeshData.idxBuffer); mDevice.DrawIndexed(PrimitiveType.TriangleList, submesh.VertexCount, submesh.PrimitiveCount * 3); } }
public void DrawRectangleWithMaterial(Span <Vertex2d> corners, IMdfRenderMaterial material) { MdfRenderOverrides overrides = new MdfRenderOverrides(); overrides.ignoreLighting = true; overrides.uiProjection = true; material?.Bind((WorldCamera)null, _device, Array.Empty <Light3d>(), overrides); _device.SetDepthStencilState(noDepthState); foreach (ref var vertex in corners) { vertex.normal = new Vector4(0, 0, -1, 0); } // Copy the vertices _device.UpdateBuffer <Vertex2d>(vertexBuffer, corners); mdfBufferBinding.Bind(); _device.SetIndexBuffer(indexBuffer); _device.DrawIndexed(PrimitiveType.TriangleList, 4, 6); }
public override void Render(IGameViewport viewport, PartSysEmitter emitter) { var it = emitter.NewIterator(); var animParams = AnimatedModelParams.Default; animParams.rotation3d = true; // Lazily initialize render state if (!emitter.HasRenderState()) { // Resolve the mesh filename var baseName = ResolveBasename(emitter.GetSpec().GetMeshName()); var skmName = baseName + ".skm"; var skaName = baseName + ".ska"; try { var animId = new EncodedAnimId(NormalAnimType.ItemIdle); // This seems to be item_idle var model = _modelFactory.FromFilenames(skmName, skaName, animId, animParams); emitter.SetRenderState( new ModelEmitterRenderState(model) ); } catch (Exception e) { Logger.Error("Unable to load model {0} for particle system {1}: {2}", baseName, emitter.GetSpec().GetParent().GetName(), e); emitter.SetRenderState(new ModelEmitterRenderState(null)); } } var renderState = (ModelEmitterRenderState)emitter.GetRenderState(); if (renderState.Model == null) { return; // The loader above was unable to load the model for this emitter } var overrides = new MdfRenderOverrides { ignoreLighting = true, overrideDiffuse = true }; var yaw = emitter.GetParamState(PartSysParamId.part_yaw); var pitch = emitter.GetParamState(PartSysParamId.part_pitch); var roll = emitter.GetParamState(PartSysParamId.part_roll); while (it.HasNext()) { var particleIdx = it.Next(); var age = emitter.GetParticleAge(particleIdx); overrides.overrideColor = GeneralEmitterRenderState.GetParticleColor(emitter, particleIdx); // Yes, this is *actually* swapped for Y / Z var particleState = emitter.GetParticleState(); animParams.offsetX = particleState.GetState(ParticleStateField.PSF_POS_VAR_X, particleIdx); animParams.offsetY = particleState.GetState(ParticleStateField.PSF_POS_VAR_Z, particleIdx); animParams.offsetZ = particleState.GetState(ParticleStateField.PSF_POS_VAR_Y, particleIdx); if (yaw != null) { animParams.rotationYaw = Angles.ToRadians(yaw.GetValue(emitter, particleIdx, age)); } if (pitch != null) { animParams.rotationPitch = Angles.ToRadians(pitch.GetValue(emitter, particleIdx, age)); } if (roll != null) { animParams.rotationRoll = Angles.ToRadians(roll.GetValue(emitter, particleIdx, age)); } renderState.Model.SetTime(animParams, age); _modelRenderer.Render(viewport, renderState.Model, animParams, new List <Light3d>(), overrides); } }
public void RenderObject(IGameViewport viewport, GameObject obj, bool showInvisible) { mTotalLastFrame++; var type = obj.type; var flags = obj.GetFlags(); // Dont render destroyed or disabled objects const ObjectFlag dontDrawFlags = ObjectFlag.OFF | ObjectFlag.DESTROYED | ObjectFlag.DONTDRAW; if ((flags & dontDrawFlags) != 0) { return; } // Hide invisible objects we're supposed to show them if ((flags & ObjectFlag.INVISIBLE) != 0 && !showInvisible) { return; } // Dont draw secret doors that haven't been found yet var secretDoorFlags = obj.GetSecretDoorFlags(); if (secretDoorFlags.HasFlag(SecretDoorFlag.SECRET_DOOR)) { var found = secretDoorFlags.HasFlag(SecretDoorFlag.SECRET_DOOR_FOUND); if (!found && type != ObjectType.portal) { return; } } var animatedModel = obj.GetOrCreateAnimHandle(); var animParams = obj.GetAnimParams(); locXY worldLoc; GameObject parent = null; if (type.IsEquipment()) { parent = GameSystems.Item.GetParent(obj); } var alpha = GetAlpha(obj); if (parent != null) { var parentAlpha = GetAlpha(parent); alpha = (alpha + parentAlpha) / 2; worldLoc = parent.GetLocation(); } else { worldLoc = obj.GetLocation(); } if (alpha == 0) { return; } // Handle fog occlusion of the world position if (type != ObjectType.container && (type == ObjectType.projectile || type.IsCritter() || type.IsEquipment()) && (GameSystems.MapFogging.GetFogStatus(worldLoc, animParams.offsetX, animParams.offsetY) & 1) == 0) { return; } LocAndOffsets worldPosFull; worldPosFull.off_x = animParams.offsetX; worldPosFull.off_y = animParams.offsetY; worldPosFull.location = worldLoc; var radius = obj.GetRadius(); var renderHeight = obj.GetRenderHeight(true); if (!IsObjectOnScreen(viewport.Camera, worldPosFull, animParams.offsetZ, radius, renderHeight)) { return; } if (Globals.Config.drawObjCylinders) { Tig.ShapeRenderer3d.DrawCylinder( viewport, worldPosFull.ToInches3D(animParams.offsetZ), radius, renderHeight ); } var lightSearchRadius = 0.0f; if (!flags.HasFlag(ObjectFlag.DONTLIGHT)) { lightSearchRadius = radius; } LocAndOffsets locAndOffsets; locAndOffsets.location = worldLoc; locAndOffsets.off_x = animParams.offsetX; locAndOffsets.off_y = animParams.offsetY; var lights = FindLights(locAndOffsets, lightSearchRadius); if (type == ObjectType.weapon) { int glowType; if (flags.HasFlag(ObjectFlag.INVENTORY) && parent != null) { glowType = GameSystems.D20.GetWeaponGlowType(parent, obj); } else { glowType = GameSystems.D20.GetWeaponGlowType(null, obj); } if (glowType != 0 && glowType <= mGlowMaterials.Length) { var glowMaterial = mGlowMaterials[glowType - 1]; if (glowMaterial.IsValid) { RenderObjectHighlight(viewport, obj, glowMaterial); } } } if (GameSystems.ItemHighlight.ShowHighlights && (type.IsEquipment() && !(flags.HasFlag(ObjectFlag.INVENTORY) || flags.HasFlag(ObjectFlag.CLICK_THROUGH)) || GameSystems.Critter.IsLootableCorpse(obj) || type == ObjectType.portal)) { RenderObjectHighlight(viewport, obj, mHighlightMaterial); // Add a single light with full ambient color to make the object appear fully lit lights.Clear(); Light3d fullBrightLight = new Light3d(); fullBrightLight.ambient = LinearColor.White; fullBrightLight.color = new LinearColor(0, 0, 0); fullBrightLight.dir = Vector4.UnitZ; fullBrightLight.type = Light3dType.Directional; lights.Add(fullBrightLight); } mRenderedLastFrame++; MdfRenderOverrides overrides = new MdfRenderOverrides(); overrides.alpha = alpha / 255.0f; mAasRenderer.Render(viewport, animatedModel, animParams, lights, overrides); Light3d globalLight = new Light3d(); if (lights.Count > 0) { globalLight = lights[0]; } if (type.IsCritter()) { if (alpha > 16) { if (mShadowType == ShadowType.ShadowMap) { RenderShadowMapShadow(viewport, obj, animParams, animatedModel, globalLight, alpha); } else if (mShadowType == ShadowType.Geometry) { mAasRenderer.RenderGeometryShadow( viewport.Camera, animatedModel, animParams, globalLight, alpha / 255.0f); } else if (mShadowType == ShadowType.Blob) { RenderBlobShadow(viewport, obj, animatedModel, ref animParams, alpha); } } /* * This renders the equipment in a critter's hand separately, but * I am not certain *why* exactly. I thought this would have been * handled by addmeshes, but it might be that there's a distinct * difference between addmeshes that are skinned onto the mobile's * skeleton and equipment that is unskinned and just positioned * in the player's hands. */ var weaponPrim = GameSystems.Critter.GetWornItem(obj, EquipSlot.WeaponPrimary); if (weaponPrim != null) { RenderObject(viewport, weaponPrim, showInvisible); } var weaponSec = GameSystems.Critter.GetWornItem(obj, EquipSlot.WeaponSecondary); if (weaponSec != null) { RenderObject(viewport, weaponSec, showInvisible); } var shield = GameSystems.Critter.GetWornItem(obj, EquipSlot.Shield); if (shield != null) { RenderObject(viewport, shield, showInvisible); } } else if (type.IsEquipment() && mShadowType == ShadowType.Geometry) { mAasRenderer.RenderGeometryShadow( viewport.Camera, animatedModel, animParams, globalLight, alpha / 255.0f); } RenderMirrorImages( viewport, obj, animParams, animatedModel, lights); if (mGrappleController.IsGiantFrog(obj)) { mGrappleController.AdvanceAndRender( viewport, obj, animParams, animatedModel, lights, alpha / 255.0f); } }
public void RenderObjectHighlight(IGameViewport viewport, GameObject obj, ResourceRef <IMdfRenderMaterial> material) { mTotalLastFrame++; var type = obj.type; var flags = obj.GetFlags(); // Dont render destroyed or disabled objects const ObjectFlag dontDrawFlags = ObjectFlag.OFF | ObjectFlag.DESTROYED | ObjectFlag.DONTDRAW; if ((flags & dontDrawFlags) != 0) { return; } // Hide invisible objects we're supposed to show them if (flags.HasFlag(ObjectFlag.INVISIBLE)) { return; } // Dont draw secret doors that haven't been found yet var secretDoorFlags = obj.GetSecretDoorFlags(); if (secretDoorFlags.HasFlag(SecretDoorFlag.SECRET_DOOR)) { var found = secretDoorFlags.HasFlag(SecretDoorFlag.SECRET_DOOR_FOUND); if (!found && type != ObjectType.portal) { return; } } var animatedModel = obj.GetOrCreateAnimHandle(); var animParams = obj.GetAnimParams(); locXY worldLoc; GameObject parent = null; if (type.IsEquipment()) { parent = GameSystems.Item.GetParent(obj); } var alpha = GetAlpha(obj); if (parent != null) { var parentAlpha = GetAlpha(parent); alpha = (alpha + parentAlpha) / 2; worldLoc = parent.GetLocation(); } else { worldLoc = obj.GetLocation(); } if (alpha == 0) { return; } // Handle fog occlusion of the world position if (type != ObjectType.container && (type == ObjectType.projectile || type.IsCritter() || type.IsEquipment()) && (GameSystems.MapFogging.GetFogStatus(worldLoc, animParams.offsetX, animParams.offsetY) & 1) == 0) { return; } LocAndOffsets worldPosFull; worldPosFull.off_x = animParams.offsetX; worldPosFull.off_y = animParams.offsetY; worldPosFull.location = worldLoc; var radius = obj.GetRadius(); var renderHeight = obj.GetRenderHeight(true); if (!IsObjectOnScreen(viewport.Camera, worldPosFull, animParams.offsetZ, radius, renderHeight)) { return; } var lightSearchRadius = 0.0f; if (!flags.HasFlag(ObjectFlag.DONTLIGHT)) { lightSearchRadius = radius; } LocAndOffsets locAndOffsets; locAndOffsets.location = worldLoc; locAndOffsets.off_x = animParams.offsetX; locAndOffsets.off_y = animParams.offsetY; var lights = FindLights(locAndOffsets, lightSearchRadius); mRenderedLastFrame++; MdfRenderOverrides overrides = new MdfRenderOverrides(); overrides.alpha = alpha / 255.0f; material.Resource.Bind(viewport, mDevice, lights, overrides); mAasRenderer.RenderWithoutMaterial(animatedModel, animParams); }
public void RenderOccludedObject(IGameViewport viewport, GameObject obj) { mTotalLastFrame++; var type = obj.type; var flags = obj.GetFlags(); // Dont render destroyed or disabled objects const ObjectFlag dontDrawFlags = ObjectFlag.OFF | ObjectFlag.DESTROYED | ObjectFlag.DONTDRAW; if ((flags & dontDrawFlags) != 0) { return; } if (flags.HasFlag(ObjectFlag.INVISIBLE) || flags.HasFlag(ObjectFlag.INVENTORY)) { return; } switch (type) { case ObjectType.scenery: case ObjectType.trap: return; case ObjectType.pc: case ObjectType.npc: if (GameSystems.Critter.IsConcealed(obj)) { return; } break; default: break; } // Dont draw secret doors that haven't been found yet var secretDoorFlags = obj.GetSecretDoorFlags(); if (secretDoorFlags.HasFlag(SecretDoorFlag.SECRET_DOOR)) { var found = ((secretDoorFlags & SecretDoorFlag.SECRET_DOOR_FOUND) != 0); if (!found && type != ObjectType.portal) { return; } } var animatedModel = obj.GetOrCreateAnimHandle(); var animParams = obj.GetAnimParams(); locXY worldLoc; GameObject parent = null; if (type.IsEquipment()) { parent = GameSystems.Item.GetParent(obj); } var alpha = GetAlpha(obj); if (parent != null) { var parentAlpha = GetAlpha(parent); alpha = (alpha + parentAlpha) / 2; worldLoc = parent.GetLocation(); } else { worldLoc = obj.GetLocation(); } if (alpha == 0) { return; } // Handle fog occlusion of the world position, but handle it differently for portals if (type != ObjectType.portal) { var fogStatus = GameSystems.MapFogging.GetFogStatus(worldLoc, animParams.offsetX, animParams.offsetY); if ((fogStatus & 0xB0) == 0 || (fogStatus & 1) == 0) { return; } } else { LocAndOffsets loc; loc.location = worldLoc; loc.off_x = animParams.offsetX - locXY.INCH_PER_SUBTILE; loc.off_y = animParams.offsetY - locXY.INCH_PER_SUBTILE; loc.Normalize(); var fogStatus = GameSystems.MapFogging.GetFogStatus(loc.location, loc.off_x, loc.off_y); if ((fogStatus & 0xB0) == 0 || (fogStatus & 1) == 0) { return; } } LocAndOffsets worldPosFull; worldPosFull.off_x = animParams.offsetX; worldPosFull.off_y = animParams.offsetY; worldPosFull.location = worldLoc; var radius = obj.GetRadius(); var renderHeight = obj.GetRenderHeight(true); if (!IsObjectOnScreen(viewport.Camera, worldPosFull, animParams.offsetZ, radius, renderHeight)) { return; } var lightSearchRadius = 0.0f; if (!flags.HasFlag(ObjectFlag.DONTLIGHT)) { lightSearchRadius = radius; } LocAndOffsets locAndOffsets; locAndOffsets.location = worldLoc; locAndOffsets.off_x = animParams.offsetX; locAndOffsets.off_y = animParams.offsetY; var lights = FindLights(locAndOffsets, lightSearchRadius); mRenderedLastFrame++; MdfRenderOverrides overrides = new MdfRenderOverrides(); overrides.alpha = alpha / 255.0f; if (type != ObjectType.portal) { mOccludedMaterial.Resource.Bind(viewport, mDevice, lights, overrides); mAasRenderer.RenderWithoutMaterial(animatedModel, animParams); if (type.IsCritter()) { /* * This renders the equipment in a critter's hand separately, but * I am not certain *why* exactly. I thought this would have been * handled by addmeshes, but it might be that there's a distinct * difference between addmeshes that are skinned onto the mobile's * skeleton and equipment that is unskinned and just positioned * in the player's hands. */ var weaponPrim = GameSystems.Critter.GetWornItem(obj, EquipSlot.WeaponPrimary); if (weaponPrim != null) { RenderOccludedObject(viewport, weaponPrim); } var weaponSec = GameSystems.Critter.GetWornItem(obj, EquipSlot.WeaponSecondary); if (weaponSec != null) { RenderOccludedObject(viewport, weaponSec); } var shield = GameSystems.Critter.GetWornItem(obj, EquipSlot.Shield); if (shield != null) { RenderOccludedObject(viewport, shield); } } } else { if (GameSystems.ItemHighlight.ShowHighlights) { overrides.ignoreLighting = true; } mAasRenderer.Render(viewport, animatedModel, animParams, lights, overrides); } }
private void BindShader([MaybeNull] WorldCamera camera, RenderingDevice device, IList <Light3d> lights, MdfRenderOverrides overrides) { // Fill out the globals for the shader var globals = new MdfGlobalConstants(); Matrix4x4 viewProj; if (overrides != null && overrides.uiProjection) { viewProj = device.UiProjection; } else { viewProj = camera?.GetViewProj() ?? device.UiProjection; } // Should we use a separate world matrix? if (overrides != null && overrides.useWorldMatrix) { // Build a world * view * proj matrix var worldViewProj = overrides.worldMatrix * viewProj; globals.viewProj = worldViewProj; } else { globals.viewProj = viewProj; } // Set material diffuse color for shader Vector4 color; // TODO: This is a bug, it should check overrideDiffuse if (overrides != null && overrides.overrideColor != default) { color = overrides.overrideColor.ToRGBA(); } else { color = new PackedLinearColorA(mSpec.diffuse).ToRGBA(); } globals.matDiffuse = color; if (overrides != null && overrides.alpha != 1.0f) { globals.matDiffuse.W *= overrides.alpha; } // Set time for UV animation in minutes as a floating point number var timeInSec = (float)(device.GetLastFrameStart() - device.GetDeviceCreated()).Seconds; globals.uvAnimTime.X = timeInSec / 60.0f; // Clamp to [0, 1] if (globals.uvAnimTime.X > 1) { globals.uvAnimTime.X -= MathF.Floor(globals.uvAnimTime.X); } // Swirl is more complicated due to cos/sin involvement // This means speedU is in "full rotations every 60 seconds" . RPM var uvRotations = globals.UvRotations; for (var i = 0; i < mSpec.samplers.Count; ++i) { var sampler = mSpec.samplers[i]; if (sampler.uvType != MdfUvType.Swirl) { continue; } ref var uvRot = ref uvRotations[i]; uvRot.X = MathF.Cos(sampler.speedU * globals.uvAnimTime.X * MathF.PI * 2) * 0.1f; uvRot.Y = MathF.Sin(sampler.speedV * globals.uvAnimTime.X * MathF.PI * 2) * 0.1f; }