created particle system
This commit is contained in:
parent
d42db622e7
commit
bba99d4d91
|
|
@ -9,6 +9,15 @@ const lua = @import("lua");
|
||||||
const pod = lua.pod;
|
const pod = lua.pod;
|
||||||
// LUA END
|
// LUA END
|
||||||
|
|
||||||
|
// vector versions.
|
||||||
|
pub const f32x4 = @Vector(4, f32);
|
||||||
|
pub const f32x8 = @Vector(8, f32);
|
||||||
|
pub const f32x16 = @Vector(16, f32);
|
||||||
|
|
||||||
|
pub const f32x4_zero = std.mem.zeroes(@Vector(4, f32));
|
||||||
|
pub const f32x8_zero = std.mem.zeroes(@Vector(8, f32));
|
||||||
|
pub const f32x16_zero = std.mem.zeroes(@Vector(16, f32));
|
||||||
|
|
||||||
pub const Rayf = RayType(Vectorf);
|
pub const Rayf = RayType(Vectorf);
|
||||||
|
|
||||||
pub fn matToScalef(mat: anytype) Vectorf {
|
pub fn matToScalef(mat: anytype) Vectorf {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,335 @@
|
||||||
|
// particle system
|
||||||
|
//
|
||||||
|
// last one we need to implement is a ParticleComposite,
|
||||||
|
// this is a component which owns a particle emitter component (adding one if it does not exist)
|
||||||
|
//
|
||||||
|
// and generates/modifies particles system properties over time.
|
||||||
|
//
|
||||||
|
// just thinking... with meta reflection. I wonder if it is possible to codegen
|
||||||
|
// a generic "timeline" runner capable of modifying any arbitrary float, bool etc... over time.
|
||||||
|
//
|
||||||
|
// that could be
|
||||||
|
|
||||||
|
pub const EmitterState = enum {
|
||||||
|
dead, // emitter is not creating any particles
|
||||||
|
alive, // emitter is creating particles up to max_porticles
|
||||||
|
paused, // emitter is not updating
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const ParticleRandRangef = struct {
|
||||||
|
min: f32 = 0,
|
||||||
|
max: f32 = 0,
|
||||||
|
|
||||||
|
pub var randomFunc: std.Random = undefined;
|
||||||
|
pub var randomEngine: std.Random.DefaultPrng = undefined;
|
||||||
|
|
||||||
|
pub fn set(self: *@This(), v: f32) void {
|
||||||
|
self.min = v;
|
||||||
|
self.max = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getRange(self: @This()) f32 {
|
||||||
|
if (std.math.approxEqAbs(f32, self.min, self.max, 0.0001))
|
||||||
|
return self.min;
|
||||||
|
|
||||||
|
const x = (randomFunc.float(f32) +
|
||||||
|
randomFunc.float(f32) +
|
||||||
|
randomFunc.float(f32) +
|
||||||
|
randomFunc.float(f32)) / 4;
|
||||||
|
|
||||||
|
return x * (self.max - self.min) + self.min;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const EmitterShape = union(enum(u8)) {
|
||||||
|
spherical: struct {
|
||||||
|
radius: f32 = 50.0,
|
||||||
|
innerRadius: f32 = 0,
|
||||||
|
// distrobution: =
|
||||||
|
},
|
||||||
|
conal: struct {
|
||||||
|
direction: core.Vectorf,
|
||||||
|
angle: f32,
|
||||||
|
innerRadius: f32 = 0,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Life = struct {
|
||||||
|
current: f32,
|
||||||
|
max: f32,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const ParticlePVA = struct {
|
||||||
|
position: core.f32x4 = core.f32x4_zero,
|
||||||
|
velocity: core.f32x4 = core.f32x4_zero,
|
||||||
|
acceleration: core.f32x4 = core.f32x4_zero,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Rotationals = struct {
|
||||||
|
quat: core.f32x4 = .{},
|
||||||
|
spinVector: core.f32x4 = .{},
|
||||||
|
angularMomentum: f32 = 0.0,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const RenderInfo = struct {
|
||||||
|
meshIndex: u32 = 0,
|
||||||
|
textureIndex: u32 = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const ParticleEmitter = struct {
|
||||||
|
pub var BaseContainer: *core.SparseSet(ParticleEmitter) = undefined;
|
||||||
|
pub const ComponentName = "ParticleEmitter";
|
||||||
|
pub const ScriptExports: []const []const u8 = &.{};
|
||||||
|
|
||||||
|
// per particle information
|
||||||
|
life: std.ArrayListUnmanaged(Life) = .{},
|
||||||
|
particlesPVA: std.ArrayListUnmanaged(ParticlePVA) = .{},
|
||||||
|
finals: std.ArrayListUnmanaged(core.Mat) = .{},
|
||||||
|
renderInfo: std.ArrayListUnmanaged(RenderInfo) = .{},
|
||||||
|
|
||||||
|
particleAcceleration: ParticleRandRangef = .{ .min = 0.0, .max = 0.0 },
|
||||||
|
particleVelocity: ParticleRandRangef = .{ .min = 8, .max = 10 },
|
||||||
|
particleLife: ParticleRandRangef = .{ .min = 2, .max = 2 },
|
||||||
|
|
||||||
|
spawnRate: ParticleRandRangef = .{ .min = 10, .max = 10 },
|
||||||
|
nextSpawn: f64 = 0.0,
|
||||||
|
|
||||||
|
gravity: ?core.Vectorf = null,
|
||||||
|
maxParticles: u32 = 100,
|
||||||
|
|
||||||
|
// globalScale: f32 = 1.0, not implemented
|
||||||
|
|
||||||
|
state: EmitterState = .dead,
|
||||||
|
billboard: bool = true,
|
||||||
|
|
||||||
|
// if billboard is set, the billboard bit will be set
|
||||||
|
// and only position and scale will be used to render the particle.
|
||||||
|
|
||||||
|
// an empty list means that this will use quad_mesh
|
||||||
|
mesh: std.ArrayListUnmanaged(rend.IndexedMesh) = .{},
|
||||||
|
|
||||||
|
// empty list means will use t_white
|
||||||
|
texture: std.ArrayListUnmanaged(*rend.Texture) = .{},
|
||||||
|
|
||||||
|
emitterLife: f64 = 0.0, // 0.0 means this emitter lives forever.
|
||||||
|
emitterMaxLife: f64 = 0.0,
|
||||||
|
emitterShape: EmitterShape = .{ .spherical = .{} },
|
||||||
|
|
||||||
|
_showDebug: bool = false,
|
||||||
|
|
||||||
|
entity: core.Entity = undefined,
|
||||||
|
|
||||||
|
pub fn updatePVA(self: *@This(), dt: f64) void {
|
||||||
|
// should generate SIMD operations
|
||||||
|
|
||||||
|
const gravity = if (self.gravity) |gravity| gravity.toZm() else core.f32x4_zero;
|
||||||
|
|
||||||
|
for (self.particlesPVA.items) |*pva| {
|
||||||
|
pva.velocity = pva.acceleration * @as(core.f32x4, @splat(@floatCast(dt))) + gravity * @as(core.f32x4, @splat(@floatCast(dt))) + pva.velocity;
|
||||||
|
pva.position = pva.velocity * @as(core.f32x4, @splat(@floatCast(dt))) + pva.position;
|
||||||
|
if (self._showDebug) {
|
||||||
|
core.debugSphere(core.Vectorf.fromArray(pva.position), 0.1, .{ .color = .{ .y = 1.0, .x = positionLength(pva.velocity) / 10 } });
|
||||||
|
// core.debugSphere(core.Vectorf.Zeroes, 0.1, .{});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fn positionLength(f: core.f32x4) f32 {
|
||||||
|
return @sqrt((f[0] * f[0]) + (f[1] * f[1]) + (f[2] * f[2]) + (f[3] * f[3]));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn updateParticleLife(self: *@This(), dt: f64) void {
|
||||||
|
// should generate SIMD operations
|
||||||
|
const dt32: f32 = @floatCast(dt);
|
||||||
|
|
||||||
|
for (self.life.items) |*life| {
|
||||||
|
if (life.max > 0)
|
||||||
|
life.current -= dt32;
|
||||||
|
}
|
||||||
|
|
||||||
|
var i: usize = 0;
|
||||||
|
while (i < self.life.items.len) : (i += 1) {
|
||||||
|
if (self.life.items[i].current < 0) {
|
||||||
|
self.removeParticle(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (self.emitterShape) {
|
||||||
|
.spherical => |spherical| {
|
||||||
|
i = 0;
|
||||||
|
while (i < self.particlesPVA.items.len) : (i += 1) {
|
||||||
|
if (positionLength(self.particlesPVA.items[i].position) > spherical.radius) {
|
||||||
|
self.removeParticle(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.conal => {
|
||||||
|
@panic("not implemented");
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn removeParticle(self: *@This(), i: usize) void {
|
||||||
|
_ = self.life.swapRemove(i);
|
||||||
|
_ = self.particlesPVA.swapRemove(i);
|
||||||
|
_ = self.finals.swapRemove(i);
|
||||||
|
_ = self.renderInfo.swapRemove(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn updateSpawn(self: *@This(), dt: f64) void {
|
||||||
|
self.nextSpawn -= dt;
|
||||||
|
|
||||||
|
if (self.nextSpawn > 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self.nextSpawn < 0 and self.life.items.len >= self.maxParticles) {
|
||||||
|
self.nextSpawn = 0.0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (self.nextSpawn < 0) {
|
||||||
|
self.spawnParticle() catch {
|
||||||
|
core.engine_err(" UNABLE TO SPAWN PARTICLE", .{});
|
||||||
|
};
|
||||||
|
|
||||||
|
// generate random values for the next spawn
|
||||||
|
self.nextSpawn += 1.0 / @as(f64, @floatCast(self.spawnRate.getRange()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn start(self: *@This()) void {
|
||||||
|
self.state = .alive;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generatePVA(self: *@This()) ParticlePVA {
|
||||||
|
switch (self.emitterShape) {
|
||||||
|
.spherical => |spherical| {
|
||||||
|
const radius = ParticleRandRangef{ .min = -spherical.innerRadius, .max = spherical.innerRadius };
|
||||||
|
|
||||||
|
const oneRand = ParticleRandRangef{ .min = -1.0, .max = 1.0 };
|
||||||
|
const v = core.Vectorf{ .x = oneRand.getRange(), .y = oneRand.getRange(), .z = oneRand.getRange() };
|
||||||
|
const v2 = v.normalize();
|
||||||
|
|
||||||
|
const pva: ParticlePVA = .{
|
||||||
|
.velocity = v2.fmul(self.particleVelocity.getRange()).toZm(),
|
||||||
|
.position = .{
|
||||||
|
radius.getRange(),
|
||||||
|
radius.getRange(),
|
||||||
|
radius.getRange(),
|
||||||
|
1.0,
|
||||||
|
},
|
||||||
|
.acceleration = v2.fmul(self.particleAcceleration.getRange()).toZm(),
|
||||||
|
};
|
||||||
|
return pva;
|
||||||
|
},
|
||||||
|
.conal => |conal| {
|
||||||
|
_ = conal;
|
||||||
|
@panic("not implemented");
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn spawnParticle(self: *@This()) !void {
|
||||||
|
const pva = self.generatePVA();
|
||||||
|
|
||||||
|
const life = self.particleLife.getRange();
|
||||||
|
try self.life.append(gParticleAllocator, .{ .current = life, .max = life });
|
||||||
|
|
||||||
|
try self.particlesPVA.append(gParticleAllocator, pva);
|
||||||
|
|
||||||
|
// renderinfo not used rn
|
||||||
|
try self.renderInfo.append(gParticleAllocator, .{});
|
||||||
|
try self.finals.append(gParticleAllocator, std.mem.zeroes(core.Mat));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn updateLife(self: *@This(), dt: f64) void {
|
||||||
|
if (self.emitterMaxLife <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.emitterLife -= dt;
|
||||||
|
if (self.emitterLife <= 0) {
|
||||||
|
self.state = .dead;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update(self: *@This(), dt: f64) void {
|
||||||
|
if (self.state != .dead) {
|
||||||
|
self.updateSpawn(dt);
|
||||||
|
}
|
||||||
|
|
||||||
|
// core.debugSphere(self.entity.fetch(core.Scene).?.getPosition(), self.emitterShape.spherical.radius, .{});
|
||||||
|
|
||||||
|
self.updatePVA(dt);
|
||||||
|
self.updateParticleLife(dt);
|
||||||
|
self.updateLife(dt);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn initECS(self: *@This(), handle: core.SetHandle) void {
|
||||||
|
// get the mesh component
|
||||||
|
self.entity = core.Entity{ .handle = handle };
|
||||||
|
|
||||||
|
if (self.entity.fetch(core.Scene)) |scene| {
|
||||||
|
_ = scene;
|
||||||
|
} else {
|
||||||
|
_ = self.entity.addComponent(core.Scene);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *@This()) void {
|
||||||
|
_ = self;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var gParticleAllocator: std.mem.Allocator = undefined;
|
||||||
|
|
||||||
|
pub const Effect = struct {};
|
||||||
|
|
||||||
|
pub const ParticleSystem = struct {
|
||||||
|
particleArena: std.heap.ArenaAllocator,
|
||||||
|
allocator: std.mem.Allocator,
|
||||||
|
|
||||||
|
pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This(), "rend.ParticleSystem");
|
||||||
|
|
||||||
|
pub fn create(allocator: std.mem.Allocator) !*@This() {
|
||||||
|
const self = try allocator.create(@This());
|
||||||
|
|
||||||
|
self.* = .{
|
||||||
|
.particleArena = std.heap.ArenaAllocator.init(allocator),
|
||||||
|
.allocator = allocator,
|
||||||
|
};
|
||||||
|
|
||||||
|
gParticleAllocator = self.particleArena.allocator();
|
||||||
|
|
||||||
|
ParticleRandRangef.randomEngine = std.Random.DefaultPrng.init(0x1234);
|
||||||
|
ParticleRandRangef.randomFunc = ParticleRandRangef.randomEngine.random();
|
||||||
|
|
||||||
|
try core.defineComponent(ParticleEmitter, allocator);
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tick(self: *@This(), dt: f64) void {
|
||||||
|
var z = tracy.ZoneN(@src(), "Particle System");
|
||||||
|
defer z.End();
|
||||||
|
|
||||||
|
_ = self;
|
||||||
|
|
||||||
|
for (ParticleEmitter.BaseContainer.dense.items) |*emitter| {
|
||||||
|
emitter.value.update(dt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn destroy(self: *@This()) void {
|
||||||
|
core.undefineComponent(ParticleEmitter);
|
||||||
|
|
||||||
|
self.particleArena.deinit();
|
||||||
|
self.allocator.destroy(self);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const core = @import("core");
|
||||||
|
const rend = @import("../rend.zig");
|
||||||
|
const std = @import("std");
|
||||||
|
const tracy = core.tracy;
|
||||||
|
|
@ -44,6 +44,11 @@ pub const Animator = animationSystem.Animator;
|
||||||
|
|
||||||
pub const setSkyboxTexture = renderer.setSkyboxTexture;
|
pub const setSkyboxTexture = renderer.setSkyboxTexture;
|
||||||
|
|
||||||
|
pub const particles = @import("particles/particles.zig");
|
||||||
|
|
||||||
|
pub const ParticleSystem = particles.ParticleSystem;
|
||||||
|
pub const ParticleEmitter = particles.ParticleEmitter;
|
||||||
|
|
||||||
var rendAllocator: std.mem.Allocator = undefined;
|
var rendAllocator: std.mem.Allocator = undefined;
|
||||||
pub fn getAllocator() std.mem.Allocator {
|
pub fn getAllocator() std.mem.Allocator {
|
||||||
return rendAllocator;
|
return rendAllocator;
|
||||||
|
|
@ -66,6 +71,7 @@ pub fn start_module(spec: *core.SpecVariantMap, args: anytype, allocator: std.me
|
||||||
try renderer.start();
|
try renderer.start();
|
||||||
|
|
||||||
_ = try context().createRendererEngineObject(animationSystem.AnimationSystem);
|
_ = try context().createRendererEngineObject(animationSystem.AnimationSystem);
|
||||||
|
_ = try context().createRendererEngineObject(particles.ParticleSystem);
|
||||||
|
|
||||||
try animationLoaders.initLoaders();
|
try animationLoaders.initLoaders();
|
||||||
try core.defineComponentList(ComponentList, allocator);
|
try core.defineComponentList(ComponentList, allocator);
|
||||||
|
|
|
||||||
|
|
@ -1092,6 +1092,7 @@ pub fn registerRendererObject(comptime T: type, object: *anyopaque) !void {
|
||||||
|
|
||||||
pub fn setSkyboxTexture(name: []const u8) void {
|
pub fn setSkyboxTexture(name: []const u8) void {
|
||||||
context().skyboxSystem.skyboxTextureName = core.MakeName(name);
|
context().skyboxSystem.skyboxTextureName = core.MakeName(name);
|
||||||
|
context().skyboxSystem.skyboxTexture = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const getMesh = mesh_pool.getMesh;
|
pub const getMesh = mesh_pool.getMesh;
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@ allocator: std.mem.Allocator,
|
||||||
directionalLightSettings: bool = false,
|
directionalLightSettings: bool = false,
|
||||||
ssaoSettings: bool = false,
|
ssaoSettings: bool = false,
|
||||||
|
|
||||||
|
skyboxes: std.ArrayListUnmanaged(core.Name) = .{},
|
||||||
|
|
||||||
pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This(), "extras.RendererDebug");
|
pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This(), "extras.RendererDebug");
|
||||||
|
|
||||||
pub fn create(allocator: std.mem.Allocator) !*@This() {
|
pub fn create(allocator: std.mem.Allocator) !*@This() {
|
||||||
|
|
@ -52,11 +54,24 @@ pub fn windowOpen(entry: *igu.MenuEntry, dt: f64) void {
|
||||||
_ = ig.sliderFloat("bias", &ssao.bias, 0.0025, 1.0, null, .{});
|
_ = ig.sliderFloat("bias", &ssao.bias, 0.0025, 1.0, null, .{});
|
||||||
_ = ig.checkbox("enable SSAO", &ssao.enable);
|
_ = ig.checkbox("enable SSAO", &ssao.enable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var buffer: [256]u8 = undefined;
|
||||||
|
|
||||||
|
ig.textFmt("skyboxes", .{}) catch unreachable;
|
||||||
|
ig.separator();
|
||||||
|
|
||||||
|
for (self.skyboxes.items) |*name| {
|
||||||
|
const x = std.fmt.bufPrintZ(&buffer, "{s}##button", .{name.utf8()}) catch unreachable;
|
||||||
|
if (ig.smallButton(x)) {
|
||||||
|
rend.setSkyboxTexture(name.utf8());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ig.end();
|
ig.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn destroy(self: *@This()) void {
|
pub fn destroy(self: *@This()) void {
|
||||||
|
self.skyboxes.deinit(self.allocator);
|
||||||
self.allocator.destroy(self);
|
self.allocator.destroy(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 868 B |
|
|
@ -54,6 +54,8 @@ pub const ExternGameObject = struct {
|
||||||
a: bool = false,
|
a: bool = false,
|
||||||
// lib: bool = false,
|
// lib: bool = false,
|
||||||
//s: u32 = 0x42,
|
//s: u32 = 0x42,
|
||||||
|
editParticle: ?core.Entity = null,
|
||||||
|
savedGravity: core.Vectorf = .{},
|
||||||
|
|
||||||
pub fn loadMap2(self: *@This()) !void {
|
pub fn loadMap2(self: *@This()) !void {
|
||||||
if (self.tbMap) |tbMap| {
|
if (self.tbMap) |tbMap| {
|
||||||
|
|
@ -69,6 +71,81 @@ pub const ExternGameObject = struct {
|
||||||
core.engine_log("map loaded", .{});
|
core.engine_log("map loaded", .{});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ItemWidth = 80;
|
||||||
|
|
||||||
|
pub fn displayRandRangeImgui(comptime Name: []const u8, range: *rend.particles.ParticleRandRangef) void {
|
||||||
|
ig.textFmt(Name, .{}) catch {};
|
||||||
|
ig.sameLine(0, 10);
|
||||||
|
ig.setNextItemWidth(ItemWidth);
|
||||||
|
_ = ig.inputFloat("Min##particleEd" ++ Name, &range.min, 1.0, 5.0, null, .{});
|
||||||
|
ig.sameLine(0, 10);
|
||||||
|
ig.setNextItemWidth(ItemWidth);
|
||||||
|
_ = ig.inputFloat("Max##particleEd" ++ Name, &range.max, 1.0, 5.0, null, .{});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn editVector(comptime Name: []const u8, range: *core.Vectorf) void {
|
||||||
|
ig.textFmt(Name, .{}) catch {};
|
||||||
|
ig.sameLine(0, 10);
|
||||||
|
ig.setNextItemWidth(ItemWidth);
|
||||||
|
_ = ig.inputFloat("X##particleEd" ++ Name, &range.x, 1.0, 5.0, null, .{});
|
||||||
|
ig.sameLine(0, 10);
|
||||||
|
ig.setNextItemWidth(ItemWidth);
|
||||||
|
_ = ig.inputFloat("Y##particleEd" ++ Name, &range.y, 1.0, 5.0, null, .{});
|
||||||
|
ig.sameLine(0, 10);
|
||||||
|
ig.setNextItemWidth(ItemWidth);
|
||||||
|
_ = ig.inputFloat("Z##particleEd" ++ Name, &range.z, 1.0, 5.0, null, .{});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn particleDebug(self: *@This()) void {
|
||||||
|
if (ig.begin("particleDebugger", null, .{})) {
|
||||||
|
var buffer: [256]u8 = undefined;
|
||||||
|
for (rend.ParticleEmitter.BaseContainer.dense.items, 0..) |*emitter, i| {
|
||||||
|
ig.textFmt("emitter {d}", .{emitter.sparseIndex.index}) catch {};
|
||||||
|
if (ig.smallButton(std.fmt.bufPrintZ(&buffer, "edit##{d}", .{i}) catch unreachable)) {
|
||||||
|
self.editParticle = emitter.value.entity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ig.end();
|
||||||
|
|
||||||
|
var checkbox: bool = true;
|
||||||
|
|
||||||
|
if (self.editParticle) |edit| {
|
||||||
|
if (edit.fetch(rend.ParticleEmitter)) |emitter| {
|
||||||
|
if (ig.begin("editParticle", null, .{})) {
|
||||||
|
displayRandRangeImgui("Acceleration", &emitter.particleAcceleration);
|
||||||
|
displayRandRangeImgui("Velocity", &emitter.particleVelocity);
|
||||||
|
displayRandRangeImgui("Life", &emitter.particleLife);
|
||||||
|
displayRandRangeImgui("spawnRate", &emitter.spawnRate);
|
||||||
|
|
||||||
|
if (emitter.gravity != null) {
|
||||||
|
checkbox = true;
|
||||||
|
} else {
|
||||||
|
checkbox = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ig.checkbox("hasGravity", &checkbox)) {
|
||||||
|
if (!checkbox) {
|
||||||
|
self.savedGravity = emitter.gravity.?;
|
||||||
|
emitter.gravity = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (checkbox) {
|
||||||
|
emitter.gravity = self.savedGravity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (emitter.gravity != null) {
|
||||||
|
editVector("gravity", &emitter.gravity.?);
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = ig.inputInt("maaxParticles##particleEd", @ptrCast(&emitter.maxParticles), 1, 5, .{});
|
||||||
|
}
|
||||||
|
ig.end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn create(allocator: std.mem.Allocator) !*@This() {
|
pub fn create(allocator: std.mem.Allocator) !*@This() {
|
||||||
const self = try Slack.create(allocator);
|
const self = try Slack.create(allocator);
|
||||||
self.* = .{
|
self.* = .{
|
||||||
|
|
@ -220,6 +297,7 @@ pub const ExternGameObject = struct {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
self.particleDebug();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,27 @@ const assetReferences = [_]assets.AssetImportReference{
|
||||||
"m_crate",
|
"m_crate",
|
||||||
.{ .path = "meshes/Crate.obj" },
|
.{ .path = "meshes/Crate.obj" },
|
||||||
),
|
),
|
||||||
|
assets.MakeImportRefOptions(
|
||||||
|
"Texture",
|
||||||
|
"t_dark_skybox",
|
||||||
|
.{
|
||||||
|
.textureCube = true,
|
||||||
|
.textureList = &.{
|
||||||
|
"textures/DarkGrey.png", // cubemapfacePositivex, right
|
||||||
|
"textures/DarkGrey.png", // cubemapfacePositivex, right
|
||||||
|
"textures/DarkGrey.png", // cubemapfacePositivex, right
|
||||||
|
"textures/DarkGrey.png", // cubemapfacePositivex, right
|
||||||
|
"textures/DarkGrey.png", // cubemapfacePositivex, right
|
||||||
|
"textures/DarkGrey.png", // cubemapfacePositivex, right
|
||||||
|
//"sky_air/cube_right.png", // cubemapfacePositivex, right
|
||||||
|
//"sky_air/cube_left.png", // cubemapfacePositivex, right
|
||||||
|
//"sky_air/cube_up.png", // cubemapfacePositivex, right
|
||||||
|
//"sky_air/cube_down.png", // cubemapfacePositivex, right
|
||||||
|
//"sky_air/cube_back.png", // cubemapfacePositivex, right
|
||||||
|
//"sky_air/cube_front.png", // cubemapfacePositivex, right
|
||||||
|
},
|
||||||
|
},
|
||||||
|
),
|
||||||
assets.MakeImportRefOptions(
|
assets.MakeImportRefOptions(
|
||||||
"Texture",
|
"Texture",
|
||||||
"t_skybox",
|
"t_skybox",
|
||||||
|
|
@ -93,6 +114,34 @@ const assetReferences = [_]assets.AssetImportReference{
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const ParticleObject = struct {
|
||||||
|
data: core.GameObjectData = undefined,
|
||||||
|
entity: core.Entity,
|
||||||
|
|
||||||
|
pub fn create(alloc: std.mem.Allocator) !*@This() {
|
||||||
|
const self = try alloc.create(@This());
|
||||||
|
const e = try core.createEntity();
|
||||||
|
|
||||||
|
const particle = e.addComponent(rend.ParticleEmitter).?;
|
||||||
|
particle._showDebug = true;
|
||||||
|
particle.start();
|
||||||
|
particle.gravity = .{ .y = -9.8 };
|
||||||
|
|
||||||
|
self.entity = e;
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getEntity(self: *@This()) core.Entity {
|
||||||
|
return self.entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn destroy(self: *@This()) void {
|
||||||
|
self.entity.destroy();
|
||||||
|
self.data.release(self);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
pub const FoxObject = struct {
|
pub const FoxObject = struct {
|
||||||
data: core.GameObjectData = undefined,
|
data: core.GameObjectData = undefined,
|
||||||
entity: core.Entity,
|
entity: core.Entity,
|
||||||
|
|
@ -106,6 +155,7 @@ pub const FoxObject = struct {
|
||||||
const mesh = fox.addComponent(rend.MeshComponent).?;
|
const mesh = fox.addComponent(rend.MeshComponent).?;
|
||||||
mesh.setMesh("m_fox");
|
mesh.setMesh("m_fox");
|
||||||
mesh.setTexture("t_fox");
|
mesh.setTexture("t_fox");
|
||||||
|
|
||||||
const animator = fox.addComponent(rend.Animator).?;
|
const animator = fox.addComponent(rend.Animator).?;
|
||||||
animator.setSkeleton("sk_fox");
|
animator.setSkeleton("sk_fox");
|
||||||
animator.setAnimation("a_fox_survey");
|
animator.setAnimation("a_fox_survey");
|
||||||
|
|
@ -187,11 +237,14 @@ pub fn prepare(self: *@This()) !void {
|
||||||
// try self.tryLoadExtern("externGame");
|
// try self.tryLoadExtern("externGame");
|
||||||
|
|
||||||
// self.rendererDebugger = try extras.RendererDebug.create(self.allocator); //try core.createObject(extras.RendererDebug, .{});
|
// self.rendererDebugger = try extras.RendererDebug.create(self.allocator); //try core.createObject(extras.RendererDebug, .{});
|
||||||
_ = try core.createObject(extras.RendererDebug, .{});
|
const rendererDebug = try core.createObject(extras.RendererDebug, .{});
|
||||||
|
try rendererDebug.skyboxes.append(rendererDebug.allocator, core.MakeName("t_skybox"));
|
||||||
|
try rendererDebug.skyboxes.append(rendererDebug.allocator, core.MakeName("t_dark_skybox"));
|
||||||
|
|
||||||
//self.objectSpawner = try extras.ObjectSpawner.create(self.allocator);
|
//self.objectSpawner = try extras.ObjectSpawner.create(self.allocator);
|
||||||
self.objectSpawner = try core.createObject(extras.ObjectSpawner, .{});
|
self.objectSpawner = try core.createObject(extras.ObjectSpawner, .{});
|
||||||
try self.objectSpawner.addSpawnFunction("fox", FoxObject);
|
try self.objectSpawner.addSpawnFunction("fox", FoxObject);
|
||||||
|
try self.objectSpawner.addSpawnFunction("particle", ParticleObject);
|
||||||
try self.objectSpawner.addSpawnFunction("doomplayer", DoomPlayer.DoomCanvas);
|
try self.objectSpawner.addSpawnFunction("doomplayer", DoomPlayer.DoomCanvas);
|
||||||
try self.objectSpawner.addSpawnFunction("empire", @import("empire.zig"));
|
try self.objectSpawner.addSpawnFunction("empire", @import("empire.zig"));
|
||||||
try self.objectSpawner.addSpawnFunction("DamagedHelmet", DamagedHelmet);
|
try self.objectSpawner.addSpawnFunction("DamagedHelmet", DamagedHelmet);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue