Brief shockwave experiment

This commit is contained in:
Anuken 2022-03-07 10:37:53 -05:00
parent 46489f9893
commit 5603672983
5 changed files with 186 additions and 27 deletions

View File

@ -0,0 +1,42 @@
#define MAX_SHOCKWAVES 64
#define WAVE_RADIUS 4.0
#define DIFF_SCL 1
#define WAVE_POW 0.8
varying vec2 v_texCoords;
uniform sampler2D u_texture;
uniform vec2 u_resolution;
uniform vec2 u_campos;
uniform vec4 u_shockwaves[MAX_SHOCKWAVES];
uniform int u_shockwave_count;
void main(){
vec2 worldCoords = v_texCoords * u_resolution + u_campos;
vec2 uv = v_texCoords;
vec2 displacement = vec2(0.0, 0.0);
for(int i = 0; i < MAX_SHOCKWAVES; i ++){
vec4 wave = u_shockwaves[i];
float radius = wave.z;
float strength = wave.w;
float dst = distance(worldCoords, wave.xy);
float realStrength = 1.0 - pow(1.0 - strength, 5.0);
if(abs(dst - radius) <= WAVE_RADIUS){
float diff = dst - radius;
float pdiff = 1.0 - pow(abs(diff * DIFF_SCL), WAVE_POW);
float diffTime = diff * pdiff;
vec2 relative = normalize(worldCoords - wave.xy);
displacement += (relative * diffTime * strength) / u_resolution;
}
if(i >= u_shockwave_count - 1){
break;
}
}
vec4 c = texture2D(u_texture, uv + displacement);
gl_FragColor = c;
}

View File

@ -85,6 +85,8 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
transient float efficiency;
/** Same as efficiency, but for optional consumers only. */
transient float optionalEfficiency;
/** The efficiency this block would have if consValid() / productionValid() returned true. */
transient float potentialEfficiency;
transient float healSuppressionTime = -1f;
transient float lastHealTime = -120f * 10f;
@ -224,7 +226,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
//version 3 has efficiency numbers instead of bools
if(version >= 3){
efficiency = read.ub() / 255f;
efficiency = potentialEfficiency = read.ub() / 255f;
optionalEfficiency = read.ub() / 255f;
}
@ -1640,7 +1642,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
}
public boolean canConsume(){
return efficiency > 0;
return potentialEfficiency > 0;
}
/** Scaled delta. */
@ -1671,40 +1673,43 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
public void updateConsumption(){
//everything is valid when cheating
if(!block.hasConsumers || cheating()){
efficiency = optionalEfficiency = 1f;
potentialEfficiency = efficiency = optionalEfficiency = 1f;
return;
}
//disabled -> nothing works
if(!enabled){
efficiency = optionalEfficiency = 0f;
potentialEfficiency = efficiency = optionalEfficiency = 0f;
return;
}
//TODO why check for old state?
boolean prevValid = efficiency > 0, update = shouldConsume() && productionValid();
if(update){
float minEfficiency = 1f;
float minEfficiency = 1f;
//assume efficiency is 1 for the calculations below
efficiency = optionalEfficiency = 1f;
//assume efficiency is 1 for the calculations below
efficiency = optionalEfficiency = 1f;
//first pass: get the minimum efficiency of any consumer
for(var cons : block.nonOptionalConsumers){
minEfficiency = Math.min(minEfficiency, cons.efficiency(self()));
}
//first pass: get the minimum efficiency of any consumer
for(var cons : block.nonOptionalConsumers){
minEfficiency = Math.min(minEfficiency, cons.efficiency(self()));
}
//same for optionals
for(var cons : block.optionalConsumers){
optionalEfficiency = Math.min(optionalEfficiency, cons.efficiency(self()));
}
//same for optionals
for(var cons : block.optionalConsumers){
optionalEfficiency = Math.min(optionalEfficiency, cons.efficiency(self()));
}
//efficiency is now this minimum value
efficiency = minEfficiency;
optionalEfficiency = Math.min(optionalEfficiency, minEfficiency);
}else{
//should not consume, efficiency now zero
//efficiency is now this minimum value
efficiency = minEfficiency;
optionalEfficiency = Math.min(optionalEfficiency, minEfficiency);
//assign "potential"
potentialEfficiency = efficiency;
//no updating means zero efficiency
if(!update){
efficiency = optionalEfficiency = 0f;
}

View File

@ -9,7 +9,9 @@ import arc.graphics.g3d.*;
import arc.graphics.gl.*;
import arc.math.geom.*;
import arc.scene.ui.layout.*;
import arc.struct.*;
import arc.util.*;
import mindustry.game.EventType.*;
import mindustry.type.*;
import static mindustry.Vars.*;
@ -28,6 +30,7 @@ public class Shaders{
public static CloudShader clouds;
public static PlanetGridShader planetGrid;
public static AtmosphereShader atmosphere;
public static ShockwaveShader shockwave;
public static MeshShader mesh;
public static Shader unlit;
public static Shader screenspace;
@ -67,6 +70,9 @@ public class Shaders{
atmosphere = new AtmosphereShader();
unlit = new LoadShader("planet", "unlit");
screenspace = new LoadShader("screenspace", "screenspace");
//disabled for now...
//shockwave = new ShockwaveShader();
}
public static class AtmosphereShader extends LoadShader{
@ -350,6 +356,112 @@ public class Shaders{
}
}
public static class ShockwaveShader extends LoadShader{
static final int max = 64;
static final int size = 5;
static final String[] uniformNames = new String[max];
//x y radius life[1-0] lifetime
protected FloatSeq data = new FloatSeq();
protected boolean hadAny = false;
protected FrameBuffer buffer = new FrameBuffer();
public float lifetime = 20f;
static{
for(int i = 0; i < max; i++){
uniformNames[i] = "u_shockwaves[" + i + "]";
}
}
public ShockwaveShader(){
super("shockwave", "screenspace");
Events.run(Trigger.update, () -> {
if(state.isPaused()) return;
if(state.isMenu()){
data.size = 0;
return;
}
var items = data.items;
for(int i = 0; i < data.size; i += size){
//decrease lifetime
items[i + 3] -= Time.delta / items[i + 4];
if(items[i + 3] <= 0f){
//swap with head.
if(data.size > size){
System.arraycopy(items, data.size - size, items, i, size);
}
data.size -= size;
i -= size;
}
}
});
Events.run(Trigger.preDraw, () -> {
hadAny = data.size > 0;
if(hadAny){
buffer.resize(Core.graphics.getWidth(), Core.graphics.getHeight());
buffer.begin(Color.clear);
}
});
Events.run(Trigger.postDraw, () -> {
if(hadAny){
buffer.end();
Draw.blend(Blending.disabled);
buffer.blit(this);
Draw.blend();
}
});
}
@Override
public void apply(){
int count = data.size / 4;
setUniformi("u_shockwave_count", count);
if(count > 0){
setUniformf("u_resolution", Core.camera.width, Core.camera.height);
setUniformf("u_campos", Core.camera.position.x - Core.camera.width/2f, Core.camera.position.y - Core.camera.height/2f);
var items = data.items;
for(int i = 0; i < count; i++){
int offset = i * size;
setUniformf(uniformNames[i],
items[offset], items[offset + 1], //xy
items[offset + 2] * (1f - items[offset + 3]), //radius * time
items[offset + 3] //time
//lifetime ignored
);
}
}
}
public void add(float x, float y, float radius){
add(x, y, radius, 20f);
}
public void add(float x, float y, float radius, float lifetime){
//replace first entry
if(data.size / size >= max){
var items = data.items;
items[0] = x;
items[1] = y;
items[2] = radius;
items[3] = 1f;
items[4] = lifetime;
}else{
data.addAll(x, y, radius, 1f, lifetime);
}
}
}
public static class LoadShader extends Shader{
public LoadShader(String frag, String vert){
super(getShaderFi(vert + ".vert"), getShaderFi(frag + ".frag"));

View File

@ -331,13 +331,13 @@ public class Turret extends ReloadTurret{
//turret always reloads regardless of whether it's targeting something
updateReload();
if(timer(timerTarget, targetInterval)){
findTarget();
}
if(hasAmmo()){
if(Float.isNaN(reloadCounter)) reloadCounter = 0;
if(timer(timerTarget, targetInterval)){
findTarget();
}
if(validateTarget()){
boolean canShoot = true;
@ -402,7 +402,7 @@ public class Turret extends ReloadTurret{
}
protected void turnToTarget(float targetRot){
rotation = Angles.moveToward(rotation, targetRot, rotateSpeed * delta() * baseReloadSpeed());
rotation = Angles.moveToward(rotation, targetRot, rotateSpeed * delta() * potentialEfficiency);
}
public boolean shouldTurn(){

View File

@ -107,7 +107,7 @@ public class CoreBlock extends StorageBlock{
public void init(){
//assign to update clipSize internally
lightRadius = 30f + 20f * size;
fogRadius = Math.max(fogRadius, (int)(lightRadius / 8f * 3f) + 5);
fogRadius = Math.max(fogRadius, (int)(lightRadius / 8f * 3f) + 13);
emitLight = true;
super.init();