package com.framsticks.net.client3D; import javax.media.opengl.GL; import javax.media.opengl.GLAutoDrawable; import javax.media.opengl.GLEventListener; import javax.media.opengl.glu.GLU; import pl.vorg.mowa.core.graphics.BoundingBox; import pl.vorg.mowa.core.graphics.SkyBox; import pl.vorg.mowa.core.graphics.Vec3; import com.sun.opengl.util.FPSAnimator; /** * Class responsible for rendering of framsticks and the world. * * @author vorg */ public class Renderer implements GLEventListener { public static final float AUTO_ROTATION_STEP = 0.5f; private float rotationY = 0; private float rotationX = 0; private float translation = -1.0f; private FPSAnimator animator; private World world; private Creature[] creatures; private Creature.ModelType modelType = Creature.ModelType.MechParts; private cgfxEffect style; private SkyBox skyBox; public SkyBox getSkyBox() { return skyBox; } public void setSkyBox(SkyBox box) { skyBox = box; } public cgfxEffect getStyle() { return style; } /** * Sets the currently used framstick rendering style. * * @param style */ public void setStyle(cgfxEffect style) { this.style = style; } public Creature[] getCreatures() { return creatures; } /** * Sets the number of creatures to display. To display a single creature in * a zoomed view pass a single element array and set the modelType to * Creature.ModelType.Parts. * * @param creatures */ public void setCreatures(Creature[] creatures) { this.creatures = creatures; } public World getWorld() { return world; } /** * Sets the world to be displayed. * * @param world */ public void setWorld(World world) { this.world = world; } public Creature.ModelType getModelType() { return modelType; } /** * Sets how the framsticks should be rendered. * * @param modelType * Creature.ModelType.Parts - the way they were created, * Creature.ModelType.MechParts - the way they currently look in * their world (in accordance with physics) */ public void setModelType(Creature.ModelType modelType) { this.modelType = modelType; } public float getTranslation() { return translation; } public void setTranslation(float t) { translation = t; if (translation < 0.1) translation = 0.1f; } public void resetTranslation() { translation = -1.0f; } public float getRotationX() { return rotationX; } public float getRotationY() { return rotationY; } public void setRotationX(float rotation) { this.rotationX = rotation; if (this.rotationX > 85.0) this.rotationX = 85.0f; else if (this.rotationX < 0) this.rotationX = 0.0f; } public void setRotationY(float rotation) { this.rotationY = rotation; } public void display(GLAutoDrawable drawable) { style.setSkyBox(skyBox); GL gl = drawable.getGL(); gl.glLoadIdentity(); gl.glClear(GL.GL_DEPTH_BUFFER_BIT | GL.GL_COLOR_BUFFER_BIT); if ((creatures != null) && (creatures.length == 1) && (modelType == Creature.ModelType.Parts)) { // renderowanie pojedynczego framsticka drawCreature(gl); } else { // renderowanie calaego swiata wraz z framstickami z nim zyjacymi drawWorld(gl); } gl.glFlush(); } public void drawWorld(GL gl) { // szescian otaczajacy swiat // wyliczamy go po to aby ustawic kamere tak aby byla w stanie objac // wszystko BoundingBox bbox; if ((world != null) && (world.getGeometry() != null)) { bbox = world.getGeometry().getBoundingBox(); } else { bbox = new BoundingBox(); if (creatures != null) { for (Creature c : creatures) { bbox.add(c.getBoundingBox(Creature.ModelType.MechParts)); } } } Vec3 bboxSize = bbox.getSize(); Vec3 bboxCenter = Vec3 .mul(0.5f, Vec3.add(bbox.getMax(), bbox.getMin())); if (translation < 0 || translation > 100000000.0f) { translation = (float) Math.sqrt(bboxSize.getX() * bboxSize.getX() / 4 + bboxSize.getZ() * bboxSize.getZ() / 4) * 1.5f; } gl.glTranslatef(0, 0, -1.0f * translation); // gl.glRotatef(30, 1, 0, 0); gl.glRotatef(rotationX, 1, 0, 0); gl.glRotatef(rotationY, 0, 1, 0); gl.glTranslatef(-bboxCenter.getX(), -bboxCenter.getY() - 2, -bboxCenter .getZ()); if (skyBox != null) skyBox.Draw(gl, 1000.0f, new Vec3(rotationX, rotationY, 0)); // renderowanie swiata if ((world != null) && (world.getGeometry() != null) && !world.getGeometry().getBoundingBox().isEmpty()) { BoundingBox wrldBox = world.getGeometry().getBoundingBox(); Vec3 wmin = wrldBox.getMin(); Vec3 wmax = wrldBox.getMax(); drawWorldGeometry(gl); drawWater(gl, wmin, wmax); if (world.getBoundaries() == 0) { drawWorldNoBounduaries(gl, wmin, wmax); } else if (world.getBoundaries() == 1) { drawWorldFence(gl, wmin, wmax); } else if (world.getBoundaries() == 2) { drawWorldTeleports(gl, wmin, wmax); } } // renderowanie stworow if ((creatures != null) && (style != null)) { if (!style.isInitialized()) { style.Init(); if (!style.isInitialized()) { setStyle(null); return; } } style.render(gl, creatures, Creature.ModelType.MechParts); } } /** * Rendering of the world surface. * * @param gl */ private void drawWorldGeometry(GL gl) { gl.glEnable(GL.GL_LIGHTING); gl.glEnable(GL.GL_LIGHT0); gl.glColor4f(0.9f, 0.8f, 0.2f, 0.0f); gl.glEnable(GL.GL_COLOR_MATERIAL); gl.glDisable(GL.GL_BLEND); world.getGeometry().display(gl); gl.glDisable(GL.GL_COLOR_MATERIAL); gl.glDisable(GL.GL_LIGHTING); // gl.glEnable(GL.GL_CULL_FACE); gl.glColor4f(0.7f, 0.7f, 0.7f, 0.1f); gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL.GL_LINE); gl.glEnable(GL.GL_LINE_SMOOTH); gl.glEnable(GL.GL_BLEND); // gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA); gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_DST_COLOR); gl.glHint(GL.GL_LINE_SMOOTH_HINT, GL.GL_DONT_CARE); gl.glLineWidth(2.5f); world.getGeometry().display(gl); gl.glDisable(GL.GL_BLEND); gl.glDisable(GL.GL_LINE_SMOOTH); gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL.GL_FILL); } /** * Rendering of the world boundaries which consist of teleports (you get in * on one side of the world and get out on the opposite side). * * @param gl * @param wmin * @param wmax */ private void drawWorldTeleports(GL gl, Vec3 wmin, Vec3 wmax) { gl.glEnable(GL.GL_BLEND); gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA); gl.glColor4f(0.0f, 0.4f, 0.9f, 0.5f); gl.glBegin(GL.GL_TRIANGLES); for (float z = -wmin.getZ(); z < wmax.getZ(); z += 1) { gl.glVertex3f(wmin.getX(), 0, z); gl.glVertex3f(wmin.getX(), 0, z + 1); gl.glVertex3f(wmin.getX(), 1, z + 0.5f); } for (float z = -wmin.getZ(); z < wmax.getZ(); z += 1) { gl.glVertex3f(wmax.getX(), 0, z); gl.glVertex3f(wmax.getX(), 0, z + 1); gl.glVertex3f(wmax.getX(), 1, z + 0.5f); } for (float x = -wmin.getX(); x < wmax.getX(); x += 1) { gl.glVertex3f(x, 0, wmin.getZ()); gl.glVertex3f(x + 1, 0, wmin.getZ()); gl.glVertex3f(x + 0.5f, 1, wmin.getZ()); } for (float x = -wmin.getX(); x < wmax.getX(); x += 1) { gl.glVertex3f(x, 0, wmax.getZ()); gl.glVertex3f(x + 1, 0, wmax.getZ()); gl.glVertex3f(x + 0.5f, 1, wmax.getZ()); } gl.glEnd(); gl.glDisable(GL.GL_BLEND); } /** * Rendering of the world boundaries which consist of a fence. * * @param gl * @param wmin * @param wmax */ private void drawWorldFence(GL gl, Vec3 wmin, Vec3 wmax) { gl.glEnable(GL.GL_BLEND); gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA); gl.glColor4f(1.0f, 0.2f, 0.0f, 0.5f); gl.glBegin(GL.GL_QUADS); for (float z = -wmin.getZ(); z < wmax.getZ(); z += 1) { gl.glVertex3f(wmin.getX(), 0, z); gl.glVertex3f(wmin.getX(), 0, z + 1); gl.glVertex3f(wmin.getX(), 1, z + 1); gl.glVertex3f(wmin.getX(), 1, z); } for (float z = -wmin.getZ(); z < wmax.getZ(); z += 1) { gl.glVertex3f(wmax.getX(), 0, z); gl.glVertex3f(wmax.getX(), 0, z + 1); gl.glVertex3f(wmax.getX(), 1, z + 1); gl.glVertex3f(wmax.getX(), 1, z); } for (float x = -wmin.getX(); x < wmax.getX(); x += 1) { gl.glVertex3f(x, 0, wmin.getZ()); gl.glVertex3f(x + 1, 0, wmin.getZ()); gl.glVertex3f(x + 1, 1, wmin.getZ()); gl.glVertex3f(x, 1, wmin.getZ()); } for (float x = -wmin.getX(); x < wmax.getX(); x += 1) { gl.glVertex3f(x, 0, wmax.getZ()); gl.glVertex3f(x + 1, 0, wmax.getZ()); gl.glVertex3f(x + 1, 1, wmax.getZ()); gl.glVertex3f(x, 1, wmax.getZ()); } gl.glEnd(); gl.glDisable(GL.GL_BLEND); } /** * Rendering of the unbounded world boundaries. * * @param gl * @param wmin * @param wmax */ private void drawWorldNoBounduaries(GL gl, Vec3 wmin, Vec3 wmax) { gl.glEnable(GL.GL_BLEND); gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA); gl.glBegin(GL.GL_QUADS); for (float z = -wmin.getZ(); z < wmax.getZ(); z += 1) { gl.glColor4f(1.0f, 0.8f, 0.0f, 0.5f); gl.glVertex3f(wmin.getX(), 0, z); gl.glVertex3f(wmin.getX(), 0, z + 1); gl.glColor4f(1.0f, 0.8f, 0.0f, 0.0f); gl.glVertex3f(wmin.getX() - 2, 0, z + 1); gl.glVertex3f(wmin.getX() - 2, 0, z); } for (float z = -wmin.getZ(); z < wmax.getZ(); z += 1) { gl.glColor4f(1.0f, 0.8f, 0.0f, 0.5f); gl.glVertex3f(wmax.getX(), 0, z); gl.glVertex3f(wmax.getX(), 0, z + 1); gl.glColor4f(1.0f, 0.8f, 0.0f, 0.0f); gl.glVertex3f(wmax.getX() + 2, 0, z + 1); gl.glVertex3f(wmax.getX() + 2, 0, z); } for (float x = -wmin.getX(); x < wmax.getX(); x += 1) { gl.glColor4f(1.0f, 0.8f, 0.0f, 0.5f); gl.glVertex3f(x, 0, wmin.getZ()); gl.glVertex3f(x + 1, 0, wmin.getZ()); gl.glColor4f(1.0f, 0.8f, 0.0f, 0.0f); gl.glVertex3f(x + 1, 0, wmin.getZ() - 2); gl.glVertex3f(x, 0, wmin.getZ() - 2); } for (float x = -wmin.getX(); x < wmax.getX(); x += 1) { gl.glColor4f(1.0f, 0.8f, 0.0f, 0.5f); gl.glVertex3f(x, 0, wmax.getZ()); gl.glVertex3f(x + 1, 0, wmax.getZ()); gl.glColor4f(1.0f, 0.8f, 0.0f, 0.0f); gl.glVertex3f(x + 1, 0, wmax.getZ() + 2); gl.glVertex3f(x, 0, wmax.getZ() + 2); } gl.glEnd(); gl.glBegin(GL.GL_TRIANGLES); gl.glColor4f(1.0f, 0.8f, 0.0f, 0.5f); gl.glVertex3f(wmin.getX(), 0, wmin.getX()); gl.glColor4f(1.0f, 0.8f, 0.0f, 0.0f); gl.glVertex3f(wmin.getX(), 0, wmin.getX() - 2); gl.glVertex3f(wmin.getX() - 2, 0, wmin.getX()); gl.glColor4f(1.0f, 0.8f, 0.0f, 0.5f); gl.glVertex3f(wmax.getX(), 0, wmin.getX()); gl.glColor4f(1.0f, 0.8f, 0.0f, 0.0f); gl.glVertex3f(wmax.getX(), 0, wmin.getX() - 2); gl.glVertex3f(wmax.getX() + 2, 0, wmin.getX()); gl.glColor4f(1.0f, 0.8f, 0.0f, 0.5f); gl.glVertex3f(wmax.getX(), 0, wmax.getX()); gl.glColor4f(1.0f, 0.8f, 0.0f, 0.0f); gl.glVertex3f(wmax.getX(), 0, wmax.getX() + 2); gl.glVertex3f(wmax.getX() + 2, 0, wmax.getX()); gl.glColor4f(1.0f, 0.8f, 0.0f, 0.5f); gl.glVertex3f(wmin.getX(), 0, wmax.getX()); gl.glColor4f(1.0f, 0.8f, 0.0f, 0.0f); gl.glVertex3f(wmin.getX(), 0, wmax.getX() + 2); gl.glVertex3f(wmin.getX() - 2, 0, wmax.getX()); gl.glEnd(); gl.glDisable(GL.GL_BLEND); } /** * Rendering of the water surface. * * @param gl * @param wmin * @param wmax */ private void drawWater(GL gl, Vec3 wmin, Vec3 wmax) { float wlev = world.getWaterLevel(); gl.glEnable(GL.GL_BLEND); gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA); gl.glBegin(GL.GL_QUADS); gl.glColor4f(0.1f, 0.5f, 0.9f, 0.3f); gl.glVertex3f(wmin.getX() - 5, wlev - 0.02f, wmin.getZ() - 5); gl.glColor4f(0.1f, 0.8f, 0.9f, 0.3f); gl.glVertex3f(wmin.getX() - 5, wlev - 0.02f, wmax.getZ() + 5); gl.glColor4f(0.1f, 0.5f, 0.9f, 0.3f); gl.glVertex3f(wmax.getX() + 5, wlev - 0.02f, wmax.getZ() + 5); gl.glColor4f(0.1f, 0.8f, 0.9f, 0.3f); gl.glVertex3f(wmax.getX() + 5, wlev - 0.02f, wmin.getZ() - 5); gl.glColor4f(0.0f, 0.0f, 0.0f, 0.2f); gl.glVertex3f(wmin.getX() - 0.5f, wlev - 0.01f, wmin.getZ() - 0.5f); gl.glVertex3f(wmin.getX() - 0.5f, wlev - 0.01f, wmax.getZ() + 0.5f); gl.glVertex3f(wmax.getX() + 0.5f, wlev - 0.01f, wmax.getZ() + 0.5f); gl.glVertex3f(wmax.getX() + 0.5f, wlev - 0.01f, wmin.getZ() - 0.5f); gl.glEnd(); gl.glDisable(GL.GL_BLEND); } /** * Rendering of a single creature. * * @param gl */ private void drawCreature(GL gl) { BoundingBox bbox = creatures[0] .getBoundingBox(Creature.ModelType.Parts); Vec3 bboxSize = bbox.getSize(); Vec3 bboxCenter = Vec3 .mul(0.5f, Vec3.add(bbox.getMax(), bbox.getMin())); if (translation < 0) { translation = (float) Math.sqrt(bboxSize.getX() * bboxSize.getX() / 4 + bboxSize.getZ() * bboxSize.getZ() / 4); } gl.glTranslatef(0, 0, -1.0f * translation - 1); // gl.glRotatef(30, 1, 0, 0); gl.glRotatef(rotationX, 1, 0, 0); gl.glRotatef(rotationY, 0, 1, 0); gl.glTranslatef(-bboxCenter.getX(), -bboxCenter.getY(), -bboxCenter .getZ()); if (skyBox != null) skyBox.Draw(gl, 1000.0f, new Vec3(rotationX, rotationY, 0)); if (style != null) { if (!style.isInitialized()) { style.Init(); if (!style.isInitialized()) { setStyle(null); return; } } // effect.render(gl, creatures, Creature.ModelType.Parts); style.render(gl, creatures, Creature.ModelType.Parts); } } public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged) { } public void init(GLAutoDrawable drawable) { Log.getInstance().log("dbg", "Renderer.init"); Log.getInstance().log("dbg", "Renderer.init creating animator"); animator = new FPSAnimator(30); animator.add(drawable); animator.start(); animator.setRunAsFastAsPossible(false); rotationX = 30.0f; rotationY = 0.0f; Log.getInstance().log("dbg", "Renderer.init initializing opengl"); GL gl = drawable.getGL(); gl.glLoadIdentity(); gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f); gl.glColor3f(1.0f, 1.0f, 1.0f); gl.glClearDepth(1.0); gl.glEnable(GL.GL_DEPTH_TEST); gl.glDepthFunc(GL.GL_LEQUAL); skyBox = new SkyBox(); skyBox.Init(gl); // style.Init(); Log.getInstance().log("dbg", "Renderer.init done"); } /** * Adjust the view to the application's window size. */ public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { GL gl = drawable.getGL(); GLU glu = new GLU(); gl.glMatrixMode(GL.GL_PROJECTION); gl.glLoadIdentity(); glu.gluPerspective(90, (float) width / (float) height, 0.015, 1000); gl.glMatrixMode(GL.GL_MODELVIEW); } }