mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-02-15 03:30:53 +01:00
Compare commits
13 Commits
v240.1.2-s
...
cubed
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0d356eb8f7 | ||
|
|
457705ae9c | ||
|
|
a9d8fed436 | ||
|
|
72bcc4a35e | ||
|
|
0f0d47c629 | ||
|
|
027e36f125 | ||
|
|
298efa3a91 | ||
|
|
8c335fc5d0 | ||
|
|
2a2c97e5ba | ||
|
|
117f4a94c2 | ||
|
|
a692dc7817 | ||
|
|
c8b2394dfb | ||
|
|
4417f685ac |
5
Resources/Shaders/Internal/default-model.swsl
Normal file
5
Resources/Shaders/Internal/default-model.swsl
Normal file
@@ -0,0 +1,5 @@
|
||||
kind model;
|
||||
|
||||
void fragment() {
|
||||
COLOR = texture(TEXTURE, UV);
|
||||
}
|
||||
@@ -12,16 +12,16 @@ uniform mat3 modelMatrix;
|
||||
|
||||
layout (std140) uniform projectionViewMatrices
|
||||
{
|
||||
mat3 projectionMatrix;
|
||||
mat3 viewMatrix;
|
||||
mat4 projectionMatrix;
|
||||
mat4 viewMatrix;
|
||||
};
|
||||
|
||||
void main()
|
||||
{
|
||||
vec3 transformed = modelMatrix * vec3(aPos, 1.0);
|
||||
vec4 transformed = mat4(modelMatrix) * vec4(aPos, 1.0, 1.0);
|
||||
worldPosition = transformed.xy;
|
||||
transformed = projectionMatrix * viewMatrix * transformed;
|
||||
|
||||
gl_Position = vec4(transformed, 1.0);
|
||||
gl_Position = transformed;
|
||||
UV = tCoord;
|
||||
}
|
||||
|
||||
34
Resources/Shaders/Internal/model.frag
Normal file
34
Resources/Shaders/Internal/model.frag
Normal file
@@ -0,0 +1,34 @@
|
||||
#version 330 core
|
||||
|
||||
out vec4 FragColor;
|
||||
|
||||
in vec2 UV;
|
||||
in vec2 Pos;
|
||||
|
||||
uniform sampler2D TEXTURE;
|
||||
uniform sampler2D lightMap;
|
||||
uniform vec4 modulate;
|
||||
|
||||
layout (std140) uniform uniformConstants
|
||||
{
|
||||
vec2 SCREEN_PIXEL_SIZE;
|
||||
float TIME;
|
||||
};
|
||||
|
||||
uniform vec2 TEXTURE_PIXEL_SIZE;
|
||||
|
||||
[SHADER_HEADER_CODE]
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 FRAGCOORD = gl_FragCoord;
|
||||
|
||||
vec4 COLOR;
|
||||
|
||||
[SHADER_CODE]
|
||||
|
||||
FragColor = COLOR * modulate;
|
||||
|
||||
if (FragColor.a < 0.5)
|
||||
discard;
|
||||
}
|
||||
41
Resources/Shaders/Internal/model.vert
Normal file
41
Resources/Shaders/Internal/model.vert
Normal file
@@ -0,0 +1,41 @@
|
||||
#version 330 core
|
||||
|
||||
// Vertex position.
|
||||
layout (location = 0) in vec3 aPos;
|
||||
// Texture coordinates.
|
||||
layout (location = 1) in vec2 tCoord;
|
||||
|
||||
out vec2 UV;
|
||||
out vec2 Pos;
|
||||
|
||||
// Maybe we should merge these CPU side.
|
||||
// idk yet.
|
||||
uniform mat4 modelMatrix;
|
||||
layout (std140) uniform projectionViewMatrices
|
||||
{
|
||||
mat4 projectionMatrix;
|
||||
mat4 viewMatrix;
|
||||
};
|
||||
|
||||
layout (std140) uniform uniformConstants
|
||||
{
|
||||
vec2 SCREEN_PIXEL_SIZE;
|
||||
float TIME;
|
||||
};
|
||||
|
||||
// Allows us to do texture atlassing with texture coordinates 0->1
|
||||
// Input texture coordinates get mapped to this range.
|
||||
uniform vec4 modifyUV;
|
||||
|
||||
[SHADER_HEADER_CODE]
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 VERTEX = projectionMatrix * viewMatrix * modelMatrix * vec4(aPos, 1.0);
|
||||
|
||||
[SHADER_CODE]
|
||||
|
||||
gl_Position = VERTEX;
|
||||
Pos = (VERTEX.xy + 1) / 2;
|
||||
UV = mix(modifyUV.xy, modifyUV.zw, tCoord);
|
||||
}
|
||||
@@ -13,8 +13,8 @@ out vec2 Pos;
|
||||
uniform mat3 modelMatrix;
|
||||
layout (std140) uniform projectionViewMatrices
|
||||
{
|
||||
mat3 projectionMatrix;
|
||||
mat3 viewMatrix;
|
||||
mat4 projectionMatrix;
|
||||
mat4 viewMatrix;
|
||||
};
|
||||
|
||||
layout (std140) uniform uniformConstants
|
||||
@@ -31,7 +31,7 @@ uniform vec4 modifyUV;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec3 transformed = projectionMatrix * viewMatrix * modelMatrix * vec3(aPos, 1.0);
|
||||
vec4 transformed = projectionMatrix * viewMatrix * mat4(modelMatrix) * vec4(aPos, 1.0, 1.0);
|
||||
vec2 VERTEX = transformed.xy;
|
||||
|
||||
[SHADER_CODE]
|
||||
|
||||
@@ -224,8 +224,7 @@ namespace Robust.Client.GameObjects
|
||||
DebugTools.Assert("Component does not exist for state.");
|
||||
}
|
||||
|
||||
DebugTools.Assert(kvStates.Value.curState != null,
|
||||
"Component state is null.");
|
||||
//DebugTools.Assert(kvStates.Value.curState != null, "Component state is null.");
|
||||
|
||||
component.HandleComponentState(kvStates.Value.curState, kvStates.Value.nextState);
|
||||
}
|
||||
|
||||
@@ -25,6 +25,8 @@ using Robust.Shared.Animations;
|
||||
using Robust.Shared.Interfaces.Reflection;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
using Sprite3DRenderMode = Robust.Client.Graphics.Clyde.Clyde.Render3D.Sprite3DRenderMode;
|
||||
|
||||
namespace Robust.Client.GameObjects
|
||||
{
|
||||
public sealed class SpriteComponent : SharedSpriteComponent, ISpriteComponent, IClickTargetComponent,
|
||||
@@ -991,6 +993,106 @@ namespace Robust.Client.GameObjects
|
||||
return LayerGetActualRSI(layer);
|
||||
}
|
||||
|
||||
/// Render the sprite in 3D. This is almost entirely copy-pasted from the 2D version.
|
||||
internal void Render3D(Graphics.Clyde.Clyde.Render3D render, Vector2 worldPosition, Angle worldRotation,
|
||||
Sprite3DRenderMode renderMode, Direction? overrideDirection = null
|
||||
) {
|
||||
Angle angle;
|
||||
Angle spriteAngle;
|
||||
if (Directional)
|
||||
{
|
||||
angle = Rotation;
|
||||
if (renderMode == Sprite3DRenderMode.SimpleSprite)
|
||||
{
|
||||
spriteAngle = worldRotation + render.CameraAngle2D;
|
||||
} else
|
||||
{
|
||||
spriteAngle = worldRotation;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
angle = Rotation + worldRotation;
|
||||
spriteAngle = worldRotation;
|
||||
}
|
||||
|
||||
var mRotation = Matrix4.CreateRotationZ((float)angle);
|
||||
var mWorldOffset = Matrix4.CreateTranslation(worldPosition.X, worldPosition.Y, 0);
|
||||
|
||||
// Draw layers
|
||||
int layer_n = 0;
|
||||
foreach (var layer in Layers)
|
||||
{
|
||||
if (!layer.Visible)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO: Implement layer-specific rotation and scale.
|
||||
|
||||
var texture = layer.Texture;
|
||||
|
||||
if (layer.State.IsValid)
|
||||
{
|
||||
// Pull texture from RSI state instead.
|
||||
var rsi = layer.RSI ?? BaseRSI;
|
||||
if (rsi != null)
|
||||
{
|
||||
var state = rsi[layer.State];
|
||||
|
||||
RSI.State.Direction layerSpecificDir;
|
||||
if (state.Directions == RSI.State.DirectionType.Dir1)
|
||||
{
|
||||
layerSpecificDir = RSI.State.Direction.South;
|
||||
}
|
||||
else
|
||||
{
|
||||
RSI.State.Direction dir;
|
||||
if (overrideDirection != null)
|
||||
{
|
||||
dir = overrideDirection.Value.Convert(state.Directions);
|
||||
}
|
||||
else
|
||||
{
|
||||
dir = GetDir(state.Directions, spriteAngle);
|
||||
}
|
||||
|
||||
layerSpecificDir = OffsetRsiDir(dir, layer.DirOffset);
|
||||
}
|
||||
|
||||
texture = state.GetFrame(layerSpecificDir, layer.AnimationFrame);
|
||||
}
|
||||
}
|
||||
|
||||
texture ??= resourceCache.GetFallback<TextureResource>();
|
||||
|
||||
float offsetZ = renderMode == Sprite3DRenderMode.SimpleSprite ? (float)drawDepth * 0.001f + layer_n * 0.001f : 0.001f;
|
||||
var mOffset = Matrix4.CreateTranslation(new Vector3(Offset.X, Offset.Y, offsetZ));
|
||||
|
||||
bool isWall = renderMode == Sprite3DRenderMode.Wall;
|
||||
int rectCount = isWall ? 5 : 1;
|
||||
|
||||
for (int i = 0; i < rectCount; i++)
|
||||
{
|
||||
var m3D = render.GetSpriteTransform(renderMode, i);
|
||||
|
||||
var transform = mOffset * mRotation * m3D * mWorldOffset;
|
||||
|
||||
var rectColor = color * layer.Color;
|
||||
var rectTexture = texture;
|
||||
|
||||
if (isWall && i == rectCount - 1)
|
||||
{
|
||||
rectColor = Color.Black;
|
||||
}
|
||||
|
||||
render.DrawRect3D(transform, rectTexture, rectColor);
|
||||
}
|
||||
|
||||
layer_n++;
|
||||
}
|
||||
}
|
||||
|
||||
internal void Render(DrawingHandleWorld drawingHandle, in Matrix3 worldTransform, Angle worldRotation, Direction? overrideDirection=null)
|
||||
{
|
||||
var angle = Rotation;
|
||||
@@ -1400,7 +1502,13 @@ namespace Robust.Client.GameObjects
|
||||
}
|
||||
|
||||
var angle = new Angle(worldRotation);
|
||||
return angle.GetDir().Convert(type);
|
||||
if (type == RSI.State.DirectionType.Dir4)
|
||||
{
|
||||
return angle.GetCardinalDir().Convert(type);
|
||||
} else
|
||||
{
|
||||
return angle.GetDir().Convert(type);
|
||||
}
|
||||
}
|
||||
|
||||
private static RSI.State.Direction OffsetRsiDir(RSI.State.Direction dir, DirectionOffset offset)
|
||||
|
||||
@@ -25,5 +25,7 @@ namespace Robust.Client.Graphics.ClientEye
|
||||
matrix.R1C2 = -Position.Y / Zoom.Y;
|
||||
return matrix;
|
||||
}
|
||||
|
||||
public bool Is3D { get; } = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,33 @@ namespace Robust.Client.Graphics.Clyde
|
||||
mapId = _eyeManager.CurrentMap;
|
||||
}
|
||||
|
||||
if (_eyeManager.CurrentEye.Is3D)
|
||||
{
|
||||
var render3d = GetRender3D();
|
||||
|
||||
foreach (var mapGrid in _mapManager.FindGridsIntersecting(mapId, worldBounds))
|
||||
{
|
||||
foreach (var tile in mapGrid.GetTilesIntersecting(worldBounds))
|
||||
{
|
||||
var regionMaybe = _tileDefinitionManager.TileAtlasRegion(tile.Tile);
|
||||
if (!regionMaybe.HasValue)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var region = regionMaybe.Value;
|
||||
|
||||
var transform = Matrix4.CreateTranslation(new Vector3(
|
||||
mapGrid.WorldPosition.X+tile.X+.5f,
|
||||
mapGrid.WorldPosition.Y+tile.Y+.5f,
|
||||
-.5f));
|
||||
|
||||
render3d.DrawRect3D(transform, _tileDefinitionManager.TileTextureAtlas, Color.White, region);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var atlasTexture = _tileDefinitionManager.TileTextureAtlas;
|
||||
var loadedTex = _loadedTextures[((ClydeTexture) atlasTexture).TextureId];
|
||||
|
||||
|
||||
213
Robust.Client/Graphics/Clyde/Clyde.Render3D.cs
Normal file
213
Robust.Client/Graphics/Clyde/Clyde.Render3D.cs
Normal file
@@ -0,0 +1,213 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
using OpenTK.Graphics.OpenGL;
|
||||
using Robust.Client.ResourceManagement.ResourceTypes;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Robust.Client.Graphics.Clyde
|
||||
{
|
||||
|
||||
internal partial class Clyde
|
||||
{
|
||||
|
||||
public class Render3D
|
||||
{
|
||||
private Clyde clyde;
|
||||
private ClydeShaderInstance modelShader;
|
||||
private OGLHandle VAO3D = new OGLHandle(GL.GenVertexArray());
|
||||
private Buffer VBO3D;
|
||||
|
||||
public enum Sprite3DRenderMode
|
||||
{
|
||||
Floor, // Draw Flat on the ground, no extra transformations
|
||||
Table, // Higher than floor
|
||||
SimpleSprite, // Always rotate to face the camera
|
||||
Wall // Render 4 sides + top cap
|
||||
}
|
||||
|
||||
public Render3D(Clyde clyde)
|
||||
{
|
||||
this.clyde = clyde;
|
||||
|
||||
// Load shader
|
||||
var defaultModelShader = clyde._resourceCache
|
||||
.GetResource<ShaderSourceResource>("/Shaders/Internal/default-model.swsl").ClydeHandle;
|
||||
|
||||
this.modelShader = (ClydeShaderInstance)clyde.InstanceShader(defaultModelShader);
|
||||
|
||||
// Set up test mesh
|
||||
int vert_size = sizeof(float) * 5;
|
||||
|
||||
GL.BindVertexArray(VAO3D.Handle);
|
||||
clyde._objectLabelMaybe(ObjectLabelIdentifier.VertexArray, VAO3D, "VAO3D");
|
||||
|
||||
var test = new float[] {
|
||||
0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
|
||||
0.5f, -0.5f, 0.0f, 1.0f, 1.0f,
|
||||
-0.5f, 0.5f, 0.0f, 0.0f, 0.0f,
|
||||
|
||||
0.5f, -0.5f, 0.0f, 1.0f, 1.0f,
|
||||
-0.5f, -0.5f, 0.0f, 0.0f, 1.0f,
|
||||
-0.5f, 0.5f, 0.0f, 0.0f, 0.0f,
|
||||
};
|
||||
|
||||
var test_bytes = MemoryMarshal.AsBytes<float>(test);
|
||||
|
||||
VBO3D = new Buffer(clyde, BufferTarget.ArrayBuffer, BufferUsageHint.DynamicDraw, test_bytes, "VBO3D");
|
||||
VBO3D.Use();
|
||||
|
||||
// Vertex Coords
|
||||
GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, vert_size, 0);
|
||||
GL.EnableVertexAttribArray(0);
|
||||
// Texture Coords.
|
||||
GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, vert_size, 3 * sizeof(float));
|
||||
GL.EnableVertexAttribArray(1);
|
||||
}
|
||||
|
||||
/// Terribly unoptimized, should probably have a sprite batch for 3D quads if this evolves beyond just being a meme.
|
||||
public void DrawRect3D(Matrix4 transform, Texture texture, Color color, UIBox2? subRegion = null)
|
||||
{
|
||||
var region = new Vector4(0, 0, 1, 1);
|
||||
|
||||
if (texture is AtlasTexture atlas)
|
||||
{
|
||||
texture = atlas.SourceTexture;
|
||||
region = new Vector4(
|
||||
atlas.SubRegion.Left / texture.Width,
|
||||
atlas.SubRegion.Top / texture.Height,
|
||||
atlas.SubRegion.Right / texture.Width,
|
||||
atlas.SubRegion.Bottom / texture.Height);
|
||||
} else if (subRegion.HasValue)
|
||||
{
|
||||
region = new Vector4(
|
||||
subRegion.Value.Left,
|
||||
subRegion.Value.Top,
|
||||
subRegion.Value.Right,
|
||||
subRegion.Value.Bottom);
|
||||
}
|
||||
|
||||
var loadedTexture = clyde._loadedTextures[ ((ClydeTexture)texture).TextureId ];
|
||||
|
||||
GL.BindVertexArray(this.VAO3D.Handle);
|
||||
|
||||
var (program, loaded) = clyde.ActivateShaderInstance(this.modelShader.Handle);
|
||||
|
||||
GL.ActiveTexture(TextureUnit.Texture0);
|
||||
GL.BindTexture(TextureTarget.Texture2D, loadedTexture.OpenGLObject.Handle);
|
||||
|
||||
program.SetUniformTextureMaybe(UniIMainTexture, TextureUnit.Texture0);
|
||||
program.SetUniformTextureMaybe(UniILightTexture, TextureUnit.Texture1);
|
||||
|
||||
// Need to take the transpose because linal is hell I guess.
|
||||
transform.Transpose();
|
||||
|
||||
// Model matrix
|
||||
program.SetUniformMaybe(UniIModelMatrix, transform);
|
||||
// Set ModUV to our subregion
|
||||
program.SetUniformMaybe(UniIModUV, region);
|
||||
|
||||
program.SetUniformMaybe(UniIModulate, color); // modulate
|
||||
program.SetUniformMaybe(UniITexturePixelSize, new Vector2(1, 1)); // meh
|
||||
|
||||
GL.DrawArrays(PrimitiveType.Triangles, 0, 6);
|
||||
}
|
||||
|
||||
Vector3 CameraPos = Vector3.Zero;
|
||||
Matrix4 FaceCameraRotation = Matrix4.Identity;
|
||||
|
||||
public Angle CameraAngle2D { get; private set; }
|
||||
|
||||
public (Matrix4,Matrix4) GetProjViewMatrices3D(Vector2 eyePos)
|
||||
{
|
||||
float dist = 10;
|
||||
float dist_v = 10;//0.3f;
|
||||
float angle = 0.3f;//clyde._renderTime * 0.05f;
|
||||
var basePos = new Vector3(eyePos.X, eyePos.Y, 0);
|
||||
CameraAngle2D = new Angle(angle);
|
||||
CameraPos = basePos + new Vector3(MathF.Sin(angle) * -dist, MathF.Cos(angle) * -dist, dist_v);
|
||||
|
||||
//var s = Math.Sin(this._renderTime);
|
||||
//var viewMatrixWorld = Matrix4.LookAt(new Vector3(0, 0, 0), new Vector3(0, 0, 0), new Vector3(0, 1, 0));
|
||||
var viewMatrixWorld = Matrix4.CreateTranslation(-CameraPos);
|
||||
//viewMatrixWorld *= Matrix4.Scale(0.01f);
|
||||
var cameraRotation = Matrix4.CreateRotationZ(angle);
|
||||
cameraRotation *= Matrix4.CreateRotationX(-0.785f);
|
||||
|
||||
viewMatrixWorld *= cameraRotation;
|
||||
//viewMatrixWorld.Invert();
|
||||
//var viewMatrixWorld = Matrix4.Identity;
|
||||
FaceCameraRotation = cameraRotation;
|
||||
FaceCameraRotation.Transpose();
|
||||
|
||||
float aspect = (float)clyde.ScreenSize.X / clyde.ScreenSize.Y;
|
||||
|
||||
var projMatrixWorld = Matrix4.CreatePerspectiveFieldOfView(1.0f, aspect, 0.1f, 100);
|
||||
|
||||
return (projMatrixWorld, viewMatrixWorld);
|
||||
}
|
||||
|
||||
public Matrix4 GetSpriteTransform(Sprite3DRenderMode renderMode, int n = 0)
|
||||
{
|
||||
switch (renderMode)
|
||||
{
|
||||
case Sprite3DRenderMode.Floor:
|
||||
return Matrix4.CreateTranslation(0, 0, -.5f);
|
||||
case Sprite3DRenderMode.Table:
|
||||
return Matrix4.CreateTranslation(0, 0, -.25f);
|
||||
case Sprite3DRenderMode.Wall:
|
||||
switch (n)
|
||||
{
|
||||
case 0:
|
||||
return Matrix4.CreateRotationY(MathHelper.PiOver2) * Matrix4.CreateTranslation(.5f, 0, 0);
|
||||
case 1:
|
||||
return Matrix4.CreateRotationY(MathHelper.PiOver2) * Matrix4.CreateTranslation(-.5f, 0, 0);
|
||||
case 2:
|
||||
return Matrix4.CreateRotationX(MathHelper.PiOver2) * Matrix4.CreateTranslation(0, .5f, 0);
|
||||
case 3:
|
||||
return Matrix4.CreateRotationX(MathHelper.PiOver2) * Matrix4.CreateTranslation(0, -.5f, 0);
|
||||
default:
|
||||
return Matrix4.CreateTranslation(0, 0, .5f);
|
||||
}
|
||||
case Sprite3DRenderMode.SimpleSprite:
|
||||
return FaceCameraRotation;
|
||||
}
|
||||
return Matrix4.Identity;
|
||||
}
|
||||
|
||||
public static Sprite3DRenderMode InferRenderMode(IEntity ent)
|
||||
{
|
||||
switch (ent.Name)
|
||||
{
|
||||
case "worktop":
|
||||
return Sprite3DRenderMode.Table;
|
||||
case "Solid wall":
|
||||
return Sprite3DRenderMode.Wall;
|
||||
case "Catwalk":
|
||||
case "Wire":
|
||||
return Sprite3DRenderMode.Floor;
|
||||
}
|
||||
if (ent.Name.Contains("Airlock"))
|
||||
{
|
||||
return Sprite3DRenderMode.Wall;
|
||||
}
|
||||
|
||||
return Sprite3DRenderMode.SimpleSprite;
|
||||
}
|
||||
}
|
||||
|
||||
Render3D? render3d;
|
||||
|
||||
Render3D GetRender3D()
|
||||
{
|
||||
if (render3d == null)
|
||||
{
|
||||
render3d = new Render3D(this);
|
||||
}
|
||||
return render3d;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Graphics.ClientEye;
|
||||
using Robust.Client.Graphics.Drawing;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
@@ -69,6 +69,9 @@ namespace Robust.Client.Graphics.Clyde
|
||||
private readonly RefList<(SpriteComponent sprite, Matrix3 worldMatrix, Angle worldRotation)> _drawingSpriteList =
|
||||
new RefList<(SpriteComponent, Matrix3, Angle)>();
|
||||
|
||||
private readonly RefList<(SpriteComponent sprite, Vector2 worldPosition, Angle worldRotation, Render3D.Sprite3DRenderMode renderMode)> _drawingSpriteList3D =
|
||||
new RefList<(SpriteComponent, Vector2, Angle, Render3D.Sprite3DRenderMode)>();
|
||||
|
||||
public void Render()
|
||||
{
|
||||
var size = ScreenSize;
|
||||
@@ -131,6 +134,16 @@ namespace Robust.Client.Graphics.Clyde
|
||||
_drawLights(worldBounds);
|
||||
}
|
||||
|
||||
if (eye.Is3D)
|
||||
{
|
||||
// Start 3D rendering. Enable depth buffer.
|
||||
GL.Enable(EnableCap.DepthTest);
|
||||
GL.DepthMask(true);
|
||||
GL.DepthFunc(DepthFunction.Less);
|
||||
|
||||
worldBounds = Box2.CenteredAround(eye.Position.Position, new Vector2(20,20));
|
||||
}
|
||||
|
||||
using (DebugGroup("Grids"))
|
||||
{
|
||||
_drawGrids(worldBounds);
|
||||
@@ -141,6 +154,9 @@ namespace Robust.Client.Graphics.Clyde
|
||||
DrawEntities(worldBounds);
|
||||
}
|
||||
|
||||
// Any 3D rendering should be done.
|
||||
GL.Disable(EnableCap.DepthTest);
|
||||
|
||||
RenderOverlays(OverlaySpace.WorldSpace);
|
||||
|
||||
_lightingReady = false;
|
||||
@@ -166,69 +182,91 @@ namespace Robust.Client.Graphics.Clyde
|
||||
return;
|
||||
}
|
||||
|
||||
// So we could calculate the correct size of the entities based on the contents of their sprite...
|
||||
// Or we can just assume that no entity is larger than 10x10 and get a stupid easy check.
|
||||
// TODO: Make this check more accurate.
|
||||
var widerBounds = worldBounds.Enlarged(5);
|
||||
|
||||
var mapEntity = _mapManager.GetMapEntity(_eyeManager.CurrentMap);
|
||||
|
||||
var identity = Matrix3.Identity;
|
||||
ProcessSpriteEntities(mapEntity, ref identity, Angle.Zero, widerBounds, _drawingSpriteList);
|
||||
|
||||
// We use a separate list for indexing so that the sort is faster.
|
||||
var indexList = ArrayPool<int>.Shared.Rent(_drawingSpriteList.Count);
|
||||
bool is3d = _eyeManager.CurrentEye.Is3D;
|
||||
|
||||
for (var i = 0; i < _drawingSpriteList.Count; i++)
|
||||
if (is3d)
|
||||
{
|
||||
indexList[i] = i;
|
||||
}
|
||||
// Enlarge by a small amount so rendered objects and grids mostly line up with eachother.
|
||||
var widerBounds = worldBounds.Enlarged(.5f);
|
||||
|
||||
Array.Sort(indexList, 0, _drawingSpriteList.Count, new SpriteDrawingOrderComparer(_drawingSpriteList));
|
||||
ProcessSpriteEntities3D(mapEntity, ref identity, Angle.Zero, widerBounds, _drawingSpriteList3D);
|
||||
|
||||
for (var i = 0; i < _drawingSpriteList.Count; i++)
|
||||
{
|
||||
ref var entry = ref _drawingSpriteList[indexList[i]];
|
||||
Vector2i roundedPos = default;
|
||||
if (entry.sprite.PostShader != null)
|
||||
var clyde3d = GetRender3D();
|
||||
|
||||
for (var i = 0; i < _drawingSpriteList3D.Count; i++)
|
||||
{
|
||||
_renderHandle.UseRenderTarget(EntityPostRenderTarget);
|
||||
_renderHandle.Clear(new Color());
|
||||
// Calculate viewport so that the entity thinks it's drawing to the same position,
|
||||
// which is necessary for light application,
|
||||
// but it's ACTUALLY drawing into the center of the render target.
|
||||
var spritePos = entry.sprite.Owner.Transform.WorldPosition;
|
||||
var screenPos = _eyeManager.WorldToScreen(spritePos);
|
||||
var (roundedX, roundedY) = roundedPos = (Vector2i) screenPos;
|
||||
var flippedPos = new Vector2i(roundedX, ScreenSize.Y - roundedY);
|
||||
flippedPos -= EntityPostRenderTarget.Size / 2;
|
||||
_renderHandle.Viewport(Box2i.FromDimensions(-flippedPos, ScreenSize));
|
||||
ref var entry = ref _drawingSpriteList3D[i];
|
||||
|
||||
entry.sprite.Render3D(clyde3d, entry.worldPosition, entry.worldRotation, entry.renderMode);
|
||||
}
|
||||
_drawingSpriteList3D.Clear();
|
||||
} else
|
||||
{
|
||||
// So we could calculate the correct size of the entities based on the contents of their sprite...
|
||||
// Or we can just assume that no entity is larger than 10x10 and get a stupid easy check.
|
||||
// TODO: Make this check more accurate.
|
||||
var widerBounds = worldBounds.Enlarged(5);
|
||||
|
||||
ProcessSpriteEntities(mapEntity, ref identity, Angle.Zero, widerBounds, _drawingSpriteList);
|
||||
|
||||
// We use a separate list for indexing so that the sort is faster.
|
||||
var indexList = ArrayPool<int>.Shared.Rent(_drawingSpriteList.Count);
|
||||
|
||||
for (var i = 0; i < _drawingSpriteList.Count; i++)
|
||||
{
|
||||
indexList[i] = i;
|
||||
}
|
||||
|
||||
entry.sprite.Render(_renderHandle.DrawingHandleWorld, entry.worldMatrix, entry.worldRotation);
|
||||
Array.Sort(indexList, 0, _drawingSpriteList.Count, new SpriteDrawingOrderComparer(_drawingSpriteList));
|
||||
|
||||
if (entry.sprite.PostShader != null)
|
||||
for (var i = 0; i < _drawingSpriteList.Count; i++)
|
||||
{
|
||||
_renderHandle.UseRenderTarget(null);
|
||||
_renderHandle.Viewport(Box2i.FromDimensions(Vector2i.Zero, ScreenSize));
|
||||
ref var entry = ref _drawingSpriteList[indexList[i]];
|
||||
Vector2i roundedPos = default;
|
||||
if (entry.sprite.PostShader != null)
|
||||
{
|
||||
_renderHandle.UseRenderTarget(EntityPostRenderTarget);
|
||||
_renderHandle.Clear(new Color());
|
||||
// Calculate viewport so that the entity thinks it's drawing to the same position,
|
||||
// which is necessary for light application,
|
||||
// but it's ACTUALLY drawing into the center of the render target.
|
||||
var spritePos = entry.sprite.Owner.Transform.WorldPosition;
|
||||
var screenPos = _eyeManager.WorldToScreen(spritePos);
|
||||
var (roundedX, roundedY) = roundedPos = (Vector2i) screenPos;
|
||||
var flippedPos = new Vector2i(roundedX, ScreenSize.Y - roundedY);
|
||||
flippedPos -= EntityPostRenderTarget.Size / 2;
|
||||
_renderHandle.Viewport(Box2i.FromDimensions(-flippedPos, ScreenSize));
|
||||
}
|
||||
|
||||
_renderHandle.UseShader(entry.sprite.PostShader);
|
||||
_renderHandle.SetSpace(CurrentSpace.ScreenSpace);
|
||||
_renderHandle.SetModelTransform(Matrix3.Identity);
|
||||
entry.sprite.Render(_renderHandle.DrawingHandleWorld, entry.worldMatrix, entry.worldRotation);
|
||||
|
||||
var rounded = roundedPos - EntityPostRenderTarget.Size / 2;
|
||||
if (entry.sprite.PostShader != null)
|
||||
{
|
||||
_renderHandle.UseRenderTarget(null);
|
||||
_renderHandle.Viewport(Box2i.FromDimensions(Vector2i.Zero, ScreenSize));
|
||||
|
||||
var box = UIBox2i.FromDimensions(rounded, EntityPostRenderTarget.Size);
|
||||
_renderHandle.UseShader(entry.sprite.PostShader);
|
||||
_renderHandle.SetSpace(CurrentSpace.ScreenSpace);
|
||||
_renderHandle.SetModelTransform(Matrix3.Identity);
|
||||
|
||||
_renderHandle.DrawTexture(EntityPostRenderTarget.Texture, box.BottomLeft,
|
||||
box.TopRight, Color.White, null, 0);
|
||||
var rounded = roundedPos - EntityPostRenderTarget.Size / 2;
|
||||
|
||||
_renderHandle.SetSpace(CurrentSpace.WorldSpace);
|
||||
_renderHandle.UseShader(null);
|
||||
var box = UIBox2i.FromDimensions(rounded, EntityPostRenderTarget.Size);
|
||||
|
||||
_renderHandle.DrawTexture(EntityPostRenderTarget.Texture, box.BottomLeft,
|
||||
box.TopRight, Color.White, null, 0);
|
||||
|
||||
_renderHandle.SetSpace(CurrentSpace.WorldSpace);
|
||||
_renderHandle.UseShader(null);
|
||||
}
|
||||
}
|
||||
_drawingSpriteList.Clear();
|
||||
}
|
||||
|
||||
_drawingSpriteList.Clear();
|
||||
|
||||
FlushRenderQueue();
|
||||
}
|
||||
@@ -268,6 +306,11 @@ namespace Robust.Client.Graphics.Clyde
|
||||
|
||||
entry.Item1 = sprite;
|
||||
entry.Item3 = childWorldRotation;
|
||||
|
||||
/*if (include3DRenderMode)
|
||||
{
|
||||
entry.Item4 = Render3D.InferRenderMode(childEntity);
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
@@ -278,6 +321,51 @@ namespace Robust.Client.Graphics.Clyde
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessSpriteEntities3D(IEntity entity, ref Matrix3 parentTransform, Angle parentRotation,
|
||||
Box2 worldBounds, RefList<(SpriteComponent, Vector2, Angle, Render3D.Sprite3DRenderMode)> list)
|
||||
{
|
||||
entity.TryGetComponent(out ContainerManagerComponent containerManager);
|
||||
|
||||
var localMatrix = entity.Transform.GetLocalMatrix();
|
||||
Matrix3.Multiply(ref parentTransform, ref localMatrix, out var matrix);
|
||||
var rotation = parentRotation + entity.Transform.LocalRotation;
|
||||
|
||||
foreach (var child in entity.Transform.ChildEntityUids)
|
||||
{
|
||||
var childEntity = _entityManager.GetEntity(child);
|
||||
|
||||
if (containerManager != null && containerManager.TryGetContainer(childEntity, out var container) &&
|
||||
!container.ShowContents)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var childTransform = childEntity.Transform;
|
||||
|
||||
var worldPosition = Matrix3.Transform(matrix, childTransform.LocalPosition);
|
||||
|
||||
if (worldBounds.Contains(worldPosition))
|
||||
{
|
||||
if (childEntity.TryGetComponent(out SpriteComponent sprite) && sprite.Visible)
|
||||
{
|
||||
ref var entry = ref list.AllocAdd();
|
||||
|
||||
var childWorldRotation = rotation + childTransform.LocalRotation;
|
||||
|
||||
entry.Item1 = sprite;
|
||||
entry.Item2 = worldPosition;
|
||||
entry.Item3 = childWorldRotation;
|
||||
entry.Item4 = Render3D.InferRenderMode(childEntity);
|
||||
}
|
||||
}
|
||||
|
||||
if (childTransform.ChildCount > 0)
|
||||
{
|
||||
ProcessSpriteEntities3D(childEntity, ref matrix, rotation, worldBounds, list);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void _drawSplash(IRenderHandle handle)
|
||||
{
|
||||
var texture = _resourceCache.GetResource<TextureResource>("/Textures/Logo/logo.png").Texture;
|
||||
@@ -312,27 +400,32 @@ namespace Robust.Client.Graphics.Clyde
|
||||
{
|
||||
var eye = _eyeManager.CurrentEye;
|
||||
|
||||
var toScreen = _eyeManager.WorldToScreen(eye.Position.Position);
|
||||
// Round camera position to a screen pixel to avoid weird issues on odd screen sizes.
|
||||
toScreen = ((float) Math.Floor(toScreen.X), (float) Math.Floor(toScreen.Y));
|
||||
var cameraWorldAdjusted = _eyeManager.ScreenToMap(toScreen);
|
||||
|
||||
var viewMatrixWorld = Matrix3.Identity;
|
||||
viewMatrixWorld.R0C0 = 1 / eye.Zoom.X;
|
||||
viewMatrixWorld.R1C1 = 1 / eye.Zoom.Y;
|
||||
viewMatrixWorld.R0C2 = -cameraWorldAdjusted.X / eye.Zoom.X;
|
||||
viewMatrixWorld.R1C2 = -cameraWorldAdjusted.Y / eye.Zoom.Y;
|
||||
if (eye.Is3D)
|
||||
{
|
||||
var (projMatrixWorld, viewMatrixWorld) = GetRender3D().GetProjViewMatrices3D(eye.Position.Position);
|
||||
return new ProjViewMatrices(projMatrixWorld, viewMatrixWorld);
|
||||
} else
|
||||
{
|
||||
var toScreen = _eyeManager.WorldToScreen(eye.Position.Position);
|
||||
// Round camera position to a screen pixel to avoid weird issues on odd screen sizes.
|
||||
toScreen = ((float) Math.Floor(toScreen.X), (float) Math.Floor(toScreen.Y));
|
||||
var cameraWorldAdjusted = _eyeManager.ScreenToMap(toScreen);
|
||||
|
||||
var projMatrixWorld = Matrix3.Identity;
|
||||
projMatrixWorld.R0C0 = EyeManager.PIXELSPERMETER * 2f / ScreenSize.X;
|
||||
projMatrixWorld.R1C1 = EyeManager.PIXELSPERMETER * 2f / ScreenSize.Y;
|
||||
var viewMatrixWorld = Matrix4.CreateTranslation(new Vector3(-cameraWorldAdjusted.X, -cameraWorldAdjusted.Y, 0));
|
||||
viewMatrixWorld *= Matrix4.Scale(1/ eye.Zoom.X, 1/ eye.Zoom.Y, 1);
|
||||
|
||||
return new ProjViewMatrices(projMatrixWorld, viewMatrixWorld);
|
||||
var projMatrixWorld = Matrix4.Identity;
|
||||
projMatrixWorld.M11 = EyeManager.PIXELSPERMETER * 2f / ScreenSize.X;
|
||||
projMatrixWorld.M22 = EyeManager.PIXELSPERMETER * 2f / ScreenSize.Y;
|
||||
|
||||
return new ProjViewMatrices(projMatrixWorld, viewMatrixWorld);
|
||||
}
|
||||
}
|
||||
|
||||
private void _drawLights(Box2 worldBounds)
|
||||
{
|
||||
if (!_lightManager.Enabled)
|
||||
if (!_lightManager.Enabled || _eyeManager.CurrentEye.Is3D)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -678,7 +771,8 @@ namespace Robust.Client.Graphics.Clyde
|
||||
{
|
||||
GL.ClearColor(color.ConvertOpenTK());
|
||||
GL.ClearStencil(0);
|
||||
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.StencilBufferBit);
|
||||
GL.ClearDepth(1);
|
||||
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.StencilBufferBit | ClearBufferMask.DepthBufferBit);
|
||||
}
|
||||
|
||||
private (ShaderProgram, LoadedShader) ActivateShaderInstance(ClydeHandle handle)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
@@ -19,6 +19,9 @@ namespace Robust.Client.Graphics.Clyde
|
||||
private string _shaderWrapCodeSpriteFrag;
|
||||
private string _shaderWrapCodeSpriteVert;
|
||||
|
||||
private string _shaderWrapCodeModelFrag;
|
||||
private string _shaderWrapCodeModelVert;
|
||||
|
||||
private readonly Dictionary<ClydeHandle, LoadedShader> _loadedShaders =
|
||||
new Dictionary<ClydeHandle, LoadedShader>();
|
||||
|
||||
@@ -48,8 +51,8 @@ namespace Robust.Client.Graphics.Clyde
|
||||
|
||||
public ClydeHandle LoadShader(ParsedShader shader, string name = null)
|
||||
{
|
||||
var vertexSource = _shaderWrapCodeSpriteVert;
|
||||
var fragmentSource = _shaderWrapCodeSpriteFrag;
|
||||
var vertexSource = shader.Kind == ShaderKind.Model ? _shaderWrapCodeModelVert : _shaderWrapCodeSpriteVert;
|
||||
var fragmentSource = shader.Kind == ShaderKind.Model ? _shaderWrapCodeModelFrag : _shaderWrapCodeSpriteFrag;
|
||||
|
||||
var (header, vertBody, fragBody) = _getShaderCode(shader);
|
||||
|
||||
@@ -91,11 +94,13 @@ namespace Robust.Client.Graphics.Clyde
|
||||
_shaderWrapCodeSpriteFrag = _readFile("/Shaders/Internal/sprite.frag");
|
||||
_shaderWrapCodeSpriteVert = _readFile("/Shaders/Internal/sprite.vert");
|
||||
|
||||
|
||||
var defaultLoadedShader = _resourceCache
|
||||
.GetResource<ShaderSourceResource>("/Shaders/Internal/default-sprite.swsl").ClydeHandle;
|
||||
|
||||
_defaultShader = (ClydeShaderInstance) InstanceShader(defaultLoadedShader);
|
||||
_defaultShader = (ClydeShaderInstance)InstanceShader(defaultLoadedShader);
|
||||
|
||||
_shaderWrapCodeModelFrag = _readFile("/Shaders/Internal/model.frag");
|
||||
_shaderWrapCodeModelVert = _readFile("/Shaders/Internal/model.vert");
|
||||
|
||||
_queuedShader = _defaultShader.Handle;
|
||||
|
||||
|
||||
@@ -548,37 +548,47 @@ namespace Robust.Client.Graphics.Clyde
|
||||
[PublicAPI]
|
||||
private struct ProjViewMatrices
|
||||
{
|
||||
[FieldOffset(0 * sizeof(float))] public Vector3 ProjMatrixC0;
|
||||
[FieldOffset(4 * sizeof(float))] public Vector3 ProjMatrixC1;
|
||||
[FieldOffset(8 * sizeof(float))] public Vector3 ProjMatrixC2;
|
||||
|
||||
[FieldOffset(12 * sizeof(float))] public Vector3 ViewMatrixC0;
|
||||
[FieldOffset(16 * sizeof(float))] public Vector3 ViewMatrixC1;
|
||||
[FieldOffset(20 * sizeof(float))] public Vector3 ViewMatrixC2;
|
||||
[FieldOffset(0 * sizeof(float))] Matrix4 ProjMatrix;
|
||||
[FieldOffset(16 * sizeof(float))] Matrix4 ViewMatrix;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ProjViewMatrices(in Matrix3 projMatrix, in Matrix3 viewMatrix)
|
||||
{
|
||||
ProjMatrixC0 = new Vector3(projMatrix.R0C0, projMatrix.R1C0, projMatrix.R2C0);
|
||||
ProjMatrixC1 = new Vector3(projMatrix.R0C1, projMatrix.R1C1, projMatrix.R2C1);
|
||||
ProjMatrixC2 = new Vector3(projMatrix.R0C2, projMatrix.R1C2, projMatrix.R2C2);
|
||||
this.ProjMatrix = new Matrix4(
|
||||
projMatrix.R0C0, projMatrix.R1C0, projMatrix.R2C0, 0,
|
||||
projMatrix.R0C1, projMatrix.R1C1, projMatrix.R2C1, 0,
|
||||
projMatrix.R0C2, projMatrix.R1C2, projMatrix.R2C2, 0,
|
||||
0, 0, 0, 1
|
||||
);
|
||||
|
||||
ViewMatrixC0 = new Vector3(viewMatrix.R0C0, viewMatrix.R1C0, viewMatrix.R2C0);
|
||||
ViewMatrixC1 = new Vector3(viewMatrix.R0C1, viewMatrix.R1C1, viewMatrix.R2C1);
|
||||
ViewMatrixC2 = new Vector3(viewMatrix.R0C2, viewMatrix.R1C2, viewMatrix.R2C2);
|
||||
this.ViewMatrix = new Matrix4(
|
||||
viewMatrix.R0C0, viewMatrix.R1C0, viewMatrix.R2C0, 0,
|
||||
viewMatrix.R0C1, viewMatrix.R1C1, viewMatrix.R2C1, 0,
|
||||
viewMatrix.R0C2, viewMatrix.R1C2, viewMatrix.R2C2, 0,
|
||||
0, 0, 0, 1
|
||||
);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ProjViewMatrices(in ProjViewMatrices readProjMatrix, in Matrix3 viewMatrix)
|
||||
{
|
||||
ProjMatrixC0 = readProjMatrix.ProjMatrixC0;
|
||||
ProjMatrixC1 = readProjMatrix.ProjMatrixC1;
|
||||
ProjMatrixC2 = readProjMatrix.ProjMatrixC2;
|
||||
this.ProjMatrix = readProjMatrix.ProjMatrix;
|
||||
|
||||
ViewMatrixC0 = new Vector3(viewMatrix.R0C0, viewMatrix.R1C0, viewMatrix.R2C0);
|
||||
ViewMatrixC1 = new Vector3(viewMatrix.R0C1, viewMatrix.R1C1, viewMatrix.R2C1);
|
||||
ViewMatrixC2 = new Vector3(viewMatrix.R0C2, viewMatrix.R1C2, viewMatrix.R2C2);
|
||||
this.ViewMatrix = new Matrix4(
|
||||
viewMatrix.R0C0, viewMatrix.R1C0, viewMatrix.R2C0, 0,
|
||||
viewMatrix.R0C1, viewMatrix.R1C1, viewMatrix.R2C1, 0,
|
||||
viewMatrix.R0C2, viewMatrix.R1C2, viewMatrix.R2C2, 0,
|
||||
0, 0, 0, 1
|
||||
);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ProjViewMatrices(in Matrix4 projMatrix, in Matrix4 viewMatrix)
|
||||
{
|
||||
this.ProjMatrix = projMatrix;
|
||||
this.ViewMatrix = viewMatrix;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit, Size = sizeof(float) * 4)]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using OpenTK.Graphics.OpenGL;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using OpenTK.Graphics.OpenGL;
|
||||
@@ -399,6 +399,22 @@ namespace Robust.Client.Graphics.Clyde
|
||||
}
|
||||
}
|
||||
|
||||
public void SetUniformMaybe(string uniformName, in Matrix4 value)
|
||||
{
|
||||
if (TryGetUniform(uniformName, out var slot))
|
||||
{
|
||||
SetUniformDirect(slot, value);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetUniformMaybe(int uniformName, in Matrix4 value)
|
||||
{
|
||||
if (TryGetUniform(uniformName, out var slot))
|
||||
{
|
||||
SetUniformDirect(slot, value);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetUniformMaybe(string uniformName, in Vector2 value)
|
||||
{
|
||||
if (TryGetUniform(uniformName, out var slot))
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Robust.Client.Graphics.ClientEye;
|
||||
using Robust.Client.Graphics.ClientEye;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Robust.Client.Graphics.Drawing
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
@@ -8,13 +8,14 @@ namespace Robust.Client.Graphics.Shaders
|
||||
{
|
||||
public ParsedShader(IReadOnlyDictionary<string, ShaderUniformDefinition> uniforms,
|
||||
IReadOnlyDictionary<string, ShaderVaryingDefinition> varyings, IList<ShaderFunctionDefinition> functions,
|
||||
ShaderLightMode lightMode, ShaderBlendMode blendMode)
|
||||
ShaderLightMode lightMode, ShaderBlendMode blendMode, ShaderKind kind)
|
||||
{
|
||||
Uniforms = uniforms;
|
||||
Varyings = varyings;
|
||||
Functions = functions;
|
||||
LightMode = lightMode;
|
||||
BlendMode = blendMode;
|
||||
Kind = kind;
|
||||
}
|
||||
|
||||
public IReadOnlyDictionary<string, ShaderUniformDefinition> Uniforms { get; }
|
||||
@@ -22,6 +23,7 @@ namespace Robust.Client.Graphics.Shaders
|
||||
public IList<ShaderFunctionDefinition> Functions { get; }
|
||||
public ShaderLightMode LightMode { get; }
|
||||
public ShaderBlendMode BlendMode { get; }
|
||||
public ShaderKind Kind { get; }
|
||||
}
|
||||
|
||||
internal sealed class ShaderFunctionDefinition
|
||||
@@ -163,6 +165,12 @@ namespace Robust.Client.Graphics.Shaders
|
||||
};
|
||||
}
|
||||
|
||||
internal enum ShaderKind
|
||||
{
|
||||
Sprite,
|
||||
Model
|
||||
}
|
||||
|
||||
internal enum ShaderLightMode
|
||||
{
|
||||
Default = 0,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
@@ -42,6 +42,7 @@ namespace Robust.Client.Graphics.Shaders
|
||||
|
||||
ShaderLightMode? lightMode = null;
|
||||
ShaderBlendMode? blendMode = null;
|
||||
ShaderKind? shaderKind = null;
|
||||
|
||||
Token token;
|
||||
|
||||
@@ -56,7 +57,7 @@ namespace Robust.Client.Graphics.Shaders
|
||||
|
||||
if (!(token is TokenWord word))
|
||||
{
|
||||
throw new ShaderParseException("Expected 'light_mode', 'blend_mode', 'uniform', 'varying' or type.",
|
||||
throw new ShaderParseException("Expected 'light_mode', 'blend_mode', 'kind', 'uniform', 'varying' or type.",
|
||||
token.Position);
|
||||
}
|
||||
|
||||
@@ -109,6 +110,34 @@ namespace Robust.Client.Graphics.Shaders
|
||||
throw new ShaderParseException("Expected 'mix', 'add', 'subtract' or 'multiply'.");
|
||||
}
|
||||
}
|
||||
else if (word.Word == "kind")
|
||||
{
|
||||
if (shaderKind != null)
|
||||
{
|
||||
throw new ShaderParseException("Already specified 'kind' before!");
|
||||
}
|
||||
_takeToken();
|
||||
token = _takeToken();
|
||||
|
||||
switch (token)
|
||||
{
|
||||
case TokenWord t when t.Word == "sprite":
|
||||
shaderKind = ShaderKind.Sprite;
|
||||
break;
|
||||
case TokenWord t when t.Word == "model":
|
||||
shaderKind = ShaderKind.Model;
|
||||
break;
|
||||
default:
|
||||
throw new ShaderParseException("Expected 'sprite' or 'model'.");
|
||||
}
|
||||
|
||||
token = _takeToken();
|
||||
if (!(token is TokenSymbol semicolonUnshadedSymbol) ||
|
||||
semicolonUnshadedSymbol.Symbol != Symbols.Semicolon)
|
||||
{
|
||||
throw new ShaderParseException("Expected ';'", token.Position);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
@@ -149,7 +178,7 @@ namespace Robust.Client.Graphics.Shaders
|
||||
return new ParsedShader(
|
||||
_uniformsParsing.ToDictionary(p => p.Name, p => p),
|
||||
_varyingsParsing.ToDictionary(p => p.Name, p => p),
|
||||
_functionsParsing, lightMode ?? ShaderLightMode.Default, blendMode ?? ShaderBlendMode.Mix);
|
||||
_functionsParsing, lightMode ?? ShaderLightMode.Default, blendMode ?? ShaderBlendMode.Mix, shaderKind ?? ShaderKind.Sprite);
|
||||
}
|
||||
|
||||
private void _parseFunction()
|
||||
|
||||
@@ -23,5 +23,7 @@ namespace Robust.Client.Interfaces.Graphics.ClientEye
|
||||
/// Returns the view matrix for this eye.
|
||||
/// </summary>
|
||||
Matrix3 GetViewMatrix();
|
||||
|
||||
bool Is3D { get; }
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user