package info.u250.c2d.tests.mesh; import info.u250.c2d.engine.Engine; import info.u250.c2d.engine.EngineDrive; import info.u250.c2d.engine.Scene; import info.u250.c2d.engine.resources.AliasResourceManager; import java.util.ArrayList; import java.util.List; import java.util.Random; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.InputAdapter; import com.badlogic.gdx.InputProcessor; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.GL20; import com.badlogic.gdx.graphics.Pixmap; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.TextureRegion; import com.badlogic.gdx.graphics.glutils.FrameBuffer; import com.badlogic.gdx.graphics.glutils.ImmediateModeRenderer; import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType; import com.badlogic.gdx.math.MathUtils; import com.badlogic.gdx.math.Vector2; public class WaterTest extends Engine { @Override protected EngineDrive onSetupEngineDrive() { return new EngineX(); } @Override public void dispose() { super.dispose(); } private class EngineX implements EngineDrive { @Override public void onResourcesRegister(AliasResourceManager<String> reg) { reg.texture("W", "data/water.png"); } @Override public void dispose() { } @Override public EngineOptions onSetupEngine() { final EngineOptions opt = new EngineOptions(new String[] {"data/water.png"}, 800,480); opt.useGL20 = true; return opt; } @Override public void onLoadedResourcesCompleted() { final Water water = new Water(new TextureRegion(Engine.resource("W",Texture.class)),200,240,Color.BLUE,Color.CYAN); Engine.setMainScene(new Scene() { @Override public void render(float delta) { water.render(delta); } @Override public InputProcessor getInputProcessor() { return new InputAdapter() { @Override public boolean touchDown(int screenX, int screenY, int pointer, int button) { water.splash(200, 120+new Random().nextFloat() * 100); return super.touchDown(screenX, screenY, pointer, button); } }; } @Override public void update(float delta) { water.update(); } @Override public void hide() { } @Override public void show() { } }); } } } class WaterColumn { public float TargetHeight; public float Height; public float Speed; public void Update(float dampening, float tension) { float x = TargetHeight - Height; Speed += tension * x - Speed * dampening; Height += Speed; } } class Particle { public Vector2 Position; public Vector2 Velocity; public float Orientation; public Particle(Vector2 position, Vector2 velocity, float orientation) { Position = position; Velocity = velocity; Orientation = orientation; } } class Water { public Water(TextureRegion particleTexture,int segment,float height,Color topColor,Color endColor) { this.particleTexture = particleTexture; columns = new WaterColumn[segment]; for (int i = 0; i < columns.length; i++) { columns[i] = new WaterColumn(); columns[i].Height = height; columns[i].TargetHeight = height; columns[i].Speed = 0; } scale = Engine.getWidth() / (columns.length -1); this.color1 = endColor; this.color2 = topColor; fbo = new FrameBuffer(Pixmap.Format.RGBA8888, (int)Engine.getWidth(), (int)Engine.getHeight(), false); } Color color1 = new Color(0.2f, 0.7f, 1f, 0.9f); Color color2 = new Color(0.2f, 0.5f, 1f, 0.8f); public float tension = 0.025f; public float dampening = 0.025f; public float spread = 0.25f; int tinkness = 2; TextureRegion particleTexture; float scale = 0; Random rnd = new Random(); WaterColumn[] columns = null; List<Particle> particles = new ArrayList<Particle>(); FrameBuffer fbo ; public void update() { for (int i = 0; i < columns.length; i++)columns[i].Update(dampening, tension); float[] lDeltas = new float[columns.length]; float[] rDeltas = new float[columns.length]; // do some passes where columns pull on their neighbours for (int j = 0; j < 8; j++) { for (int i = 0; i < columns.length; i++) { if (i > 0) { lDeltas[i] = spread * (columns[i].Height - columns[i - 1].Height); columns[i - 1].Speed += lDeltas[i]; } if (i < columns.length - 1) { rDeltas[i] = spread * (columns[i].Height - columns[i + 1].Height); columns[i + 1].Speed += rDeltas[i]; } } for (int i = 0; i < columns.length; i++) { if (i > 0) columns[i - 1].Height += lDeltas[i]; if (i < columns.length - 1) columns[i + 1].Height += rDeltas[i]; } } for(Particle particle : particles){ updateParticle(particle); } } public void render(float delta) { Gdx.gl.glEnable(GL20.GL_BLEND); final ImmediateModeRenderer renderer = Engine.getShapeRenderer().getRenderer(); Engine.getShapeRenderer().begin(ShapeType.Filled); for (int i = 1; i < columns.length; i++) { Vector2 p1 = new Vector2((i - 1) * scale, 0); Vector2 p2 = new Vector2((i - 1) * scale, columns[i - 1].Height); Vector2 p3 = new Vector2(i * scale, columns[i].Height); Vector2 p4 = new Vector2(i * scale, 0); renderer.color(color1.r, color1.g, color1.b, color1.a); renderer.vertex(p1.x, p1.y, 0); renderer.color(color2.r, color2.g, color2.b, color2.a); renderer.vertex(p2.x, p2.y, 0); renderer.color(color2.r, color2.g, color2.b,color2.a); renderer.vertex(p3.x, p3.y, 0); renderer.color(color2.r, color2.g, color2.b, color2.a); renderer.vertex(p3.x, p3.y, 0); renderer.color(color1.r, color1.g, color1.b, color1.a); renderer.vertex(p4.x, p4.y, 0); renderer.color(color1.r, color1.g, color1.b,color1.a); renderer.vertex(p1.x, p1.y, 0); renderer.color(color1.r, color1.g, color1.b, color1.a*0.3f); renderer.vertex(p1.x, p2.y-tinkness, 0); renderer.color(color2.r, color2.g, color2.b, color2.a*0.3f); renderer.vertex(p2.x, p2.y, 0); renderer.color(color2.r, color2.g, color2.b,color2.a*0.3f); renderer.vertex(p3.x, p3.y, 0); renderer.color(color2.r, color2.g, color2.b, color2.a*0.3f); renderer.vertex(p3.x, p3.y, 0); renderer.color(color1.r, color1.g, color1.b, color1.a*0.3f); renderer.vertex(p4.x, p3.y-tinkness, 0); renderer.color(color1.r, color1.g, color1.b,color1.a*0.3f); renderer.vertex(p1.x, p2.y-tinkness, 0); } Engine.getShapeRenderer().end(); fbo.begin(); Gdx.graphics.getGL20().glClear( GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT ); Engine.getSpriteBatch().setColor(color2); Engine.getSpriteBatch().setBlendFunction(GL20.GL_SRC_ALPHA,GL20.GL_ONE); Engine.getSpriteBatch().begin(); for(Particle p:particles){ Engine.getSpriteBatch().draw(particleTexture, p.Position.x, p.Position.y, 0, 0, particleTexture.getRegionWidth(), particleTexture.getRegionHeight(), 1, 1, p.Orientation); } Engine.getSpriteBatch().end(); Engine.getSpriteBatch().setShader(null); fbo.end(); Engine.getSpriteBatch().setBlendFunction(GL20.GL_SRC_ALPHA,GL20.GL_ONE); Engine.getSpriteBatch().begin(); Engine.getSpriteBatch().draw(fbo.getColorBufferTexture(),0,0,fbo.getColorBufferTexture().getWidth(),fbo.getColorBufferTexture().getHeight(),0,0,1,1); Engine.getSpriteBatch().end(); Engine.getSpriteBatch().setColor(Color.WHITE); Engine.getSpriteBatch().setBlendFunction(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA); } void updateParticle(Particle particle) { float Gravity = -0.3f; particle.Velocity.y += Gravity; particle.Position.add(particle.Velocity); particle.Orientation = GetAngle(particle.Velocity); } private float GetAngle(Vector2 vector) { return (float) Math.atan2(vector.y, vector.x); } public float GetHeight(float x) { if (x < 0 || x > 800) return 240; return columns[(int) (x / scale)].Height; } private void CreateParticle(Vector2 pos, Vector2 velocity) { particles.add(new Particle(pos, velocity, 0)); } private Vector2 FromPolar(float angle, float magnitude) { return new Vector2((float) Math.cos(angle), (float) Math.sin(angle)) .scl(magnitude); } private float GetRandomFloat(float min, float max) { return (float) rnd.nextDouble() * (max - min) + min; } private Vector2 GetRandomVector2(float maxLength) { return FromPolar(GetRandomFloat(-MathUtils.PI, -MathUtils.PI), GetRandomFloat(0, maxLength)); } private void CreateSplashParticles(float xPosition, float speed) { float y = GetHeight(xPosition); if (speed > 120) { for (int i = 0; i < speed / 8; i++) { Vector2 pos = new Vector2(xPosition, y) .add(GetRandomVector2(40)); Vector2 vel = FromPolar(GetRandomFloat(-150, -30) * MathUtils.degreesToRadians, GetRandomFloat(0, 0.5f * (float) Math.sqrt(speed))); vel.y *= -1; CreateParticle(pos, vel); } } } public void splash(float xPosition, float speed) { int index = (int) MathUtils.clamp(xPosition / scale, 0, columns.length - 1); for (int i = Math.max(0, index - 0); i < Math.min(columns.length - 1, index + 1); i++) { columns[index].Speed = speed; } CreateSplashParticles(xPosition, speed); } }