diff --git a/assets/Data/entity/objects.json b/assets/Data/entity/objects.json index 187afe01..280dba49 100644 --- a/assets/Data/entity/objects.json +++ b/assets/Data/entity/objects.json @@ -6,6 +6,7 @@ "Data/entity/objects/testscene1objects.json", "Data/entity/objects/debug_objects.json", "Data/entity/objects/game_objects.json", - "Data/entity/objects/containers.json" + "Data/entity/objects/containers.json", + "Data/entity/objects/furniture.json" ] } \ No newline at end of file diff --git a/assets/Data/entity/objects/furniture.json b/assets/Data/entity/objects/furniture.json new file mode 100644 index 00000000..772c55dc --- /dev/null +++ b/assets/Data/entity/objects/furniture.json @@ -0,0 +1,58 @@ +{ + "objects" : [ + { + "id" : "Torch", + "particleEmitter": { + "maxLife": 20, + "lifeCurrent": 0, + "particleVelocity": { + "x": 0.0, + "y": 0.02, + "z": 0.0 + }, + "acceleration": -0.0001, + "texture": "flame_05.png", + "size": 0.3, + "color": { + "x": 0.83, + "y": 0.6, + "z": 0.09 + }, + "offset": { + "x": 0, + "y": 1.2, + "z": 0 + }, + "radialAcceleration": 0.0001, + "transparency": { + "constant": 1, + "linear": 0, + "quadratic": -1 + }, + "spread": 15, + "frequency": 2 + }, + "pointLight" : { + "const": 1.0, + "linear": 0.9, + "quadratic": 0.9, + "radius": 3.0, + "color": { + "x": 0.83, + "y": 0.6, + "z": 0.09 + }, + "offset": { + "x": 0.0, + "y": 1.1, + "z": 0.0 + } + }, + "modelPath" : "Models/objects/furniture/torch1.glb", + "tokens": [ + ] + } + + ], + "files" : [] +} \ No newline at end of file diff --git a/assets/Data/entity/objects/game_objects.json b/assets/Data/entity/objects/game_objects.json index 76a619b2..b6b25409 100644 --- a/assets/Data/entity/objects/game_objects.json +++ b/assets/Data/entity/objects/game_objects.json @@ -9,23 +9,35 @@ ] }, { - "id" : "particleEmitterTest", + "id" : "flameEmitterTest", "particleEmitter": { "maxLife": 20, "lifeCurrent": 0, "particleVelocity": { "x": 0.0, - "y": 0.1, + "y": 0.02, "z": 0.0 }, - "acceleration": -0.01, + "acceleration": -0.0001, "texture": "flame_05.png", "size": 0.3, "color": { - "x": 0.5, - "y": 0.5, - "z": 0.5 + "x": 0.83, + "y": 0.6, + "z": 0.09 }, + "offset": { + "x": 0, + "y": 0, + "z": 0 + }, + "radialAcceleration": 0.0001, + "transparency": { + "constant": 1, + "linear": 0, + "quadratic": -1 + }, + "spread": 15, "frequency": 2 }, "tokens": [ diff --git a/assets/Models/objects/furniture/texturemap.json b/assets/Models/objects/furniture/texturemap.json new file mode 100644 index 00000000..25c3088f --- /dev/null +++ b/assets/Models/objects/furniture/texturemap.json @@ -0,0 +1,11 @@ +{ + "textureMap": { + "Models/objects/furniture/torch1.glb": [ + { + "meshName" : "Cube", + "diffuse" : "/Textures/wooden.png", + "isDefault" : true + } + ] + } +} \ No newline at end of file diff --git a/assets/Models/objects/furniture/torch1.glb b/assets/Models/objects/furniture/torch1.glb new file mode 100644 index 00000000..57601893 Binary files /dev/null and b/assets/Models/objects/furniture/torch1.glb differ diff --git a/assets/Textures/wooden.png b/assets/Textures/wooden.png new file mode 100644 index 00000000..1dc78928 Binary files /dev/null and b/assets/Textures/wooden.png differ diff --git a/src/main/java/electrosphere/client/effects/ParticleEffects.java b/src/main/java/electrosphere/client/effects/ParticleEffects.java index e266131f..4f7d7655 100644 --- a/src/main/java/electrosphere/client/effects/ParticleEffects.java +++ b/src/main/java/electrosphere/client/effects/ParticleEffects.java @@ -1,15 +1,15 @@ package electrosphere.client.effects; -import electrosphere.client.entity.particle.ParticleUtils; -import electrosphere.engine.Globals; -import electrosphere.entity.ClientEntityUtils; -import electrosphere.entity.Entity; -import electrosphere.entity.EntityUtils; -import electrosphere.game.data.particle.ParticleData; +// import electrosphere.client.entity.particle.ParticleUtils; +// import electrosphere.engine.Globals; +// import electrosphere.entity.ClientEntityUtils; +// import electrosphere.entity.Entity; +// import electrosphere.entity.EntityUtils; +// import electrosphere.game.data.particle.ParticleData; -import java.util.Random; +// import java.util.Random; -import org.joml.Quaterniond; +// import org.joml.Quaterniond; import org.joml.Vector3d; /** @@ -22,26 +22,26 @@ public class ParticleEffects { * @param position The position of the collision */ public static void spawnBloodsplats(Vector3d position){ - int max = 30; - int min = 10; - ParticleData bloodsplatData = null; - for(ParticleData data : Globals.gameConfigCurrent.getParticleDefinition().getData()){ - if(data.getName().equals("blood")){ - bloodsplatData = data; - } - } - Random rand = new Random(); - int num = (int)(rand.nextFloat() * (max - min)) + min; - for(int i = 0; i < num; i++){ - Vector3d destination = new Vector3d(rand.nextFloat() - 0.5f,rand.nextFloat() - 0.5f,rand.nextFloat() - 0.5f).normalize(); - Entity particleEntity = ParticleUtils.clientSpawnBillboardParticle(bloodsplatData, destination); - ClientEntityUtils.initiallyPositionEntity( - particleEntity, - position, - new Quaterniond() - ); - EntityUtils.getScale(particleEntity).mul(bloodsplatData.getSize()); - } + // int max = 30; + // int min = 10; + // ParticleData bloodsplatData = null; + // for(ParticleData data : Globals.gameConfigCurrent.getParticleDefinition().getData()){ + // if(data.getName().equals("blood")){ + // bloodsplatData = data; + // } + // } + // Random rand = new Random(); + // int num = (int)(rand.nextFloat() * (max - min)) + min; + // for(int i = 0; i < num; i++){ + // Vector3d destination = new Vector3d(rand.nextFloat() - 0.5f,rand.nextFloat() - 0.5f,rand.nextFloat() - 0.5f).normalize(); + // Entity particleEntity = ParticleUtils.clientSpawnBillboardParticle(bloodsplatData, destination); + // ClientEntityUtils.initiallyPositionEntity( + // particleEntity, + // position, + // new Quaterniond() + // ); + // EntityUtils.getScale(particleEntity).mul(bloodsplatData.getSize()); + // } } } diff --git a/src/main/java/electrosphere/entity/state/client/particle/ClientParticleEmitterComponent.java b/src/main/java/electrosphere/entity/state/client/particle/ClientParticleEmitterComponent.java index 6965bbb8..49aec5a7 100644 --- a/src/main/java/electrosphere/entity/state/client/particle/ClientParticleEmitterComponent.java +++ b/src/main/java/electrosphere/entity/state/client/particle/ClientParticleEmitterComponent.java @@ -1,5 +1,7 @@ package electrosphere.entity.state.client.particle; +import org.joml.Quaterniond; +import org.joml.Random; import org.joml.Vector3d; import electrosphere.engine.Globals; @@ -10,6 +12,7 @@ import electrosphere.entity.btree.BehaviorTree; import electrosphere.entity.state.equip.ClientEquipState; import electrosphere.game.data.particle.ParticleData; import electrosphere.game.data.particle.ParticleEmitter; +import electrosphere.util.math.MathUtils; /** * A component that causes the entity to emit particles @@ -32,13 +35,22 @@ public class ClientParticleEmitterComponent implements BehaviorTree { */ long lastEmittedFrame = 0; + /** + * The random for particle generation + */ + static Random particleRand = new Random(0); + @Override public void simulate(float deltaTime) { Vector3d entityPos = EntityUtils.getPosition(parent); if((float)(Globals.timekeeper.getNumberOfRenderFramesElapsed() - lastEmittedFrame) > particleEmitter.getFrequency()){ lastEmittedFrame = Globals.timekeeper.getNumberOfRenderFramesElapsed(); //create particle here - Globals.particleService.spawn(this.getData(), new Vector3d(entityPos)); + Vector3d spawnPos = new Vector3d(entityPos); + if(this.particleEmitter.getOffset() != null){ + spawnPos = spawnPos.add(new Vector3d(this.particleEmitter.getOffset()).rotate(new Quaterniond(EntityUtils.getRotation(parent)))); + } + Globals.particleService.spawn(this.getData(), spawnPos); } } @@ -64,7 +76,23 @@ public class ClientParticleEmitterComponent implements BehaviorTree { data.setMaxLife(this.particleEmitter.getMaxLife()); data.setSize(this.particleEmitter.getSize()); data.setTexture(this.particleEmitter.getTexture()); - data.setVelocity(this.particleEmitter.getParticleVelocity()); + Vector3d initialVelocity = new Vector3d(this.particleEmitter.getParticleVelocity()); + if(this.particleEmitter.getSpread() != null){ + Quaterniond rot = new Quaterniond(); + Vector3d cross = null; + Vector3d normalizedVelocity = new Vector3d(initialVelocity).normalize(); + if(Math.abs(normalizedVelocity.dot(MathUtils.getOriginVector())) < 0.8){ + cross = MathUtils.getOriginVector().cross(normalizedVelocity); + } else { + cross = MathUtils.getUpVector().cross(normalizedVelocity); + } + rot.rotateAxis(Math.PI * 2 * particleRand.nextFloat(), normalizedVelocity); + rot.rotateAxis((particleRand.nextFloat() * this.particleEmitter.getSpread()) / 180.0 * Math.PI, cross); + initialVelocity = rot.transform(initialVelocity); + } + data.setVelocity(initialVelocity); + data.setEmitter(this.particleEmitter); + data.setParentEmitter(parent); return data; } diff --git a/src/main/java/electrosphere/entity/state/client/particle/ClientParticleTree.java b/src/main/java/electrosphere/entity/state/client/particle/ClientParticleTree.java index d2c35c9e..6018fbe6 100644 --- a/src/main/java/electrosphere/entity/state/client/particle/ClientParticleTree.java +++ b/src/main/java/electrosphere/entity/state/client/particle/ClientParticleTree.java @@ -1,7 +1,5 @@ package electrosphere.entity.state.client.particle; -import java.util.Random; - import org.joml.AxisAngle4f; import org.joml.Matrix4f; import org.joml.Quaternionf; @@ -17,6 +15,7 @@ import electrosphere.entity.EntityDataStrings; import electrosphere.entity.EntityUtils; import electrosphere.entity.btree.BehaviorTree; import electrosphere.game.data.particle.ParticleData; +import electrosphere.game.data.particle.ParticleEmitter; import electrosphere.renderer.actor.instance.InstancedActor; import electrosphere.renderer.texture.TextureAtlas; @@ -50,6 +49,11 @@ public class ClientParticleTree implements BehaviorTree { * The color of the particle */ Vector3d color; + + /** + * The data about the emitter + */ + ParticleEmitter emitterData; /** @@ -70,7 +74,8 @@ public class ClientParticleTree implements BehaviorTree { this.acceleration = particleData.getAcceleration(); this.hasLife = particleData.getMaxLife() != null; this.lifeCurrent = maxLife; - this.color = new Vector3d(new Random().nextFloat(),new Random().nextFloat(),0); + this.emitterData = particleData.getEmitter(); + this.color = new Vector3d(particleData.getColor()); } public int getMaxLife() { @@ -92,11 +97,12 @@ public class ClientParticleTree implements BehaviorTree { @Override public void simulate(float deltaTime){ InstancedActor instancedActor = InstancedActor.getInstancedActor(parent); - Vector3d parentPosition = EntityUtils.getPosition(parent); + Vector3d position = EntityUtils.getPosition(parent); Vector3f cameraPos = CameraEntityUtils.getCameraCenter(Globals.playerCamera); //update position - parentPosition.set(new Vector3d(parentPosition).add(velocity)); + position = position.set(new Vector3d(position).add(velocity)); + EntityUtils.getPosition(parent).set(position); //update velocity Vector3d accelerationVec = new Vector3d(velocity).normalize().mul(acceleration); @@ -105,6 +111,37 @@ public class ClientParticleTree implements BehaviorTree { velocity = new Vector3d(0,0,0); acceleration = 0; } + //add radial acceleration + if(this.emitterData.getRadialAcceleration() != null){ + Vector3d towardsParent = new Vector3d(EntityUtils.getPosition(this.particleData.getParentEmitter())).sub(position).normalize().mul(this.emitterData.getRadialAcceleration()); + velocity = velocity.add(towardsParent); + } + + //rotate the model to face the camera + Matrix4f rotationMatrix = new Matrix4f(Globals.viewMatrix).invert(); + Quaternionf rotation = new Quaternionf(rotationMatrix.getRotation(new AxisAngle4f())); + EntityUtils.getRotation(parent).set(rotation); + + //scale the particle + Vector3f scale = EntityUtils.getScale(parent); + scale.set(this.particleData.getSize()); + + //calculate alpha + float alpha = 1.0f; + if(this.emitterData.getTransparency() != null){ + float t = 1.0f - (lifeCurrent / (float)maxLife); + alpha = (float)this.emitterData.getTransparency().calculate(t); + } + + //store color + Vector4f currentColor = new Vector4f( + (float)this.color.y, + (float)this.color.z, + alpha, + (float)this.color.x + ); + + //calculate life left if(hasLife){ lifeCurrent--; if(lifeCurrent <= 0){ @@ -113,24 +150,16 @@ public class ClientParticleTree implements BehaviorTree { } } - //rotate the model to face the camera - Matrix4f rotationMatrix = new Matrix4f(Globals.viewMatrix).invert(); - Quaternionf rotation = new Quaternionf(rotationMatrix.getRotation(new AxisAngle4f())); - EntityUtils.getRotation(parent).set(rotation); - - Vector3f scale = EntityUtils.getScale(parent); - scale.set(this.particleData.getSize()); - //push values to buffer that eventually gets uploaded to gpu if(instancedActor != null){ TextureAtlas particleTextureAtlas = Globals.particleService.getTextureAtlas(); int textureIndex = particleTextureAtlas.getTextureIndex(this.particleData.getTexture()); instancedActor.setAttribute(Globals.particleService.getModelAttrib(), new Matrix4f().translationRotateScale( - new Vector3f((float)parentPosition.x,(float)parentPosition.y,(float)parentPosition.z).sub(cameraPos), + new Vector3f((float)position.x,(float)position.y,(float)position.z).sub(cameraPos), new Quaternionf(rotation), scale )); - instancedActor.setAttribute(Globals.particleService.getColorAttrib(), new Vector4f((float)this.color.y,(float)this.color.z,1.0f,(float)this.color.x)); + instancedActor.setAttribute(Globals.particleService.getColorAttrib(), currentColor); //when written to buffer, will be written in order w, x, y, z //but gpu will fetch in order x, y, z, w diff --git a/src/main/java/electrosphere/game/data/Config.java b/src/main/java/electrosphere/game/data/Config.java index 8f78188d..58d99883 100644 --- a/src/main/java/electrosphere/game/data/Config.java +++ b/src/main/java/electrosphere/game/data/Config.java @@ -13,7 +13,6 @@ import electrosphere.game.data.creature.type.attack.AttackMoveResolver; import electrosphere.game.data.creature.type.model.CreatureTypeMap; import electrosphere.game.data.foliage.type.model.FoliageTypeMap; import electrosphere.game.data.item.type.model.ItemTypeMap; -import electrosphere.game.data.particle.ParticleDefinition; import electrosphere.game.data.projectile.ProjectileTypeHolder; import electrosphere.game.data.tutorial.HintDefinition; import electrosphere.game.data.units.UnitDefinitionFile; @@ -47,11 +46,6 @@ public class Config { */ SurfaceAudioCollection surfaceAudioCollection; - /** - * The particle definition - */ - ParticleDefinition particleDefinition; - /** * The unit loader */ @@ -73,7 +67,6 @@ public class Config { config.projectileTypeHolder = FileUtils.loadObjectFromAssetPath("Data/entity/projectile.json", ProjectileTypeHolder.class); config.hintData = FileUtils.loadObjectFromAssetPath("Data/tutorial/hints.json", HintDefinition.class); config.surfaceAudioCollection = FileUtils.loadObjectFromAssetPath("Data/audio/surface.json", SurfaceAudioCollection.class); - config.particleDefinition = FileUtils.loadObjectFromAssetPath("Data/entity/particles.json", ParticleDefinition.class); config.projectileTypeHolder.init(); config.unitLoader = UnitLoader.create(FileUtils.loadObjectFromAssetPath("Data/game/units/units.json", UnitDefinitionFile.class)); @@ -245,14 +238,6 @@ public class Config { return this.surfaceAudioCollection; } - /** - * Gets the particle definition - * @return The particle definition - */ - public ParticleDefinition getParticleDefinition(){ - return particleDefinition; - } - /** * Gets the unit loader * @return The unit loader diff --git a/src/main/java/electrosphere/game/data/color/ColorRange.java b/src/main/java/electrosphere/game/data/color/ColorRange.java new file mode 100644 index 00000000..bb41c3c8 --- /dev/null +++ b/src/main/java/electrosphere/game/data/color/ColorRange.java @@ -0,0 +1,88 @@ +package electrosphere.game.data.color; + +/** + * Defines a range of colors + */ +public class ColorRange { + + /** + * The minimum chroma value + */ + float chromaMin; + + /** + * The range of allowed chroma values + */ + float chromaRange; + + /** + * The minimum hue value + */ + float hueMin; + + /** + * The range of allowed hue values + */ + float hueRange; + + /** + * The minimum lightness + */ + float lightMin; + + /** + * The range of allowed lightness values + */ + float lightRange; + + public float getChromaMin() { + return chromaMin; + } + + public void setChromaMin(float chromaMin) { + this.chromaMin = chromaMin; + } + + public float getChromaRange() { + return chromaRange; + } + + public void setChromaRange(float chromaRange) { + this.chromaRange = chromaRange; + } + + public float getHueMin() { + return hueMin; + } + + public void setHueMin(float hueMin) { + this.hueMin = hueMin; + } + + public float getHueRange() { + return hueRange; + } + + public void setHueRange(float hueRange) { + this.hueRange = hueRange; + } + + public float getLightMin() { + return lightMin; + } + + public void setLightMin(float lightMin) { + this.lightMin = lightMin; + } + + public float getLightRange() { + return lightRange; + } + + public void setLightRange(float lightRange) { + this.lightRange = lightRange; + } + + + +} diff --git a/src/main/java/electrosphere/game/data/math/ScalarGenerator.java b/src/main/java/electrosphere/game/data/math/ScalarGenerator.java new file mode 100644 index 00000000..1d8e1ddd --- /dev/null +++ b/src/main/java/electrosphere/game/data/math/ScalarGenerator.java @@ -0,0 +1,58 @@ +package electrosphere.game.data.math; + +/** + * A defintion of a function that generates a scalar + */ +public class ScalarGenerator { + + /** + * The constant value + */ + float constant; + + /** + * The linear value + */ + float linear; + + /** + * The quadratic value + */ + float quadratic; + + public float getConstant() { + return constant; + } + + public void setConstant(float constant) { + this.constant = constant; + } + + public float getLinear() { + return linear; + } + + public void setLinear(float linear) { + this.linear = linear; + } + + public float getQuadratic() { + return quadratic; + } + + public void setQuadratic(float quadratic) { + this.quadratic = quadratic; + } + + + /** + * Calculates the scalar's value given an input t + * @param t The input + * @return The scalar's value at t + */ + public double calculate(double t){ + return constant + t * linear + t * t * quadratic; + } + + +} diff --git a/src/main/java/electrosphere/game/data/particle/ParticleData.java b/src/main/java/electrosphere/game/data/particle/ParticleData.java index 7c0bdf70..c1ac4015 100644 --- a/src/main/java/electrosphere/game/data/particle/ParticleData.java +++ b/src/main/java/electrosphere/game/data/particle/ParticleData.java @@ -2,6 +2,8 @@ package electrosphere.game.data.particle; import org.joml.Vector3d; +import electrosphere.entity.Entity; + /** * Data on how a particle should behave */ @@ -49,6 +51,16 @@ public class ParticleData { */ Vector3d color; + /** + * The particle emitter DO NOT SET THIS IN JSON + */ + ParticleEmitter emitter; + + /** + * The parent emitter + */ + Entity parentEmitter; + /** * Gets the max life of the particle * @return The max life @@ -137,6 +149,25 @@ public class ParticleData { this.color = color; } + public Vector3d getColor() { + return color; + } + + public ParticleEmitter getEmitter() { + return emitter; + } + + public void setEmitter(ParticleEmitter emitter) { + this.emitter = emitter; + } + + public Entity getParentEmitter() { + return parentEmitter; + } + + public void setParentEmitter(Entity parentEmitter) { + this.parentEmitter = parentEmitter; + } } diff --git a/src/main/java/electrosphere/game/data/particle/ParticleEmitter.java b/src/main/java/electrosphere/game/data/particle/ParticleEmitter.java index 47cc004b..725cc093 100644 --- a/src/main/java/electrosphere/game/data/particle/ParticleEmitter.java +++ b/src/main/java/electrosphere/game/data/particle/ParticleEmitter.java @@ -2,6 +2,9 @@ package electrosphere.game.data.particle; import org.joml.Vector3d; +import electrosphere.game.data.color.ColorRange; +import electrosphere.game.data.math.ScalarGenerator; + /** * Describes a particle emitter */ @@ -53,6 +56,41 @@ public class ParticleEmitter { */ Float frequency; + /** + * The gravity applied to the particle + */ + Vector3d gravity; + + /** + * The range of allowed colors + */ + ColorRange colorRange; + + /** + * The value of transparency given time + */ + ScalarGenerator transparency; + + /** + * The value of scale given time + */ + ScalarGenerator scale; + + /** + * The amount the emitter can vary the initial velocity + */ + Float spread; + + /** + * The acceleration to/from the center of the emitter + */ + Float radialAcceleration; + + /** + * The offset from the base of the entity to emit from + */ + Vector3d offset; + /** * Gets the max life of the particle * @return The max life @@ -161,6 +199,64 @@ public class ParticleEmitter { this.frequency = frequency; } + public Vector3d getGravity() { + return gravity; + } + + public void setGravity(Vector3d gravity) { + this.gravity = gravity; + } + + public ColorRange getColorRange() { + return colorRange; + } + + public void setColorRange(ColorRange colorRange) { + this.colorRange = colorRange; + } + + public ScalarGenerator getTransparency() { + return transparency; + } + + public void setTransparency(ScalarGenerator transparency) { + this.transparency = transparency; + } + + public ScalarGenerator getScale() { + return scale; + } + + public void setScale(ScalarGenerator scale) { + this.scale = scale; + } + + public Float getSpread() { + return spread; + } + + public void setSpread(Float spread) { + this.spread = spread; + } + + public Float getRadialAcceleration() { + return radialAcceleration; + } + + public void setRadialAcceleration(Float radialAcceleration) { + this.radialAcceleration = radialAcceleration; + } + + public Vector3d getOffset() { + return offset; + } + + public void setOffset(Vector3d offset) { + this.offset = offset; + } + + + } diff --git a/src/main/java/electrosphere/renderer/light/PointLight.java b/src/main/java/electrosphere/renderer/light/PointLight.java index 600b6618..c26b3e44 100644 --- a/src/main/java/electrosphere/renderer/light/PointLight.java +++ b/src/main/java/electrosphere/renderer/light/PointLight.java @@ -86,6 +86,7 @@ public class PointLight { * @param description The description */ protected PointLight(PointLightDescription description){ + this.position = new Vector3f(); this.radius = description.getRadius(); this.constant = description.getConstant(); this.linear = description.getLinear();