ProjectZombie/src/projectzombie/entity/particle/ParticleBreak.java

383 lines
8.2 KiB
Java
Executable File

package projectzombie.entity.particle;
import static org.lwjgl.opengl.GL15.glBindBuffer;
import static org.lwjgl.opengl.GL15.glBufferData;
import static org.lwjgl.opengl.GL15.glGenBuffers;
import java.util.Random;
import org.lwjgl.opengl.GL33;
import gl_engine.MathHelpers;
import gl_engine.matrix.Matrix4;
import gl_engine.texture.TextureRef3D;
import gl_engine.vec.Vec2d;
import gl_engine.vec.Vec2i;
import gl_engine.vec.Vec3d;
import projectzombie.Main;
import projectzombie.entity.EntityParticle;
import projectzombie.init.Models;
import projectzombie.model.IModel;
import projectzombie.model.Model;
import projectzombie.model.ModelVertical;
import projectzombie.world.chunk.Chunk;
import projectzombie.world.layer.Layer;
public class ParticleBreak extends EntityParticle implements IModel
{
protected static final Random rand = new Random();
protected class Break {
TextureRef3D ref;
Vec3d velocity;
Vec3d pos;
boolean moving;
int time, flags;
}
protected Break[] particles;
private int ibo, vbo, vao;
private boolean generated;
protected int dead, still, time;
protected double still_ypos;
protected boolean do_gravity;
public Vec2d getParticleSize() {
return new Vec2d(0.1, 0.1);
}
public ParticleBreak(Vec3d pos, Vec3d velocity, IModel model) {
this(pos, velocity, model, 200, 0.05);
}
public ParticleBreak(Vec3d pos, Vec3d velocity, IModel model, int count) {
this(pos, velocity, model, count, 0.05);
}
protected Break createParticle(
IModel model, TextureRef3D ref, int tex_id,
Vec3d pos, Vec3d velocity, float[] verticies,
double velocity_up_multiplier, double model_height, int i)
{
Break particle = new Break();
particle.pos = pos.add(new Vec3d(0, rand.nextDouble() * model_height, 0));
particle.velocity = velocity.multiply(rand.nextDouble()).add(
MathHelpers.moveTowards2(0.01, rand.nextDouble() * MathHelpers.TWO_PI).xny().add(
new Vec3d(0, rand.nextDouble() * velocity_up_multiplier, 0)));
particle.ref = ref;
particle.moving = true;
particle.flags = ((int)verticies[tex_id * Model.SIZE + Model.SIZE - 1] & 0b0110) | 0b1000;
return particle;
}
protected ParticleBreak(Vec3d pos, Vec3d velocity, IModel model, int count, double velocity_up_multiplier) {
super(new Vec3d(pos.x, 0, pos.z), new Vec3d(0, 0, 0));
if(pos.squareDistance(Main.player.getPos()) > 32) {
count = 0;
}
this.hasGravity = false;
double model_height = model.getHeight();
TextureRef3D[] textures = model.getTextures();
float[] verticies = model.getVerticies();
count *= model_height;
particles = new Break[count];
for(int i=0;i<particles.length;i++)
{
int tex_id = (int)(rand.nextDouble() * textures.length);
TextureRef3D texture = textures[tex_id];
TextureRef3D ref = new TextureRef3D();
float dx = texture.ex - texture.sx;
float dy = texture.ey - texture.sy;
float w = (float)model.getWidth();
float h = (float)model.getHeight();
ref.sx = (float)MathHelpers.map((int)(rand.nextDouble()*16*w), 0, 16*w, texture.sx, texture.ex - dx/(16*w));
ref.sy = (float)MathHelpers.map((int)(rand.nextDouble()*16*h), 0, 16*h, texture.sy, texture.ey - dy/(16*h));
ref.ex = ref.sx + dx/(16*w);
ref.ey = ref.sy + dy/(16*h);
ref.texmap = texture.texmap;
ref.z = texture.z;
Break particle = createParticle(
model, ref, tex_id, pos, velocity,
verticies, velocity_up_multiplier,
model_height, i);
particles[i] = particle;
}
time = 1000;
generated = false;
do_gravity = true;
still = 0;
dead = 0;
}
protected void onAllStill() {
if(time < 0 && rand.nextDouble() > 0.75) {
dead += 1;
}
}
protected void onAllDead() {
if(getPos().squareDistance(Main.player.getPos()) > 32) {
kill();
}
}
protected boolean isStill(Break particle) {
return particle.pos.y < 0;
}
protected void onStill(Break particle) {
particle.moving = false;
particle.pos.y = still_ypos;
still += 1;
}
@Override
public void tick(Chunk chunk, Layer layer) {
super.tick(chunk, layer);
if(isDead()) {
return;
}
time -= 1;
if(dead == particles.length - 1) {
onAllDead();
return;
}
if(still == particles.length) {
onAllStill();
return;
}
for(int i=0;i<(particles.length - dead);i++)
{
Break particle = particles[i];
if(!particle.moving) {
continue;
}
if(isStill(particle)) {
onStill(particle);
continue;
}
if(do_gravity) {
particle.velocity.y -= MathHelpers.FallSpeed;
}
particle.pos = particle.pos.add(particle.velocity);
}
}
@Override
public void kill() {
this.free();
super.kill();
}
@Override
public IModel getModel()
{
if(isDead()) {
return Models.EMPTY;
}
return this;
}
@Override
public int[] getIndicies()
{
int[] indicies = new int[getIndexSize()];
int upto = 0;
for(int i=0;i<indicies.length;i+=6)
{
indicies[i+0] = upto+0;
indicies[i+1] = upto+1;
indicies[i+2] = upto+2;
indicies[i+3] = upto+2;
indicies[i+4] = upto+3;
indicies[i+5] = upto+0;
upto += 4;
}
return indicies;
}
@Override
public float[] getVerticies()
{
float[] verticies = new float[getSize() * Model.SIZE];
Vec3d ppos = getPos();
int upto = 0;
float k = Model.OFFSET;
float x = (float)getParticleSize().x/2;
float y = (float)getParticleSize().y;
for(int i=0;i<(particles.length - dead);i++)
{
Break particle = particles[i];
TextureRef3D ref = particle.ref;
float f = particle.flags;
float px = (float)(particle.pos.x - ppos.x);
float py = (float)(particle.pos.y - ppos.y);
float pz = (float)(particle.pos.z - ppos.z);
float a = y, b = 0, c = 0;
if(!particle.moving) {
f = particle.flags & 0b0110;
a = 0.001f;
b = y / 2;
c = a;
}
float[] p = {
-x, c,-b, ref.sx+k, ref.sy+k, ref.z, ref.sy, ref.ey, px, py, pz, 1, 1, f,
x, c,-b, ref.ex-k, ref.sy+k, ref.z, ref.sy, ref.ey, px, py, pz, 1, 1, f,
x, a, b, ref.ex-k, ref.ey-k, ref.z, ref.sy, ref.ey, px, py, pz, 1, 1, f,
-x, a, b, ref.sx+k, ref.ey-k, ref.z, ref.sy, ref.ey, px, py, pz, 1, 1, f,
};
for(int j=0;j<p.length;j++) {
verticies[upto+j] = p[j];
}
upto += 4*Model.SIZE;
}
return verticies;
}
@Override
public TextureRef3D[] getTextures()
{
TextureRef3D[] textures = new TextureRef3D[getSize()];
int upto = 0;
for(int i=0;i<particles.length;i++) {
textures[upto+0] = particles[i].ref;
textures[upto+1] = particles[i].ref;
textures[upto+2] = particles[i].ref;
textures[upto+3] = particles[i].ref;
upto += 4;
}
return textures;
}
@Override
public double getHeight() {
return 1;
}
@Override
public int getIndexSize() {
return 6 * (particles.length - dead);
}
@Override
public int getSize() {
return 4 * (particles.length - dead);
}
@Override
public void bind()
{
if(isDead()) {
return;
}
if(!generated)
{
int[] indicies = this.getIndicies();
vao = GL33.glGenVertexArrays();
GL33.glBindVertexArray(vao);
vbo = GL33.glGenBuffers();
GL33.glBindBuffer(GL33.GL_ARRAY_BUFFER, vbo);
GL33.glBufferData(GL33.GL_ARRAY_BUFFER, getVerticies(), GL33.GL_DYNAMIC_DRAW);
Model.setGLArrayAttributes();
ibo = glGenBuffers();
glBindBuffer(GL33.GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(GL33.GL_ELEMENT_ARRAY_BUFFER, indicies, GL33.GL_STATIC_DRAW);
}
else {
GL33.glBindVertexArray(vao);
}
generated = true;
Model.bound = this;
}
@Override
public void render()
{
if(isDead()) {
return;
}
if(Model.bound != this) {
bind();
}
if(still != particles.length) {
GL33.glBindBuffer(GL33.GL_ARRAY_BUFFER, vbo);
GL33.glBufferSubData(GL33.GL_ARRAY_BUFFER, 0, getVerticies());
}
GL33.glDrawElements(GL33.GL_TRIANGLES, getIndexSize(), GL33.GL_UNSIGNED_INT, 0);
}
@Override
public void free()
{
if(generated)
{
GL33.glDeleteBuffers(ibo);
GL33.glDeleteBuffers(vbo);
GL33.glDeleteVertexArrays(vao);
generated = false;
}
}
public void setModel(Matrix4 model) {
GL33.glUniformMatrix4fv(Main.window.glsl_model, true, model.getArray());
}
@Override
public boolean isLoaded() {
return generated;
}
@Override
public double getWidth() {
return 1;
}
}