HDR color targets!
This commit is contained in:
parent
c2429d3fe6
commit
77a118ee8d
|
|
@ -15,7 +15,7 @@ const modulelist = @import("modulelist.zig").list;
|
|||
const std = @import("std");
|
||||
|
||||
pub const NwArgs = struct {
|
||||
useGPA: bool = true, // slower zig based memory allocator, provides detailed tracking of leaks and memory violations
|
||||
useGPA: bool = false, // slower zig based memory allocator, provides detailed tracking of leaks and memory violations
|
||||
vulkanValidation: bool = true,
|
||||
fastTest: bool = false,
|
||||
dmt: bool = false, // detailed memory tracking, implements a timeline for tracking all memory allocations
|
||||
|
|
|
|||
|
|
@ -557,6 +557,14 @@ pub const Rotation = struct {
|
|||
return .{};
|
||||
}
|
||||
|
||||
pub fn add(self: @This(), other: @This()) Rotation {
|
||||
const m1 = zm.quatToMat(self.quat);
|
||||
const m2 = zm.quatToMat(other.quat);
|
||||
|
||||
const r = zm.mul(m1, m2);
|
||||
return .{ .quat = zm.matToQuat(r) };
|
||||
}
|
||||
|
||||
pub fn eulerX(o: f32) @This() {
|
||||
return .{
|
||||
.quat = zm.matToQuat(zm.rotationX((o))),
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ pub const Impl = struct {
|
|||
//const renderpass = cmd.beginGPURenderPass(color_target_infos: [*c]const GPUColorTargetInfo, num_color_targets: u32, depth_stencil_target_info: [*c]const GPUDepthStencilTargetInfo);
|
||||
|
||||
var targetInfo: gpu.GPUColorTargetInfo = std.mem.zeroes(gpu.GPUColorTargetInfo);
|
||||
targetInfo.texture = rend.context().state.swapchainTexture.?;
|
||||
targetInfo.texture = rend.context().state.swapchainTargetTexture.?;
|
||||
targetInfo.clear_color = .{ .r = 0.0, .g = 0.0, .b = 0.0, .a = 0.0 };
|
||||
targetInfo.load_op = .loadopLoad;
|
||||
targetInfo.store_op = .storeopStore;
|
||||
|
|
|
|||
|
|
@ -44,6 +44,9 @@ pub fn build(b: *std.Build) void {
|
|||
sdl3.shaderDefintion(b, mod, "../../lib/sdl3", optimize, "skybox.frag", b.path("shaders/skybox.frag.json"));
|
||||
sdl3.shaderDefintion(b, mod, "../../lib/sdl3", optimize, "skybox.vert", b.path("shaders/skybox.vert.json"));
|
||||
|
||||
sdl3.shaderDefintion(b, mod, "../../lib/sdl3", optimize, "postProc.frag", b.path("shaders/postProc.frag.json"));
|
||||
sdl3.shaderDefintion(b, mod, "../../lib/sdl3", optimize, "postProc.vert", b.path("shaders/postProc.vert.json"));
|
||||
|
||||
// ========== tests ==========
|
||||
const tests = b.addTest(.{
|
||||
.target = target,
|
||||
|
|
|
|||
|
|
@ -154,7 +154,6 @@ float shadowCalculationPCF(float3 fragPos, float4 DirectionalShadowFragPos)
|
|||
|
||||
float3 DirectionalLight(float3 normal, float3 fragPos, float4 DirectionalShadowFragPos)
|
||||
{
|
||||
|
||||
float3 lightDir = directionalLight.xyz;
|
||||
float diff = max(dot(lightDir, normal), 0.0);
|
||||
float3 diffuse = diff * directionalLightColor.xyz;
|
||||
|
|
@ -174,6 +173,14 @@ float3 DirectionalLight(float3 normal, float3 fragPos, float4 DirectionalShadow
|
|||
return diffuse;
|
||||
}
|
||||
|
||||
float3 reinhard2(float3 x) {
|
||||
const float L_white = 4.0;
|
||||
|
||||
const float3 a = 1.0 + x / (L_white * L_white);
|
||||
const float3 x2 = x * a;
|
||||
const float3 x3 = 1.0 + x;
|
||||
return x2 / x3;
|
||||
}
|
||||
|
||||
|
||||
float4 main(
|
||||
|
|
@ -242,7 +249,7 @@ float4 main(
|
|||
|
||||
if((texMode & 0x2) > 0) // full bright no lighting bit
|
||||
{
|
||||
c2 = col;
|
||||
c2 = col * 4;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
Texture2D<float4> Texture0 : register(t0, space2);
|
||||
SamplerState Sampler0 : register(s0, space2);
|
||||
|
||||
float4 main(float2 UV : TEXCOORD0) : SV_Target0
|
||||
{
|
||||
float2 uv = UV;
|
||||
uv.y *= -1;
|
||||
|
||||
float4 color = Texture0.Sample(Sampler0, uv);
|
||||
|
||||
return color;
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
"entryPoints" : [
|
||||
{
|
||||
"name" : "main",
|
||||
"mode" : "frag"
|
||||
}
|
||||
],
|
||||
"inputs" : [
|
||||
{
|
||||
"type" : "vec2",
|
||||
"name" : "in.var.TEXCOORD0",
|
||||
"location" : 0
|
||||
}
|
||||
],
|
||||
"outputs" : [
|
||||
{
|
||||
"type" : "vec4",
|
||||
"name" : "out.var.SV_Target0",
|
||||
"location" : 0
|
||||
}
|
||||
],
|
||||
"separate_images" : [
|
||||
{
|
||||
"type" : "texture2D",
|
||||
"name" : "Texture0",
|
||||
"set" : 2,
|
||||
"binding" : 0
|
||||
}
|
||||
],
|
||||
"separate_samplers" : [
|
||||
{
|
||||
"type" : "sampler",
|
||||
"name" : "Sampler0",
|
||||
"set" : 2,
|
||||
"binding" : 0
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
struct Input
|
||||
{
|
||||
float3 Position : TEXCOORD0;
|
||||
float3 Normal : TEXCOORD1;
|
||||
float4 Color : TEXCOORD2;
|
||||
float2 UV : TEXCOORD3;
|
||||
uint Bones : TEXCOORD4;
|
||||
uint weights : TEXCOORD5;
|
||||
|
||||
uint Instance : SV_InstanceID;
|
||||
};
|
||||
|
||||
struct Output
|
||||
{
|
||||
float2 UV : TEXCOORD0;
|
||||
float4 Position : SV_Position;
|
||||
};
|
||||
|
||||
Output main(Input input)
|
||||
{
|
||||
Output output;
|
||||
output.Position = float4(input.Position, 1.0);
|
||||
output.UV = input.UV;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"entryPoints" : [
|
||||
{
|
||||
"name" : "main",
|
||||
"mode" : "vert"
|
||||
}
|
||||
],
|
||||
"inputs" : [
|
||||
{
|
||||
"type" : "vec3",
|
||||
"name" : "in.var.TEXCOORD0",
|
||||
"location" : 0
|
||||
},
|
||||
{
|
||||
"type" : "vec2",
|
||||
"name" : "in.var.TEXCOORD3",
|
||||
"location" : 3
|
||||
}
|
||||
],
|
||||
"outputs" : [
|
||||
{
|
||||
"type" : "vec2",
|
||||
"name" : "out.var.TEXCOORD0",
|
||||
"location" : 0
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -197,7 +197,7 @@ pub fn createPipeline(self: *@This()) !*gpu.GPUGraphicsPipeline {
|
|||
pci.target_info.num_color_targets = 1;
|
||||
pci.target_info.color_target_descriptions = &[_]gpu.GPUColorTargetDescription{
|
||||
.{
|
||||
.format = self.device.getGPUSwapchainTextureFormat(rend.context().window),
|
||||
.format = rend.context().hdrTextureFormat,
|
||||
.blend_state = std.mem.zeroes(gpu.GPUColorTargetBlendState),
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ fn createPipeline(self: *@This()) !void {
|
|||
pci.target_info.num_color_targets = 1;
|
||||
pci.target_info.color_target_descriptions = &[_]gpu.GPUColorTargetDescription{
|
||||
.{
|
||||
.format = self.device.getGPUSwapchainTextureFormat(ctx.window),
|
||||
.format = ctx.hdrTextureFormat,
|
||||
.blend_state = std.mem.zeroes(gpu.GPUColorTargetBlendState),
|
||||
},
|
||||
};
|
||||
|
|
@ -85,7 +85,7 @@ pub fn destroy(self: *@This()) void {
|
|||
|
||||
pub fn render(self: *@This(), cmd: *gpu.GPUCommandBuffer) void {
|
||||
const targetInfo: gpu.GPUColorTargetInfo = std.mem.zeroInit(gpu.GPUColorTargetInfo, .{
|
||||
.texture = rend.context().state.swapchainTexture.?,
|
||||
.texture = rend.context().state.targetTexture,
|
||||
.clear_color = self.skyboxColor,
|
||||
.load_op = .loadopClear,
|
||||
.store_op = .storeopStore,
|
||||
|
|
@ -102,6 +102,7 @@ pub fn render(self: *@This(), cmd: *gpu.GPUCommandBuffer) void {
|
|||
}
|
||||
|
||||
const renderpass = cmd.beginGPURenderPass(&targetInfo, 1, null);
|
||||
|
||||
if (self.skyboxTexture) |skyboxTexture| {
|
||||
if (self.skyboxMesh) |skyboxMesh| {
|
||||
const ctx = rend.context();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
# Blender 4.4.3
|
||||
# www.blender.org
|
||||
o Plane
|
||||
v -1.000000 1.000000 0.000000
|
||||
v 1.000000 1.000000 0.000000
|
||||
v -1.000000 -1.000000 -0.000000
|
||||
v 1.000000 -1.000000 -0.000000
|
||||
vn -0.0000 1.0000 -0.0000
|
||||
vt 0.000000 0.000000
|
||||
vt 1.000000 0.000000
|
||||
vt 1.000000 1.000000
|
||||
vt 0.000000 1.000000
|
||||
s 0
|
||||
f 1/1/1 2/2/1 4/3/1 3/4/1
|
||||
|
||||
|
|
@ -72,6 +72,12 @@ pub const Renderer = struct {
|
|||
state: RendererState = .{},
|
||||
// swapchainTexture: ?*gpu.GPUTexture = undefined,
|
||||
|
||||
swapchainTargetFormat: gpu.GPUTextureFormat = undefined,
|
||||
hdrTextureFormat: gpu.GPUTextureFormat = undefined,
|
||||
postProcessingPipeline: *gpu.GPUGraphicsPipeline = undefined,
|
||||
|
||||
screenPlane: ?rend.IndexedMesh = null,
|
||||
|
||||
pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This());
|
||||
|
||||
pub const MaxObjectCount = 50000;
|
||||
|
|
@ -86,9 +92,28 @@ pub const Renderer = struct {
|
|||
try core.defineComponent(rend.MeshComponent, allocator);
|
||||
try core.defineComponent(rend.CameraComponent, allocator);
|
||||
|
||||
self.hdrTextureFormat = .textureformatR16g16b16a16Float;
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn createHDRTexture(self: *@This()) !void {
|
||||
var gci = std.mem.zeroes(gpu.GPUTextureCreateInfo);
|
||||
|
||||
gci.type = .texturetype2d;
|
||||
gci.format = self.hdrTextureFormat;
|
||||
gci.width = @intCast(platform.getInstance().windowExtent.x);
|
||||
gci.height = @intCast(platform.getInstance().windowExtent.y);
|
||||
gci.layer_count_or_depth = 1;
|
||||
gci.num_levels = 1;
|
||||
gci.sample_count = .samplecount1;
|
||||
gci.usage = .{
|
||||
.textureusageSampler = true,
|
||||
.textureusageColorTarget = true,
|
||||
};
|
||||
|
||||
self.state.targetTexture = self.device.createGPUTexture(&gci);
|
||||
}
|
||||
|
||||
pub fn startRenderer(self: *@This()) !void {
|
||||
self.device = gpu.createGPUDevice(.{
|
||||
.shaderformatSpirv = true,
|
||||
|
|
@ -110,6 +135,8 @@ pub const Renderer = struct {
|
|||
try self.createMeshPipeline();
|
||||
try self.createBuffers();
|
||||
try self.createDepthTexture();
|
||||
try self.createHDRTexture();
|
||||
try self.createPostProcessingPipeline();
|
||||
|
||||
self.meshPool = try self.createRendererObject(MeshPool);
|
||||
self.textureList = try self.createRendererEngineObject(TextureList);
|
||||
|
|
@ -141,6 +168,8 @@ pub const Renderer = struct {
|
|||
|
||||
_ = try core.fs().installFileBytesMount("embedded:plane.obj", @constCast(&plane_obj), true);
|
||||
|
||||
_ = try core.fs().installFileBytesMount("embedded:screenPlane.obj", @constCast(&screenPlane_obj), true);
|
||||
|
||||
try assets.load(
|
||||
assets.MakeImportRefOptions(
|
||||
"Mesh",
|
||||
|
|
@ -148,6 +177,49 @@ pub const Renderer = struct {
|
|||
.{ .path = "embedded:plane.obj" },
|
||||
),
|
||||
);
|
||||
|
||||
try assets.load(
|
||||
assets.MakeImportRefOptions(
|
||||
"Mesh",
|
||||
"m_screenPlane",
|
||||
.{ .path = "embedded:screenPlane.obj" },
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
pub fn createPostProcessingPipeline(self: *@This()) !void {
|
||||
const vertex = try self.loadShader("postProc.vert", postProcVert.LoadArgs);
|
||||
const fragment = try self.loadShader("postProc.frag", postProcFrag.LoadArgs);
|
||||
|
||||
var pci = std.mem.zeroes(gpu.GPUGraphicsPipelineCreateInfo);
|
||||
pci.vertex_shader = vertex;
|
||||
pci.fragment_shader = fragment;
|
||||
|
||||
var attributes = try self.generateVertexAttributeList();
|
||||
defer attributes.deinit();
|
||||
|
||||
pci.vertex_input_state = .{
|
||||
.num_vertex_buffers = 1,
|
||||
.vertex_buffer_descriptions = &[_]gpu.GPUVertexBufferDescription{
|
||||
.{ .slot = 0, .pitch = @sizeOf(rend.MeshVertex), .input_rate = .vertexinputrateVertex, .instance_step_rate = 0 },
|
||||
},
|
||||
.num_vertex_attributes = @intCast(attributes.items.len),
|
||||
.vertex_attributes = @ptrCast(attributes.items.ptr),
|
||||
};
|
||||
|
||||
core.graphics_log("hdr texture format format: {any}", .{self.hdrTextureFormat});
|
||||
pci.target_info.num_color_targets = 1;
|
||||
pci.target_info.color_target_descriptions = &[_]gpu.GPUColorTargetDescription{
|
||||
.{
|
||||
.format = self.swapchainTargetFormat,
|
||||
.blend_state = std.mem.zeroes(gpu.GPUColorTargetBlendState),
|
||||
},
|
||||
};
|
||||
|
||||
pci.rasterizer_state.cull_mode = .cullmodeNone;
|
||||
pci.rasterizer_state.fill_mode = .fillmodeFill;
|
||||
|
||||
self.postProcessingPipeline = self.device.createGPUGraphicsPipeline(&pci);
|
||||
}
|
||||
|
||||
pub fn createDirectionalShadowsPipeline(self: *@This()) !void {
|
||||
|
|
@ -340,12 +412,14 @@ pub const Renderer = struct {
|
|||
pci.depth_stencil_state.enable_depth_write = true;
|
||||
pci.depth_stencil_state.write_mask = 0xff;
|
||||
|
||||
self.swapchainTargetFormat = self.device.getGPUSwapchainTextureFormat(self.window);
|
||||
core.graphics_log("swapchain format: {any}", .{self.swapchainTargetFormat});
|
||||
pci.target_info.has_depth_stencil_target = true;
|
||||
pci.target_info.depth_stencil_format = self.depthFormat;
|
||||
pci.target_info.num_color_targets = 1;
|
||||
pci.target_info.color_target_descriptions = &[_]gpu.GPUColorTargetDescription{
|
||||
.{
|
||||
.format = self.device.getGPUSwapchainTextureFormat(self.window),
|
||||
.format = self.hdrTextureFormat,
|
||||
.blend_state = std.mem.zeroes(gpu.GPUColorTargetBlendState),
|
||||
},
|
||||
};
|
||||
|
|
@ -606,8 +680,8 @@ pub const Renderer = struct {
|
|||
pub fn draw(self: *@This()) void {
|
||||
const cmd = self.state.cmd.?;
|
||||
|
||||
if (cmd.waitAndAcquireGPUSwapchainTexture(self.window, @ptrCast(&self.state.swapchainTexture), null, null)) {
|
||||
if (self.state.swapchainTexture == null) {
|
||||
if (cmd.waitAndAcquireGPUSwapchainTexture(self.window, @ptrCast(&self.state.swapchainTargetTexture), null, null)) {
|
||||
if (self.state.swapchainTargetTexture == null) {
|
||||
_ = cmd.submitGPUCommandBuffer();
|
||||
return;
|
||||
}
|
||||
|
|
@ -623,7 +697,7 @@ pub const Renderer = struct {
|
|||
|
||||
// can cache this
|
||||
const targetInfo: gpu.GPUColorTargetInfo = std.mem.zeroInit(gpu.GPUColorTargetInfo, .{
|
||||
.texture = self.state.swapchainTexture.?,
|
||||
.texture = self.state.targetTexture,
|
||||
.load_op = .loadopLoad,
|
||||
.store_op = .storeopStore,
|
||||
});
|
||||
|
|
@ -640,6 +714,8 @@ pub const Renderer = struct {
|
|||
|
||||
self.state.pass = cmd.beginGPURenderPass(&targetInfo, 1, &depthTarget);
|
||||
const renderpass = self.state.pass.?;
|
||||
renderpass.setGPUScissor(&self.scissor);
|
||||
|
||||
//renderpass.bindGPUGraphicsPipeline(self.testPipeline);
|
||||
renderpass.bindGPUFragmentSamplers(1, &.{ .sampler = self.blockySampler, .texture = self.defaultTexture.texture }, 1);
|
||||
renderpass.bindGPUFragmentSamplers(2, &.{ .sampler = self.blockySampler, .texture = self.defaultTexture.texture }, 1);
|
||||
|
|
@ -654,8 +730,6 @@ pub const Renderer = struct {
|
|||
renderpass.bindGPUFragmentSamplers(self.shadowDepthTextureSlot, &.{ .texture = self.shadowDepthTexture, .sampler = self.blockySampler }, 1);
|
||||
// todo move into materials system
|
||||
|
||||
renderpass.setGPUScissor(&self.scissor);
|
||||
|
||||
try self.uploadUniforms(cmd);
|
||||
//rendering each mesh
|
||||
{
|
||||
|
|
@ -686,15 +760,35 @@ pub const Renderer = struct {
|
|||
for (self.postMesh.items) |interface| {
|
||||
interface.func(interface.ptr, cmd, renderpass);
|
||||
}
|
||||
|
||||
renderpass.endGPURenderPass();
|
||||
|
||||
{
|
||||
const postProcTargetInfo: gpu.GPUColorTargetInfo = std.mem.zeroInit(gpu.GPUColorTargetInfo, .{
|
||||
.texture = self.state.swapchainTargetTexture.?,
|
||||
.load_op = .loadopDontCare,
|
||||
.store_op = .storeopStore,
|
||||
});
|
||||
|
||||
const postProcPass = cmd.beginGPURenderPass(&postProcTargetInfo, 1, null);
|
||||
|
||||
postProcPass.bindGPUGraphicsPipeline(self.postProcessingPipeline);
|
||||
postProcPass.bindGPUFragmentSamplers(0, &.{ .sampler = self.blockySampler, .texture = self.state.targetTexture }, 1);
|
||||
|
||||
// post processing + hdr etc...
|
||||
if (self.screenPlane == null) {
|
||||
self.screenPlane = getMesh("m_screenPlane");
|
||||
}
|
||||
|
||||
if (self.screenPlane) |mesh| {
|
||||
postProcPass.drawGPUIndexedPrimitives(mesh.index.size, 1, mesh.index.start, @intCast(mesh.vertex.start), 0);
|
||||
}
|
||||
|
||||
postProcPass.endGPURenderPass();
|
||||
}
|
||||
|
||||
for (self.postRenders.items) |interface| {
|
||||
interface.func(interface.ptr, cmd);
|
||||
}
|
||||
|
||||
// renderpass.drawGPUPrimitives(3, 1, 0, 0);
|
||||
|
||||
}
|
||||
|
||||
_ = cmd.submitGPUCommandBuffer();
|
||||
|
|
@ -734,6 +828,9 @@ const lit_mesh_frag = @import("lit_mesh.frag");
|
|||
const depthOnly = @import("depthOnly.frag");
|
||||
const sample_vert = @import("sample.vert");
|
||||
|
||||
const postProcVert = @import("postProc.vert");
|
||||
const postProcFrag = @import("postProc.frag");
|
||||
|
||||
const MeshVertices = meshes_vert.Scene;
|
||||
const MeshUniforms = meshes_vert.Uniforms;
|
||||
|
||||
|
|
@ -801,10 +898,12 @@ pub const RendererState = struct {
|
|||
copyPass: ?*gpu.GPURenderPass = null,
|
||||
pass: ?*gpu.GPURenderPass = null,
|
||||
cmd: ?*gpu.GPUCommandBuffer = null,
|
||||
swapchainTexture: ?*gpu.GPUTexture = null,
|
||||
swapchainTargetTexture: ?*gpu.GPUTexture = null,
|
||||
targetTexture: *gpu.GPUTexture = undefined,
|
||||
};
|
||||
|
||||
pub const CustomMeshRenderFunc = *const fn (?*anyopaque) void;
|
||||
pub const GPUTextureType = gpu.GPUTexture;
|
||||
|
||||
const plane_obj align(8) = @embedFile("embedded/plane.obj").*;
|
||||
const screenPlane_obj align(8) = @embedFile("embedded/screenPlane.obj").*;
|
||||
|
|
|
|||
|
|
@ -7,18 +7,75 @@ texture: *gpu.GPUTexture = undefined,
|
|||
|
||||
width: u32,
|
||||
height: u32,
|
||||
|
||||
inputEnabled: bool = false,
|
||||
|
||||
sensitivity: f32 = 1.0,
|
||||
|
||||
entity: core.Entity,
|
||||
|
||||
fn log(comptime fmt: []const u8, args: anytype) void {
|
||||
core.engine_log("[Doomplayer] " ++ fmt, args);
|
||||
}
|
||||
|
||||
pub fn create(allocator: std.mem.Allocator) !*@This() {
|
||||
pub const DoomCanvas = struct {
|
||||
data: core.GameObjectData = undefined,
|
||||
entity: core.Entity,
|
||||
first: bool = false,
|
||||
|
||||
pub fn create(alloc: std.mem.Allocator) !*@This() {
|
||||
var first: bool = false;
|
||||
if (gDoom == null) {
|
||||
first = true;
|
||||
gDoom = try createDoom(alloc);
|
||||
}
|
||||
|
||||
if (gDoom) |doomCtx| {
|
||||
const self = try alloc.create(@This());
|
||||
self.first = first;
|
||||
|
||||
const entity = try core.createEntity();
|
||||
const scene = entity.addComponent(core.Scene).?;
|
||||
const size = 5.0;
|
||||
const h: f32 = @floatFromInt(doomCtx.height);
|
||||
const w: f32 = @floatFromInt(doomCtx.width);
|
||||
|
||||
scene.setScale(size, size, size * (h / w));
|
||||
scene.setRotation(core.Rotation.eulerX(core.radians(90.0)));
|
||||
scene.setPosition(.{ .z = 30 });
|
||||
|
||||
if (entity.addComponent(rend.MeshComponent)) |mesh| {
|
||||
mesh.cmrf = bindVideoTextures;
|
||||
mesh.cmrf_ctx = doomCtx;
|
||||
mesh.textureMode.fullbright = true;
|
||||
mesh.textureMode.noSrgb = true;
|
||||
mesh.setMesh("m_plane");
|
||||
}
|
||||
self.entity = entity;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
return error.ContextNotReady;
|
||||
}
|
||||
|
||||
pub fn tick(self: *@This(), dt: f64) void {
|
||||
if (self.first) {
|
||||
gDoom.?.tick(dt);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn getEntity(self: *@This()) core.Entity {
|
||||
return self.entity;
|
||||
}
|
||||
|
||||
pub fn destroy(self: *@This()) void {
|
||||
self.entity.destroy();
|
||||
if (self.first) {
|
||||
gDoom.?.destroy();
|
||||
}
|
||||
self.data.release(self);
|
||||
}
|
||||
};
|
||||
|
||||
pub fn createDoom(allocator: std.mem.Allocator) !*@This() {
|
||||
const self = try allocator.create(@This());
|
||||
self.* = .{
|
||||
.allocator = allocator,
|
||||
|
|
@ -28,8 +85,6 @@ pub fn create(allocator: std.mem.Allocator) !*@This() {
|
|||
|
||||
log("initialized", .{});
|
||||
|
||||
try self.setup();
|
||||
|
||||
self.sensitivity = core.configVar(f32, "doomplayer.sensitivity", 1.0);
|
||||
gDoom = self;
|
||||
|
||||
|
|
@ -44,11 +99,13 @@ pub fn create(allocator: std.mem.Allocator) !*@This() {
|
|||
c.doom_set_default_int("mouse_move", 0); // Mouse will not move forward
|
||||
|
||||
c.doom_init(1, @constCast(@ptrCast(@alignCast(&.{"doom"}))), 8);
|
||||
|
||||
self.entity = try self.createEntity();
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn getEntity(self: *@This()) core.Entity {
|
||||
return self.entity;
|
||||
}
|
||||
|
||||
fn sdlToDoomButton(button: c_uint) c_uint {
|
||||
switch (button) {
|
||||
sdl3_c.SDL_BUTTON_LEFT => {
|
||||
|
|
@ -290,34 +347,36 @@ fn sdlToDoomScancode(sdlScancode: c_uint) c_int {
|
|||
return c.DOOM_KEY_UNKNOWN;
|
||||
}
|
||||
|
||||
var gDoom: *@This() = undefined;
|
||||
pub var gDoom: ?*@This() = null;
|
||||
|
||||
pub fn processFunc(e: *sdl3.Event) void {
|
||||
if (!gDoom.inputEnabled) {
|
||||
return;
|
||||
}
|
||||
if (gDoom) |ctx| {
|
||||
if (!ctx.inputEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (e.type) {
|
||||
else => {},
|
||||
sdl3_c.SDL_EVENT_MOUSE_MOTION => {
|
||||
c.doom_mouse_move(@intFromFloat(e.motion.xrel * 4 * gDoom.sensitivity), @intFromFloat(e.motion.yrel * 4 * gDoom.sensitivity));
|
||||
},
|
||||
sdl3_c.SDL_EVENT_MOUSE_BUTTON_DOWN => {
|
||||
c.doom_button_down(sdlToDoomButton(e.button.button));
|
||||
},
|
||||
sdl3_c.SDL_EVENT_MOUSE_BUTTON_UP => {
|
||||
c.doom_button_up(sdlToDoomButton(e.button.button));
|
||||
},
|
||||
sdl3_c.SDL_EVENT_KEY_DOWN => {
|
||||
if (!e.key.repeat) {
|
||||
c.doom_key_down(sdlToDoomScancode(e.key.scancode));
|
||||
}
|
||||
},
|
||||
sdl3_c.SDL_EVENT_KEY_UP => {
|
||||
if (!e.key.repeat) {
|
||||
c.doom_key_up(sdlToDoomScancode(e.key.scancode));
|
||||
}
|
||||
},
|
||||
switch (e.type) {
|
||||
else => {},
|
||||
sdl3_c.SDL_EVENT_MOUSE_MOTION => {
|
||||
c.doom_mouse_move(@intFromFloat(e.motion.xrel * 4 * ctx.sensitivity), @intFromFloat(e.motion.yrel * 4 * ctx.sensitivity));
|
||||
},
|
||||
sdl3_c.SDL_EVENT_MOUSE_BUTTON_DOWN => {
|
||||
c.doom_button_down(sdlToDoomButton(e.button.button));
|
||||
},
|
||||
sdl3_c.SDL_EVENT_MOUSE_BUTTON_UP => {
|
||||
c.doom_button_up(sdlToDoomButton(e.button.button));
|
||||
},
|
||||
sdl3_c.SDL_EVENT_KEY_DOWN => {
|
||||
if (!e.key.repeat) {
|
||||
c.doom_key_down(sdlToDoomScancode(e.key.scancode));
|
||||
}
|
||||
},
|
||||
sdl3_c.SDL_EVENT_KEY_UP => {
|
||||
if (!e.key.repeat) {
|
||||
c.doom_key_up(sdlToDoomScancode(e.key.scancode));
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -418,26 +477,6 @@ fn bindVideoTextures(p: ?*anyopaque) void {
|
|||
}
|
||||
|
||||
// creates a video player entity
|
||||
pub fn createEntity(self: *@This()) !core.Entity {
|
||||
const entity = try core.createEntity();
|
||||
const scene = entity.addComponent(core.Scene).?;
|
||||
const size = 5.0;
|
||||
const h: f32 = @floatFromInt(self.height);
|
||||
const w: f32 = @floatFromInt(self.width);
|
||||
|
||||
scene.setScale(size, size, size * (h / w));
|
||||
scene.setRotation(core.Rotation.eulerX(core.radians(90.0)));
|
||||
scene.setPosition(.{ .z = 30 });
|
||||
|
||||
if (entity.addComponent(rend.MeshComponent)) |mesh| {
|
||||
mesh.cmrf = bindVideoTextures;
|
||||
mesh.cmrf_ctx = self;
|
||||
mesh.textureMode.fullbright = true;
|
||||
mesh.textureMode.noSrgb = true;
|
||||
mesh.setMesh("m_plane");
|
||||
}
|
||||
return entity;
|
||||
}
|
||||
|
||||
pub fn destroy(self: *@This()) void {
|
||||
core.engine_logs("[Videoplayer] destroying player");
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ objectList: *core.GameObjectList,
|
|||
windowOpen: bool = true,
|
||||
spawnFuncs: std.ArrayListUnmanaged(SpawnEntry) = .{},
|
||||
spawnPosition: core.Vectorf = .{},
|
||||
spawnRotation: core.Rotation = .{},
|
||||
|
||||
pub const SpawnEntry = struct {
|
||||
typeName: []const u8,
|
||||
|
|
@ -44,6 +45,9 @@ pub fn addSpawnFunction(self: *@This(), comptime name: []const u8, comptime T: t
|
|||
pub fn prepareEntity(self: *@This(), entity: core.Entity) void {
|
||||
if (entity.fetch(core.Scene)) |scene| {
|
||||
scene.setPosition(self.spawnPosition);
|
||||
scene.setRotation(scene.getRotation().add(self.spawnRotation));
|
||||
|
||||
_ = scene.getAndResolveTransform();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -47,101 +47,110 @@ struct main0_in
|
|||
fragment main0_out main0(main0_in in [[stage_in]], constant type_Uniforms& Uniforms [[buffer(0)]], const device type_StructuredBuffer_Scene& scene [[buffer(1)]], texture2d<float> Texture0 [[texture(0)]], texture2d<float> Texture1 [[texture(1)]], texture2d<float> Texture2 [[texture(2)]], texture2d<float> DirectionalShadowDepthMap [[texture(3)]], sampler Sampler0 [[sampler(0)]], sampler Sampler1 [[sampler(1)]], sampler Sampler2 [[sampler(2)]], sampler DirectionalShadowSampler [[sampler(3)]])
|
||||
{
|
||||
main0_out out = {};
|
||||
int _98 = int(scene._m0[in.in_var_TEXCOORD4].textureMode);
|
||||
int _99 = _98 & 240;
|
||||
float4 _133;
|
||||
if (_99 == 16)
|
||||
int _97 = int(scene._m0[in.in_var_TEXCOORD4].textureMode);
|
||||
int _98 = _97 & 240;
|
||||
float4 _132;
|
||||
if (_98 == 16)
|
||||
{
|
||||
float3 _120 = float3(Texture0.sample(Sampler0, in.in_var_TEXCOORD0).x, Texture1.sample(Sampler1, in.in_var_TEXCOORD0).x, Texture2.sample(Sampler2, in.in_var_TEXCOORD0).x) + float3(-0.0625, -0.5, -0.5);
|
||||
_133 = float4(dot(_120, float3(1.164000034332275390625, 0.0, 1.7929999828338623046875)), dot(_120, float3(1.164000034332275390625, -0.212999999523162841796875, -0.53299999237060546875)), dot(_120, float3(1.164000034332275390625, 2.111999988555908203125, 0.0)), 1.0);
|
||||
float3 _119 = float3(Texture0.sample(Sampler0, in.in_var_TEXCOORD0).x, Texture1.sample(Sampler1, in.in_var_TEXCOORD0).x, Texture2.sample(Sampler2, in.in_var_TEXCOORD0).x) + float3(-0.0625, -0.5, -0.5);
|
||||
_132 = float4(dot(_119, float3(1.164000034332275390625, 0.0, 1.7929999828338623046875)), dot(_119, float3(1.164000034332275390625, -0.212999999523162841796875, -0.53299999237060546875)), dot(_119, float3(1.164000034332275390625, 2.111999988555908203125, 0.0)), 1.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
float4 _132;
|
||||
if (_99 == 0)
|
||||
float4 _131;
|
||||
if (_98 == 0)
|
||||
{
|
||||
_132 = Texture0.sample(Sampler0, in.in_var_TEXCOORD0);
|
||||
_131 = Texture0.sample(Sampler0, in.in_var_TEXCOORD0);
|
||||
}
|
||||
else
|
||||
{
|
||||
_132 = _86;
|
||||
_131 = _86;
|
||||
}
|
||||
_133 = _132;
|
||||
_132 = _131;
|
||||
}
|
||||
float4 _139;
|
||||
if ((_98 & 1) == 1)
|
||||
float4 _138;
|
||||
if ((_97 & 1) == 1)
|
||||
{
|
||||
_139 = powr(_133, float4(2.2000000476837158203125));
|
||||
_138 = powr(_132, float4(2.2000000476837158203125));
|
||||
}
|
||||
else
|
||||
{
|
||||
_139 = _133;
|
||||
_138 = _132;
|
||||
}
|
||||
if (_139.w < 0.00999999977648258209228515625)
|
||||
if (_138.w < 0.00999999977648258209228515625)
|
||||
{
|
||||
discard_fragment();
|
||||
}
|
||||
float3 _193;
|
||||
float3 _192;
|
||||
do
|
||||
{
|
||||
float3 _150 = Uniforms.lightPosition.xyz - in.in_var_TEXCOORD1;
|
||||
float _151 = length(_150);
|
||||
float _152 = _151 * _151;
|
||||
float _158;
|
||||
if (_151 > 2.0)
|
||||
float3 _149 = Uniforms.lightPosition.xyz - in.in_var_TEXCOORD1;
|
||||
float _150 = length(_149);
|
||||
float _151 = _150 * _150;
|
||||
float _157;
|
||||
if (_150 > 2.0)
|
||||
{
|
||||
_158 = 0.5 / _152;
|
||||
_157 = 0.5 / _151;
|
||||
}
|
||||
else
|
||||
{
|
||||
_158 = 1.0 / _152;
|
||||
_157 = 1.0 / _151;
|
||||
}
|
||||
float _163;
|
||||
if (_151 > 4.0)
|
||||
float _162;
|
||||
if (_150 > 4.0)
|
||||
{
|
||||
_163 = _158 * 0.5;
|
||||
_162 = _157 * 0.5;
|
||||
}
|
||||
else
|
||||
{
|
||||
_163 = _158;
|
||||
_162 = _157;
|
||||
}
|
||||
float _165 = (_151 > 15.0) ? 0.0 : _163;
|
||||
float _167 = (_165 > 1.0) ? 1.0 : _165;
|
||||
float _164 = (_150 > 15.0) ? 0.0 : _162;
|
||||
float _166 = (_164 > 1.0) ? 1.0 : _164;
|
||||
if (length(in.in_var_TEXCOORD2) < 0.100000001490116119384765625)
|
||||
{
|
||||
_193 = (in.in_var_TEXCOORD1 * float3(0.800000011920928955078125, 0.800000011920928955078125, 0.5)) * _167;
|
||||
_192 = (in.in_var_TEXCOORD1 * float3(0.800000011920928955078125, 0.800000011920928955078125, 0.5)) * _166;
|
||||
break;
|
||||
}
|
||||
float3 _174 = fast::normalize(_150);
|
||||
_193 = ((float3(0.800000011920928955078125, 0.800000011920928955078125, 0.5) * precise::max(dot(_174, in.in_var_TEXCOORD2), 0.0)) * _167) + (((float3(0.800000011920928955078125, 0.800000011920928955078125, 0.5) * powr(precise::max(dot(in.in_var_TEXCOORD2, fast::normalize(_174 + fast::normalize(in.in_var_TEXCOORD1 - Uniforms.viewPos.xyz))), 0.0), 30.0)) * 2.0) * _167);
|
||||
float3 _173 = fast::normalize(_149);
|
||||
_192 = ((float3(0.800000011920928955078125, 0.800000011920928955078125, 0.5) * precise::max(dot(_173, in.in_var_TEXCOORD2), 0.0)) * _166) + (((float3(0.800000011920928955078125, 0.800000011920928955078125, 0.5) * powr(precise::max(dot(in.in_var_TEXCOORD2, fast::normalize(_173 + fast::normalize(in.in_var_TEXCOORD1 - Uniforms.viewPos.xyz))), 0.0), 30.0)) * 2.0) * _166);
|
||||
break;
|
||||
} while(false);
|
||||
float3 _210 = ((in.in_var_TEXCOORD3.xyz / float3(in.in_var_TEXCOORD3.w)) * 0.5) + float3(0.5);
|
||||
float3 _212;
|
||||
_212.x = _210.x;
|
||||
float2 _213 = _212.xy;
|
||||
_213.y = -_210.y;
|
||||
float3 _209 = ((in.in_var_TEXCOORD3.xyz / float3(in.in_var_TEXCOORD3.w)) * 0.5) + float3(0.5);
|
||||
float3 _211;
|
||||
_211.x = _209.x;
|
||||
float2 _212 = _211.xy;
|
||||
_212.y = -_209.y;
|
||||
float _219;
|
||||
int _222;
|
||||
int _224;
|
||||
_219 = 0.0;
|
||||
_222 = 0;
|
||||
_224 = -4;
|
||||
float _220;
|
||||
int _223;
|
||||
int _225;
|
||||
_220 = 0.0;
|
||||
_223 = 0;
|
||||
_225 = -4;
|
||||
float _221;
|
||||
int _224;
|
||||
for (; _225 <= 4; _220 = _221, _223 = _224, _225++)
|
||||
for (; _224 <= 4; _219 = _220, _222 = _223, _224++)
|
||||
{
|
||||
_224 = _223;
|
||||
_221 = _220;
|
||||
for (int _234 = -4; _234 <= 4; )
|
||||
_223 = _222;
|
||||
_220 = _219;
|
||||
for (int _233 = -4; _233 <= 4; )
|
||||
{
|
||||
_224++;
|
||||
_221 += float((in.in_var_TEXCOORD3.z - 0.004999999888241291046142578125) > DirectionalShadowDepthMap.sample(DirectionalShadowSampler, (_213 + float2(float(_234) * 0.000244140625, float(_225) * 0.000244140625))).x);
|
||||
_234++;
|
||||
_223++;
|
||||
_220 += float((in.in_var_TEXCOORD3.z - 0.004999999888241291046142578125) > DirectionalShadowDepthMap.sample(DirectionalShadowSampler, (_212 + float2(float(_233) * 0.000244140625, float(_224) * 0.000244140625))).x);
|
||||
_233++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
out.out_var_SV_Target0 = float4(powr(select(_139.xyz * ((float3(0.100000001490116119384765625) + _193) + ((Uniforms.directionalLightColor.xyz * precise::max(dot(Uniforms.directionalLight.xyz, in.in_var_TEXCOORD2), 0.0)) * (1.0 - (_220 / float(_223))))), _139.xyz, bool3((_98 & 2) > 0)), float3(0.4545454680919647216796875)), _139.w);
|
||||
float3 _262;
|
||||
if ((_97 & 2) > 0)
|
||||
{
|
||||
_262 = _138.xyz * 4.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
_262 = _138.xyz * ((float3(0.100000001490116119384765625) + _192) + ((Uniforms.directionalLightColor.xyz * precise::max(dot(Uniforms.directionalLight.xyz, in.in_var_TEXCOORD2), 0.0)) * (1.0 - (_219 / float(_222)))));
|
||||
}
|
||||
out.out_var_SV_Target0 = float4(powr(_262, float3(0.4545454680919647216796875)), _138.w);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
#include <metal_stdlib>
|
||||
#include <simd/simd.h>
|
||||
|
||||
using namespace metal;
|
||||
|
||||
struct main0_out
|
||||
{
|
||||
float4 out_var_SV_Target0 [[color(0)]];
|
||||
};
|
||||
|
||||
struct main0_in
|
||||
{
|
||||
float2 in_var_TEXCOORD0 [[user(locn0)]];
|
||||
};
|
||||
|
||||
fragment main0_out main0(main0_in in [[stage_in]], texture2d<float> Texture0 [[texture(0)]], sampler Sampler0 [[sampler(0)]])
|
||||
{
|
||||
main0_out out = {};
|
||||
float2 _19 = in.in_var_TEXCOORD0;
|
||||
_19.y = -_19.y;
|
||||
out.out_var_SV_Target0 = Texture0.sample(Sampler0, _19);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
#include <metal_stdlib>
|
||||
#include <simd/simd.h>
|
||||
|
||||
using namespace metal;
|
||||
|
||||
struct main0_out
|
||||
{
|
||||
float2 out_var_TEXCOORD0 [[user(locn0)]];
|
||||
float4 gl_Position [[position]];
|
||||
};
|
||||
|
||||
struct main0_in
|
||||
{
|
||||
float3 in_var_TEXCOORD0 [[attribute(0)]];
|
||||
float2 in_var_TEXCOORD3 [[attribute(3)]];
|
||||
};
|
||||
|
||||
vertex main0_out main0(main0_in in [[stage_in]])
|
||||
{
|
||||
main0_out out = {};
|
||||
out.out_var_TEXCOORD0 = in.in_var_TEXCOORD3;
|
||||
out.gl_Position = float4(in.in_var_TEXCOORD0, 1.0);
|
||||
return out;
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -16,9 +16,7 @@ showWindow: bool = true,
|
|||
fpcamera: *FpCamera = undefined,
|
||||
|
||||
videoplayer: *VideoPlayer = undefined,
|
||||
doomplayer: *DoomPlayer = undefined,
|
||||
videoplayerObject: core.Entity = undefined,
|
||||
doomplayerObject: core.Entity = undefined,
|
||||
|
||||
objectSpawner: *extras.ObjectSpawner = undefined,
|
||||
|
||||
|
|
@ -119,15 +117,13 @@ pub fn prepare(self: *@This()) !void {
|
|||
|
||||
self.objectSpawner = try extras.ObjectSpawner.create(self.allocator);
|
||||
try self.objectSpawner.addSpawnFunction("fox", FoxObject);
|
||||
try self.objectSpawner.addSpawnFunction("doomplayer", DoomPlayer.DoomCanvas);
|
||||
|
||||
try assets.loadList(assetReferences);
|
||||
self.videoplayer = try VideoPlayer.create(self.allocator);
|
||||
try self.videoplayer.startPlayback("LAPWING2.ogv");
|
||||
self.videoplayerObject = try self.videoplayer.createVideoPlayerEntity();
|
||||
|
||||
self.doomplayer = try DoomPlayer.create(self.allocator);
|
||||
self.doomplayerObject = try self.doomplayer.createEntity();
|
||||
|
||||
rend.setSkyboxTexture("t_skybox");
|
||||
|
||||
const exitInput = try core.ActionBinding.create(core.MakeName("exit"));
|
||||
|
|
@ -158,26 +154,6 @@ pub fn prepare(self: *@This()) !void {
|
|||
empireMesh.setTexture("t_empire");
|
||||
}
|
||||
|
||||
{
|
||||
// const fox = try core.createEntity();
|
||||
// const scene = fox.addComponent(core.Scene).?;
|
||||
// _ = scene;
|
||||
// // scene.setScale();
|
||||
// const mesh = fox.addComponent(rend.MeshComponent).?;
|
||||
// mesh.setMesh("m_fox");
|
||||
// mesh.setTexture("t_fox");
|
||||
}
|
||||
|
||||
{
|
||||
// const lightbox = try core.createEntity();
|
||||
// const scene = lightbox.addComponent(core.Scene).?;
|
||||
// scene.setPosition(.{ .z = 20 });
|
||||
// scene.setScale(0.1, 0.1, 0.1);
|
||||
// const mesh = lightbox.addComponent(rend.MeshComponent).?;
|
||||
// mesh.setMesh("m_default_cube");
|
||||
// mesh.setTexture("t_default");
|
||||
}
|
||||
|
||||
const moveInput = try core.Axis2dBinding.create(core.MakeName("movement"));
|
||||
|
||||
moveInput.addKey(.w, 1.0, .y);
|
||||
|
|
@ -248,8 +224,11 @@ fn toggleDoom(ctx: ?*anyopaque, action: core.ActionEvent) void {
|
|||
const self: *@This() = @ptrCast(@alignCast(ctx));
|
||||
_ = action;
|
||||
|
||||
self.doomplayer.inputEnabled = !self.doomplayer.inputEnabled;
|
||||
self.inputEnabled = !self.doomplayer.inputEnabled;
|
||||
self.inputEnabled = !self.inputEnabled;
|
||||
|
||||
if (DoomPlayer.gDoom) |c| {
|
||||
c.inputEnabled = !self.inputEnabled;
|
||||
}
|
||||
}
|
||||
|
||||
fn toggleMouseLook(ctx: ?*anyopaque, action: core.ActionEvent) void {
|
||||
|
|
@ -328,7 +307,6 @@ pub fn tick(self: *@This(), dt: f64) void {
|
|||
extras.inputDebugger.tick();
|
||||
self.objectSpawner.tick(dt);
|
||||
self.videoplayer.tick(dt);
|
||||
self.doomplayer.tick(dt);
|
||||
self.fpcamera.tick(dt);
|
||||
|
||||
var movement = self.fpcamera.getForwardXZ().fmul(self.moveVector.z * fdt * self.cameraSpeed);
|
||||
|
|
@ -347,6 +325,7 @@ pub fn tick(self: *@This(), dt: f64) void {
|
|||
const forward = self.fpcamera.getForward();
|
||||
const debugCenter = self.fpcamera.getPosition().add(forward.fmul(self.centerDist));
|
||||
self.objectSpawner.spawnPosition = debugCenter;
|
||||
self.objectSpawner.spawnRotation = core.Rotation.eulerY(core.radians(self.fpcamera.yaw));
|
||||
|
||||
if (self.moveLight) {
|
||||
core.debugSphere(debugCenter, 0.3, .{});
|
||||
|
|
@ -376,7 +355,7 @@ pub fn tick(self: *@This(), dt: f64) void {
|
|||
}
|
||||
|
||||
pub fn deinit(self: *@This()) void {
|
||||
self.doomplayer.destroy();
|
||||
// self.doomplayer.destroy();
|
||||
self.fpcamera.destroy();
|
||||
|
||||
self.objectSpawner.destroy();
|
||||
|
|
|
|||
Loading…
Reference in New Issue