Skip to content

Commit 526a84d

Browse files
committed
Add mesh rendering
1 parent d9750d1 commit 526a84d

File tree

6 files changed

+187
-25
lines changed

6 files changed

+187
-25
lines changed

Dependencies/Common

Dependencies/RfgTools

src/Render/Renderer.bf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ namespace Nanoforge.Render
177177
//Blending
178178
D3D11_BLEND_DESC blend = .();
179179
ZeroMemory(&blend);
180-
blend.RenderTarget[0].BlendEnable = 1;
180+
blend.RenderTarget[0].BlendEnable = 0;
181181
blend.RenderTarget[0].SrcBlend = .SRC_COLOR;
182182
blend.RenderTarget[0].DestBlend = .BLEND_FACTOR;
183183
blend.RenderTarget[0].BlendOp = .ADD;

src/Render/Resources/Mesh.bf

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
using Common;
2+
using System;
3+
using RfgTools.Formats.Meshes;
4+
using Direct3D;
5+
6+
namespace Nanoforge.Render.Resources
7+
{
8+
public class Mesh
9+
{
10+
public u32 NumLods { get; private set; } = 0;
11+
public u32 LodLevel { get; set; } = 0;
12+
13+
//TODO: Change this to be shareable between mesh instances. Once chunk meshes are added having separate copies of this for each RenderObject will be a serious memory hog (was a problem in the C++ version)
14+
private MeshDataBlock _config = null ~DeleteIfSet!(_);
15+
16+
private append Buffer _vertexBuffer;
17+
private append Buffer _indexBuffer;
18+
private u32 _numVertices = 0;
19+
private u32 _numIndices = 0;
20+
private u32 _vertexStride = 0;
21+
private u32 _indexStride = 0;
22+
private DXGI_FORMAT _indexBufferFormat = .UNKNOWN;
23+
private D3D_PRIMITIVE_TOPOLOGY _topology = .D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
24+
25+
public Result<void> Init(ID3D11Device* device, MeshDataBlock config, Span<u8> indexBuffer, Span<u8> vertexBuffer, u32 numLods = 1)
26+
{
27+
_config = config.Clone(.. new .());
28+
29+
//Test the current assumption that each lod level has only 1 submesh when multiple lods exist
30+
if (numLods != 1)
31+
Runtime.Assert(numLods == config.Header.NumSubmeshes);
32+
33+
_vertexStride = config.Header.VertexStride0;
34+
_indexStride = config.Header.IndexSize;
35+
_numVertices = config.Header.NumVertices;
36+
_numIndices = config.Header.NumIndices;
37+
if (config.Header.IndexSize == 2)
38+
_indexBufferFormat = .R16_UINT;
39+
else if (config.Header.IndexSize == 4)
40+
_indexBufferFormat = .R32_UINT;
41+
else
42+
return .Err; //Unsupported index format
43+
44+
_topology = .D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP; //Hardcoded since all RFG meshes have used this so far
45+
NumLods = numLods;
46+
47+
if (_indexBuffer.Init(device, (u32)indexBuffer.Length, .INDEX_BUFFER, indexBuffer.Ptr) case .Err)
48+
return .Err;
49+
if (_vertexBuffer.Init(device, (u32)vertexBuffer.Length, .VERTEX_BUFFER, vertexBuffer.Ptr) case .Err)
50+
return .Err;
51+
52+
return .Ok;
53+
}
54+
55+
public void Draw(ID3D11DeviceContext* context)
56+
{
57+
//Bind buffers
58+
u32 vertexOffset = 0;
59+
context.IASetIndexBuffer(_indexBuffer.Ptr, _indexBufferFormat, 0);
60+
context.IASetVertexBuffers(0, 1, &_vertexBuffer.Ptr, &_vertexStride, &vertexOffset);
61+
62+
if (NumLods == 1) //In this case the mesh is split into several submeshes
63+
{
64+
for (var submesh in ref _config.Submeshes)
65+
{
66+
u32 firstBlock = submesh.RenderBlocksOffset;
67+
for (u32 i in 0 ..< submesh.NumRenderBlocks)
68+
{
69+
var block = ref _config.RenderBlocks[firstBlock + i];
70+
context.DrawIndexed(block.NumIndices, block.StartIndex, 0);
71+
}
72+
}
73+
}
74+
else //In this case each submesh is a different lod level, so we only draw one submesh
75+
{
76+
var submesh = ref _config.Submeshes[LodLevel];
77+
u32 firstBlock = submesh.RenderBlocksOffset;
78+
for (u32 i in 0 ..< submesh.NumRenderBlocks)
79+
{
80+
var block = ref _config.RenderBlocks[firstBlock + i];
81+
context.DrawIndexed(block.NumIndices, block.StartIndex, 0);
82+
}
83+
}
84+
}
85+
}
86+
}

src/Render/Resources/RenderObject.bf

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
using Common;
2+
using System;
3+
using Common.Math;
4+
using Direct3D;
5+
6+
namespace Nanoforge.Render.Resources
7+
{
8+
[Align(16), CRepr]
9+
public struct PerObjectConstants
10+
{
11+
public Mat4 MVP;
12+
public Mat4 Rotation;
13+
public Vec4<f32> WorldPosition;
14+
}
15+
16+
public class RenderObject
17+
{
18+
public Mesh ObjectMesh ~delete _;
19+
Vec3<f32> Scale = .(1.0f, 1.0f, 1.0f);
20+
Vec3<f32> Position = .Zero;
21+
Mat3 Rotation = .Identity;
22+
bool Visible = true;
23+
24+
public this(Mesh mesh, Vec3<f32> position, Mat3 rotation = .Identity)
25+
{
26+
ObjectMesh = mesh;
27+
Position = position;
28+
Rotation = rotation;
29+
}
30+
31+
public void Draw(ID3D11DeviceContext* context, Buffer perObjectBuffer, Camera3D cam)
32+
{
33+
if (!Visible)
34+
return;
35+
36+
PerObjectConstants constants = .();
37+
38+
//Calculate matrices
39+
Mat4 rotation = .();
40+
rotation.Vectors[0] = .(Rotation.Vectors[0].x, Rotation.Vectors[0].y, Rotation.Vectors[0].z, 0.0f);
41+
rotation.Vectors[1] = .(Rotation.Vectors[1].x, Rotation.Vectors[1].y, Rotation.Vectors[1].z, 0.0f);
42+
rotation.Vectors[2] = .(Rotation.Vectors[2].x, Rotation.Vectors[2].y, Rotation.Vectors[2].z, 0.0f);
43+
rotation.Vectors[3] = .(0.0f, 0.0f, 0.0f, 1.0f);
44+
Mat4 translation = Mat4.Translation(Position);
45+
Mat4 scale = Mat4.Scale(Scale);
46+
Mat4 model = rotation * translation * scale;
47+
48+
//Calculate final MVP matrix + set other constants
49+
constants.MVP = Mat4.Transpose(model * cam.View * cam.Projection);
50+
constants.Rotation = rotation;
51+
constants.WorldPosition = .(Position.x, Position.y, Position.z, 1.0f);
52+
53+
//Set constants
54+
perObjectBuffer.SetData(context, &constants);
55+
56+
ObjectMesh.Draw(context);
57+
}
58+
}
59+
}

src/Render/Scene.bf

Lines changed: 39 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ using Direct3D;
66
using Common;
77
using System;
88
using Win32;
9+
using Common.Misc;
10+
using System.Threading;
911

1012
namespace Nanoforge.Render
1113
{
@@ -22,6 +24,10 @@ namespace Nanoforge.Render
2224
public ID3D11ShaderResourceView* View => _viewTexture.ShaderResourceView;
2325
public bool ErrorOccurred { get; private set; } = false;
2426

27+
public append List<RenderObject> RenderObjects ~ClearAndDeleteItems!(_);
28+
public append Dictionary<Material, List<RenderObject>> ObjectsByMaterial ~ClearDictionaryAndDeleteValues!(_);
29+
private append Monitor _renderObjectCreationLock;
30+
2531
private ID3D11Device* _device = null;
2632
private ID3D11DeviceContext* _context = null;
2733
private ID3D11RasterizerState* _meshRasterizerState ~ReleaseCOM(&_);
@@ -50,6 +56,7 @@ namespace Nanoforge.Render
5056
private bool _primitiveBufferNeedsUpdate = true; //Set to true when the cpu side buffers have changed and need to be sent to the GPU
5157
public bool PrimitiveMaterialsSet => _lineListMaterial != null && _triangleListMaterial != null && _litTriangleListMaterial != null;
5258

59+
[CRepr, RequiredSize(16)]
5360
private struct ColoredVertex
5461
{
5562
public Vec3<f32> Position;
@@ -65,6 +72,7 @@ namespace Nanoforge.Render
6572
}
6673
}
6774

75+
[CRepr, RequiredSize(28)]
6876
private struct ColoredVertexLit
6977
{
7078
public Vec3<f32> Position;
@@ -85,17 +93,11 @@ namespace Nanoforge.Render
8593
[OnCompile(.TypeInit)]
8694
private static void ComptimeSizeChecks()
8795
{
88-
//Make sure vertex structs are the expected size
89-
Runtime.Assert(sizeof(ColoredVertex) == 16);
90-
Runtime.Assert(sizeof(ColoredVertexLit) == 28);
91-
9296
//D3D11 constant buffers must align to 16 bytes
9397
Runtime.Assert(strideof(PerFrameConstants) % 16 == 0);
9498
Runtime.Assert(strideof(PerObjectConstants) % 16 == 0);
9599
}
96100

97-
//TODO: Add drawing functions
98-
99101
public this(ID3D11Device* device, ID3D11DeviceContext* context)
100102
{
101103
_device = device;
@@ -108,11 +110,6 @@ namespace Nanoforge.Render
108110
Camera.Init(.(312.615f, 56.846f, -471.078f), 80.0f, .(ViewWidth, ViewHeight), 1.0f, 10000.0f);
109111
}
110112

111-
public ~this()
112-
{
113-
114-
}
115-
116113
public void Draw(f32 deltaTime)
117114
{
118115
if (ErrorOccurred || !PrimitiveMaterialsSet)
@@ -137,9 +134,18 @@ namespace Nanoforge.Render
137134

138135
//Prepare state to render triangle strip meshes
139136
_context.VSSetConstantBuffers(0, 1, &_perObjectConstantsBuffer.Ptr);
140-
//_context.RSSetState(_meshRasterizerState);
141-
//_context.IASetPrimitiveTopology(.D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
142-
//TODO: Add render objects tied to meshes and draw them here. Use to draw buildings, rocks, terrain, etc
137+
_context.RSSetState(_meshRasterizerState);
138+
_context.IASetPrimitiveTopology(.D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
139+
140+
//Render meshes
141+
for (var kv in ObjectsByMaterial)
142+
{
143+
//Batch render objects by material
144+
Material material = kv.key;
145+
material.Use(_context);
146+
for (RenderObject renderObject in kv.value)
147+
renderObject.Draw(_context, _perObjectConstantsBuffer, Camera);
148+
}
143149

144150
//Prepare state to render primitives
145151
_context.RSSetState(_primitiveRasterizerState);
@@ -192,6 +198,25 @@ namespace Nanoforge.Render
192198
ClearPrimitiveVertexBuffers();
193199
}
194200

201+
public Result<RenderObject> CreateRenderObject(StringView materialName, Mesh mesh, Vec3<f32> position, Mat3 rotation)
202+
{
203+
ScopedLock!(_renderObjectCreationLock);
204+
if (RenderMaterials.GetMaterial(materialName) case .Ok(Material material))
205+
{
206+
RenderObject renderObject = new .(mesh, position, rotation);
207+
RenderObjects.Add(renderObject);
208+
if (!ObjectsByMaterial.ContainsKey(material))
209+
ObjectsByMaterial[material] = new List<RenderObject>();
210+
211+
ObjectsByMaterial[material].Add(renderObject);
212+
return renderObject;
213+
}
214+
else
215+
{
216+
return .Err;
217+
}
218+
}
219+
195220
private void UpdatePrimitiveBuffers()
196221
{
197222
//Update line list vertex buffer
@@ -511,12 +536,4 @@ namespace Nanoforge.Render
511536
public f32 Time = 0.0f;
512537
public Vec2<f32> ViewportDimensions = .Zero;
513538
}
514-
515-
[Align(16), CRepr]
516-
public struct PerObjectConstants
517-
{
518-
public Mat4 MVP;
519-
public Mat4 Rotation;
520-
public Vec4<f32> WorldPosition;
521-
}
522539
}

0 commit comments

Comments
 (0)