package com.googlecode.gwtquake.shared.render; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer; import java.nio.IntBuffer; import com.googlecode.gwtquake.shared.common.Constants; import com.googlecode.gwtquake.shared.common.QuakeImage; import com.googlecode.gwtquake.shared.util.Lib; import com.googlecode.gwtquake.shared.util.Math3D; public class Particles { static final byte[][] dottexture = { {0,0,0,0,0,0,0,0}, {0,0,1,1,0,0,0,0}, {0,1,1,1,1,0,0,0}, {0,1,1,1,1,0,0,0}, {0,0,1,1,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, }; private static ByteBuffer colorByteArray = Lib.newByteBuffer( Constants.MAX_PARTICLES * Lib.SIZEOF_INT, ByteOrder.LITTLE_ENDIAN); public static FloatBuffer vertexArray = Lib.newFloatBuffer(Constants.MAX_PARTICLES * 3); public static int[] colorTable = new int[256]; public static IntBuffer colorArray = colorByteArray.asIntBuffer(); public static void setColorPalette(int[] palette) { for (int i = 0; i < 256; i++) { colorTable[i] = palette[i] & 0x00FFFFFF; } } public static ByteBuffer getColorAsByteBuffer() { return colorByteArray; } /** * GL_DrawParticles */ static void GL_DrawParticles(int num_particles) { float origin_x, origin_y, origin_z; Math3D.VectorScale(GlState.vup, 1.5f, GlState.up); Math3D.VectorScale(GlState.vright, 1.5f, GlState.right); Images.GL_Bind(GlState.r_particletexture.texnum); GlState.gl.glDepthMask(false); // no z buffering GlState.gl.glEnable(Gl1Context.GL_BLEND); Images.GL_TexEnv(Gl1Context.GL_MODULATE); GlState.gl.glBegin(Gl1Context.GL_TRIANGLES); FloatBuffer sourceVertices = Particles.vertexArray; IntBuffer sourceColors = Particles.colorArray; float scale; int color; for (int j = 0, i = 0; i < num_particles; i++) { origin_x = sourceVertices.get(j++); origin_y = sourceVertices.get(j++); origin_z = sourceVertices.get(j++); // hack a scale up to keep particles from disapearing scale = (origin_x - GlState.r_origin[0]) * GlState.vpn[0] + (origin_y - GlState.r_origin[1]) * GlState.vpn[1] + (origin_z - GlState.r_origin[2]) * GlState.vpn[2]; scale = (scale < 20) ? 1 : 1 + scale * 0.004f; color = sourceColors.get(i); GlState.gl.glColor4ub((byte) ((color) & 0xFF), (byte) ((color >> 8) & 0xFF), (byte) ((color >> 16) & 0xFF), (byte) ((color >>> 24))); // first vertex GlState.gl.glTexCoord2f(0.0625f, 0.0625f); GlState.gl.glVertex3f(origin_x, origin_y, origin_z); // second vertex GlState.gl.glTexCoord2f(1.0625f, 0.0625f); GlState.gl.glVertex3f(origin_x + GlState.up[0] * scale, origin_y + GlState.up[1] * scale, origin_z + GlState.up[2] * scale); // third vertex GlState.gl.glTexCoord2f(0.0625f, 1.0625f); GlState.gl.glVertex3f(origin_x + GlState.right[0] * scale, origin_y + GlState.right[1] * scale, origin_z + GlState.right[2] * scale); } GlState.gl.glEnd(); GlState.gl.glDisable(Gl1Context.GL_BLEND); GlState.gl.glColor4f(1, 1, 1, 1); GlState.gl.glDepthMask(true); // back to normal Z buffering Images.GL_TexEnv(Gl1Context.GL_REPLACE); } /** * R_DrawParticles */ static void draw() { if (GlConfig.gl_ext_pointparameters.value != 0.0f && GlState.qglPointParameterfEXT) { // gl.glEnableClientState(GLAdapter.GL_VERTEX_ARRAY); GlState.gl.glVertexPointer(3, 0, Particles.vertexArray); GlState.gl.glEnableClientState(Gl1Context.GL_COLOR_ARRAY); GlState.gl.glColorPointer(4, true, 0, Particles.getColorAsByteBuffer()); GlState.gl.glDepthMask(false); GlState.gl.glEnable(Gl1Context.GL_BLEND); GlState.gl.glDisable(Gl1Context.GL_TEXTURE_2D); GlState.gl.glPointSize(GlConfig.gl_particle_size.value); GlState.gl.glDrawArrays(Gl1Context.GL_POINTS, 0, GlState.r_newrefdef.num_particles); GlState.gl.glDisableClientState(Gl1Context.GL_COLOR_ARRAY); // gl.glDisableClientState(GLAdapter.GL_VERTEX_ARRAY); GlState.gl.glDisable(Gl1Context.GL_BLEND); GlState.gl.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); GlState.gl.glDepthMask(true); GlState.gl.glEnable(Gl1Context.GL_TEXTURE_2D); } else { GL_DrawParticles(GlState.r_newrefdef.num_particles); throw new RuntimeException("Old particle stuff"); } } static void R_InitParticleTexture() { int x, y; byte[] data = new byte[8 * 8 * 4]; // // particle texture // for (x = 0; x < 8; x++) { for (y = 0; y < 8; y++) { data[y * 32 + x * 4 + 0] = (byte) 255; data[y * 32 + x * 4 + 1] = (byte) 255; data[y * 32 + x * 4 + 2] = (byte) 255; data[y * 32 + x * 4 + 3] = (byte) (Particles.dottexture[x][y] * 255); } } GlState.r_particletexture = Images.GL_LoadPic("***particle***", data, 8, 8, QuakeImage.it_sprite, 32); // // also use this for bad textures, but without alpha // for (x = 0; x < 8; x++) { for (y = 0; y < 8; y++) { data[y * 32 + x * 4 + 0] = (byte) (Particles.dottexture[x & 3][y & 3] * 255); data[y * 32 + x * 4 + 1] = 0; // dottexture[x&3][y&3]*255; data[y * 32 + x * 4 + 2] = 0; // dottexture[x&3][y&3]*255; data[y * 32 + x * 4 + 3] = (byte) 255; } } GlState.r_notexture = Images.GL_LoadPic("***r_notexture***", data, 8, 8, QuakeImage.it_wall, 32); } }