Initial commit
This commit is contained in:
commit
f04752d09c
10 changed files with 747 additions and 0 deletions
36
LightingTest/.config/dotnet-tools.json
Normal file
36
LightingTest/.config/dotnet-tools.json
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
{
|
||||
"version": 1,
|
||||
"isRoot": true,
|
||||
"tools": {
|
||||
"dotnet-mgcb": {
|
||||
"version": "3.8.1.303",
|
||||
"commands": [
|
||||
"mgcb"
|
||||
]
|
||||
},
|
||||
"dotnet-mgcb-editor": {
|
||||
"version": "3.8.1.303",
|
||||
"commands": [
|
||||
"mgcb-editor"
|
||||
]
|
||||
},
|
||||
"dotnet-mgcb-editor-linux": {
|
||||
"version": "3.8.1.303",
|
||||
"commands": [
|
||||
"mgcb-editor-linux"
|
||||
]
|
||||
},
|
||||
"dotnet-mgcb-editor-windows": {
|
||||
"version": "3.8.1.303",
|
||||
"commands": [
|
||||
"mgcb-editor-windows"
|
||||
]
|
||||
},
|
||||
"dotnet-mgcb-editor-mac": {
|
||||
"version": "3.8.1.303",
|
||||
"commands": [
|
||||
"mgcb-editor-mac"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
15
LightingTest/Content/Content.mgcb
Normal file
15
LightingTest/Content/Content.mgcb
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
|
||||
#----------------------------- Global Properties ----------------------------#
|
||||
|
||||
/outputDir:bin/$(Platform)
|
||||
/intermediateDir:obj/$(Platform)
|
||||
/platform:DesktopGL
|
||||
/config:
|
||||
/profile:Reach
|
||||
/compress:False
|
||||
|
||||
#-------------------------------- References --------------------------------#
|
||||
|
||||
|
||||
#---------------------------------- Content ---------------------------------#
|
||||
|
||||
BIN
LightingTest/Icon.bmp
Normal file
BIN
LightingTest/Icon.bmp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 256 KiB |
BIN
LightingTest/Icon.ico
Normal file
BIN
LightingTest/Icon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 144 KiB |
198
LightingTest/Lighting.cs
Normal file
198
LightingTest/Lighting.cs
Normal file
|
|
@ -0,0 +1,198 @@
|
|||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
using MonoGame.Extended;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
namespace Orpticon.MonoGameLighting
|
||||
{
|
||||
public static class Lighting
|
||||
{
|
||||
private static Texture2D pixelTexture;
|
||||
public static float MaxOpacity { get; set; } = 0.5f; // Maximum opacity
|
||||
public static float BaseDarkness { get; set; } = 0.95f;
|
||||
private static Rectangle CameraRect;
|
||||
private static float[] alphaMap;
|
||||
public static void Initialize(GraphicsDeviceManager graphicsDevice, Rectangle cameraRect)
|
||||
{
|
||||
// TODO: Add your initialization logic here
|
||||
|
||||
pixelTexture = new Texture2D(graphicsDevice.GraphicsDevice, 1, 1);
|
||||
pixelTexture.SetData(new Color[] { Color.White });
|
||||
|
||||
CameraRect = cameraRect;
|
||||
|
||||
alphaMap = new float[CameraRect.Width * CameraRect.Height];
|
||||
Array.Fill(alphaMap, 1f);
|
||||
}
|
||||
|
||||
public static void RenderCone(SpriteBatch _spriteBatch, Vector2 originPoint, float radius) => RenderCone(_spriteBatch, originPoint, new Vector2(0, -1), radius, 360, new List<RectangleF>(), Color.White);
|
||||
public static void RenderCone(SpriteBatch _spriteBatch, Vector2 originPoint, float radius, Color color) => RenderCone(_spriteBatch, originPoint, new Vector2(0, -1), radius, 360, new List<RectangleF>(), color);
|
||||
public static void RenderCone(SpriteBatch _spriteBatch, Vector2 originPoint, float radius, List<RectangleF> collisionBoxes) => RenderCone(_spriteBatch, originPoint, new Vector2(0, -1), radius, 360, collisionBoxes, Color.White);
|
||||
public static void RenderCone(SpriteBatch _spriteBatch, Vector2 originPoint, float radius, List<RectangleF> collisionBoxes, Color color) => RenderCone(_spriteBatch, originPoint, new Vector2(0, -1), radius, 360, collisionBoxes, color);
|
||||
public static void RenderCone(SpriteBatch _spriteBatch, Vector2 originPoint, Vector2 direction, float coneRadius, float coneAngleInDegrees) => RenderCone(_spriteBatch, originPoint, direction, coneRadius, coneAngleInDegrees, new List<RectangleF>(), Color.White);
|
||||
public static void RenderCone(SpriteBatch _spriteBatch, Vector2 originPoint, Vector2 direction, float coneRadius, float coneAngleInDegrees, List<RectangleF> collisionBoxes) => RenderCone(_spriteBatch, originPoint, direction, coneRadius, coneAngleInDegrees, collisionBoxes, Color.White);
|
||||
public static void RenderCone(SpriteBatch _spriteBatch, Vector2 originPoint, Vector2 notNormalizedDirection, float coneRadius, float coneAngleInDegrees, List<RectangleF> collisionBoxes, Color color)
|
||||
{
|
||||
float halfAngle = MathHelper.ToRadians(coneAngleInDegrees) / 2;
|
||||
Vector2 normalizedDirection = Vector2.Normalize(notNormalizedDirection);
|
||||
float coneStartAngle = (float)Math.Atan2(normalizedDirection.Y, normalizedDirection.X) - halfAngle;
|
||||
float coneEndAngle = (float)Math.Atan2(normalizedDirection.Y, normalizedDirection.X) + halfAngle;
|
||||
|
||||
Vector2 startingPoint = new Vector2(
|
||||
Math.Min(originPoint.X, originPoint.X + normalizedDirection.X * coneRadius) - coneRadius,
|
||||
Math.Min(originPoint.Y, originPoint.Y + normalizedDirection.Y * coneRadius) - coneRadius
|
||||
);
|
||||
|
||||
float radiusSquared = coneRadius * coneRadius;
|
||||
float maxBoundingCircleRadius = (float)Math.Sqrt(2 * (1f / 2) * (1f / 2)); // Diagonal of a block
|
||||
|
||||
List<RectangleF> filteredCollisionBoxes = new List<RectangleF>();
|
||||
|
||||
foreach (var collisionBox in collisionBoxes)
|
||||
{
|
||||
Vector2 boxCenter = new Vector2(collisionBox.Center.X, collisionBox.Center.Y);
|
||||
Vector2 directionToBox = Vector2.Normalize(boxCenter - originPoint);
|
||||
float distanceToBoxCenter = Vector2.Distance(originPoint, boxCenter);
|
||||
if (distanceToBoxCenter > coneRadius + maxBoundingCircleRadius)
|
||||
continue;
|
||||
|
||||
float angleToBox = (float)Math.Atan2(directionToBox.Y, directionToBox.X);
|
||||
if (angleToBox < 0)
|
||||
angleToBox += MathHelper.TwoPi;
|
||||
|
||||
float normalizedConeStartAngle = coneStartAngle < 0 ? coneStartAngle + MathHelper.TwoPi : coneStartAngle;
|
||||
float normalizedConeEndAngle = coneEndAngle < 0 ? coneEndAngle + MathHelper.TwoPi : coneEndAngle;
|
||||
|
||||
bool withinConeAngle = normalizedConeStartAngle <= angleToBox && angleToBox <= normalizedConeEndAngle;
|
||||
if (normalizedConeEndAngle < normalizedConeStartAngle)
|
||||
withinConeAngle = angleToBox >= normalizedConeStartAngle || angleToBox <= normalizedConeEndAngle;
|
||||
|
||||
if (withinConeAngle)
|
||||
{
|
||||
filteredCollisionBoxes.Add(collisionBox);
|
||||
}
|
||||
}
|
||||
|
||||
for (float y = startingPoint.Y; y < originPoint.Y + coneRadius; y += 1)
|
||||
{
|
||||
for (float x = startingPoint.X; x < originPoint.X + coneRadius; x += 1)
|
||||
{
|
||||
if(!CameraRect.Contains(x, y)) continue;
|
||||
Vector2 blockCenter = new Vector2(x + 1 / 2, y + 1 / 2);
|
||||
Vector2 toBlock = blockCenter - originPoint;
|
||||
if (toBlock.LengthSquared() > radiusSquared)
|
||||
continue;
|
||||
|
||||
Vector2 directionToBlock = Vector2.Normalize(toBlock);
|
||||
float angleToBlock = (float)Math.Atan2(directionToBlock.Y, directionToBlock.X);
|
||||
if (angleToBlock < 0)
|
||||
angleToBlock += MathHelper.TwoPi;
|
||||
|
||||
float normalizedConeStartAngle = coneStartAngle < 0 ? coneStartAngle + MathHelper.TwoPi : coneStartAngle;
|
||||
float normalizedConeEndAngle = coneEndAngle < 0 ? coneEndAngle + MathHelper.TwoPi : coneEndAngle;
|
||||
|
||||
bool withinConeAngle = normalizedConeStartAngle <= angleToBlock && angleToBlock <= normalizedConeEndAngle;
|
||||
if (normalizedConeEndAngle < normalizedConeStartAngle)
|
||||
withinConeAngle = angleToBlock >= normalizedConeStartAngle || angleToBlock <= normalizedConeEndAngle;
|
||||
|
||||
if (withinConeAngle)
|
||||
{
|
||||
bool clearLineOfSight = true;
|
||||
foreach (var collisionBox in filteredCollisionBoxes)
|
||||
{
|
||||
if (collisionBox.Contains(blockCenter) || RayIntersectsRectangle(originPoint, blockCenter, collisionBox))
|
||||
{
|
||||
clearLineOfSight = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (clearLineOfSight)
|
||||
{
|
||||
float distanceToCenter = toBlock.Length();
|
||||
float opacity = MaxOpacity * (1 - MathHelper.Clamp(distanceToCenter / coneRadius, 0f, 1f));
|
||||
DrawFilledRectangle((int)x, (int)y, opacity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void DrawFilledRectangle(int x, int y, float opacity)
|
||||
{
|
||||
int i = (y - CameraRect.Y) * CameraRect.Width + (x - CameraRect.X);
|
||||
alphaMap[i] *= (1 - opacity);
|
||||
}
|
||||
|
||||
private static bool PointInCone(Vector2 point, Vector2 originPoint, Vector2 endPoint, float coneRadius, float angleOffset)
|
||||
{
|
||||
Vector2 directionToPoint = point - originPoint;
|
||||
Vector2 directionToEndpoint = endPoint - originPoint;
|
||||
float dotProduct = Vector2.Dot(directionToPoint, directionToEndpoint);
|
||||
|
||||
if (dotProduct < 0)
|
||||
return false; // Point is behind the origin point of the cone
|
||||
|
||||
float distanceSquaredToOrigin = Vector2.DistanceSquared(point, originPoint);
|
||||
float maxDistanceSquared = coneRadius * coneRadius;
|
||||
|
||||
if (distanceSquaredToOrigin > maxDistanceSquared)
|
||||
return false; // Point is outside cone radius
|
||||
|
||||
float angleToPoint = (float)Math.Acos(dotProduct / (directionToPoint.Length() * directionToEndpoint.Length()));
|
||||
return angleToPoint <= angleOffset;
|
||||
}
|
||||
private static bool RayIntersectsRectangle(Vector2 rayStart, Vector2 rayEnd, RectangleF rectangle)
|
||||
{
|
||||
Vector2 direction = rayEnd - rayStart;
|
||||
float invDirX = 1.0f / direction.X;
|
||||
float invDirY = 1.0f / direction.Y;
|
||||
|
||||
float tNearX = (rectangle.Left - rayStart.X) * invDirX;
|
||||
float tNearY = (rectangle.Top - rayStart.Y) * invDirY;
|
||||
float tFarX = (rectangle.Right - rayStart.X) * invDirX;
|
||||
float tFarY = (rectangle.Bottom - rayStart.Y) * invDirY;
|
||||
|
||||
if (tNearX > tFarX) (tNearX, tFarX) = (tFarX, tNearX);
|
||||
if (tNearY > tFarY) (tNearY, tFarY) = (tFarY, tNearY);
|
||||
|
||||
if (tNearX > tFarY || tNearY > tFarX)
|
||||
return false;
|
||||
|
||||
float tNear = Math.Max(tNearX, tNearY);
|
||||
float tFar = Math.Min(tFarX, tFarY);
|
||||
|
||||
return tNear >= 0 && tFar >= 0 && tNear <= 1;
|
||||
}
|
||||
public static void ApplyAlphaMap(SpriteBatch _spriteBatch)
|
||||
{
|
||||
for(int x = 0; x < CameraRect.Width; x++)
|
||||
{
|
||||
for(int y = 0; y < CameraRect.Height; y++)
|
||||
{
|
||||
int i = y * CameraRect.Width + x;
|
||||
_spriteBatch.Draw(pixelTexture, new Rectangle(x + CameraRect.X, y + CameraRect.Y, 1, 1), Color.Black * BaseDarkness * alphaMap[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
//protected override void Draw(GameTime gameTime)
|
||||
//{
|
||||
// GraphicsDevice.Clear(Color.Green);
|
||||
|
||||
// _spriteBatch.Begin();
|
||||
// var pos = Mouse.GetState().Position.ToVector2();
|
||||
// var cen = new Vector2(_graphics.PreferredBackBufferWidth / 2, _graphics.PreferredBackBufferHeight / 2);
|
||||
|
||||
// var rects = new List<RectangleF> { new RectangleF(pos, new Vector2(48, 48)), new RectangleF(new Vector2(1024, 384), new Vector2(48, 48)) };
|
||||
// rects.ForEach(x => DrawFilledRectangle(_spriteBatch, x, Color.Brown));
|
||||
|
||||
// RenderCone(_spriteBatch, new Vector2(cen.X, cen.Y), 1000, rects);
|
||||
// _spriteBatch.End();
|
||||
|
||||
// base.Draw(gameTime);
|
||||
//}
|
||||
}
|
||||
}
|
||||
30
LightingTest/Orpticon.MonoGameLighting.csproj
Normal file
30
LightingTest/Orpticon.MonoGameLighting.csproj
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>Library</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<RollForward>Major</RollForward>
|
||||
<PublishReadyToRun>false</PublishReadyToRun>
|
||||
<TieredCompilation>false</TieredCompilation>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||
<ApplicationIcon>Icon.ico</ApplicationIcon>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<None Remove="Icon.ico" />
|
||||
<None Remove="Icon.bmp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Icon.ico" />
|
||||
<EmbeddedResource Include="Icon.bmp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MonoGame.Extended" Version="3.8.0" />
|
||||
<PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.1.303" />
|
||||
<PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.1.303" />
|
||||
</ItemGroup>
|
||||
<Target Name="RestoreDotnetTools" BeforeTargets="Restore">
|
||||
<Message Text="Restoring dotnet tools" Importance="High" />
|
||||
<Exec Command="dotnet tool restore" />
|
||||
</Target>
|
||||
</Project>
|
||||
43
LightingTest/app.manifest
Normal file
43
LightingTest/app.manifest
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<assemblyIdentity version="1.0.0.0" name="LightingTest"/>
|
||||
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
|
||||
<security>
|
||||
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
|
||||
</requestedPrivileges>
|
||||
</security>
|
||||
</trustInfo>
|
||||
|
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
<application>
|
||||
<!-- A list of the Windows versions that this application has been tested on and is
|
||||
is designed to work with. Uncomment the appropriate elements and Windows will
|
||||
automatically selected the most compatible environment. -->
|
||||
|
||||
<!-- Windows Vista -->
|
||||
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />
|
||||
|
||||
<!-- Windows 7 -->
|
||||
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />
|
||||
|
||||
<!-- Windows 8 -->
|
||||
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />
|
||||
|
||||
<!-- Windows 8.1 -->
|
||||
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />
|
||||
|
||||
<!-- Windows 10 -->
|
||||
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
|
||||
|
||||
</application>
|
||||
</compatibility>
|
||||
|
||||
<application xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<windowsSettings>
|
||||
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/pm</dpiAware>
|
||||
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">permonitorv2,permonitor</dpiAwareness>
|
||||
</windowsSettings>
|
||||
</application>
|
||||
|
||||
</assembly>
|
||||
Loading…
Add table
Add a link
Reference in a new issue