package net.sf.openrocket.gui.figure3d; import javax.media.opengl.GL; import javax.media.opengl.GL2; import javax.media.opengl.GL2ES1; import javax.media.opengl.GLAutoDrawable; import javax.media.opengl.fixedfunc.GLLightingFunc; import javax.media.opengl.fixedfunc.GLMatrixFunc; import net.sf.openrocket.appearance.Appearance; import net.sf.openrocket.appearance.Decal; import net.sf.openrocket.appearance.defaults.DefaultAppearance; import net.sf.openrocket.document.OpenRocketDocument; import net.sf.openrocket.gui.figure3d.geometry.Geometry; import net.sf.openrocket.gui.figure3d.geometry.Geometry.Surface; import net.sf.openrocket.motor.Motor; import net.sf.openrocket.rocketcomponent.RocketComponent; import net.sf.openrocket.util.Color; import com.jogamp.opengl.util.texture.Texture; public class RealisticRenderer extends RocketRenderer { private final float[] colorClear = { 0, 0, 0, 0 }; private final float[] colorWhite = { 1, 1, 1, 1 }; private final float[] color = new float[4]; private final TextureCache textures; private float anisotrophy = 0; public RealisticRenderer(OpenRocketDocument document) { textures = new TextureCache(); } @Override public void init(GLAutoDrawable drawable) { super.init(drawable); textures.init(drawable); GL2 gl = drawable.getGL().getGL2(); gl.glLightModelfv(GL2ES1.GL_LIGHT_MODEL_AMBIENT, new float[] { 0, 0, 0 }, 0); float amb = 0.3f; float dif = 1.0f - amb; float spc = 1.0f; gl.glLightfv(GLLightingFunc.GL_LIGHT1, GLLightingFunc.GL_AMBIENT, new float[] { amb, amb, amb, 1 }, 0); gl.glLightfv(GLLightingFunc.GL_LIGHT1, GLLightingFunc.GL_DIFFUSE, new float[] { dif, dif, dif, 1 }, 0); gl.glLightfv(GLLightingFunc.GL_LIGHT1, GLLightingFunc.GL_SPECULAR, new float[] { spc, spc, spc, 1 }, 0); gl.glEnable(GLLightingFunc.GL_LIGHT1); gl.glEnable(GLLightingFunc.GL_LIGHTING); gl.glShadeModel(GLLightingFunc.GL_SMOOTH); gl.glEnable(GLLightingFunc.GL_NORMALIZE); if (gl.isExtensionAvailable("GL_EXT_texture_filter_anisotropic")) { float a[] = new float[1]; gl.glGetFloatv(GL.GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, a, 0); anisotrophy = a[0]; } } @Override public void updateFigure(GLAutoDrawable drawable) { super.updateFigure(drawable); textures.advanceCacheGeneration(drawable); } @Override public void dispose(GLAutoDrawable drawable) { flushTextureCache(drawable); super.dispose(drawable); textures.dispose(drawable); } @Override public boolean isDrawn(RocketComponent c) { return true; } @Override public boolean isDrawnTransparent(RocketComponent c) { // if there is any degree of transparency, then... if (getAppearance(c).getPaint().getAlpha()<255){ return true; } return false; } @Override protected void renderMotor(final GL2 gl, final Motor motor) { render(gl, cr.getGeometry(motor, Surface.OUTSIDE), DefaultAppearance.getDefaultAppearance(motor), true, 1); } @Override public void renderComponent(final GL2 gl, final RocketComponent c, final float alpha) { if (isDrawnTransparent(c)){ // if transparent, draw inside the same as the outside so we dont get a cardboard interior on a clear payload bay render(gl, cr.getGeometry(c, Surface.INSIDE), getAppearance(c), true, alpha); }else{ render(gl, cr.getGeometry(c, Surface.INSIDE), DefaultAppearance.getDefaultAppearance(c), true, 1.0f); } render(gl, cr.getGeometry(c, Surface.OUTSIDE), getAppearance(c), true, alpha); render(gl, cr.getGeometry(c, Surface.EDGES), getAppearance(c), false, alpha); } private void render(GL2 gl, Geometry g, Appearance a, boolean decals, float alpha) { final Decal t = a.getTexture(); final Texture tex = textures.getTexture(t); gl.glLightModeli(GL2.GL_LIGHT_MODEL_COLOR_CONTROL, GL2.GL_SEPARATE_SPECULAR_COLOR); convertColor(a.getPaint(), color);//color now contains alpha value gl.glMaterialfv(GL.GL_FRONT, GLLightingFunc.GL_DIFFUSE, color, 0); gl.glMaterialfv(GL.GL_FRONT, GLLightingFunc.GL_AMBIENT, color, 0); color[0] = color[1] = color[2] = (float) a.getShine(); color[3] = 1;//no alpha for shine gl.glMaterialfv(GL.GL_FRONT, GLLightingFunc.GL_SPECULAR, color, 0); gl.glMateriali(GL.GL_FRONT, GLLightingFunc.GL_SHININESS, (int) (100 * a.getShine())); g.render(gl); if (decals && t != null && tex != null) { tex.enable(gl); tex.bind(gl); gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR_MIPMAP_LINEAR); gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR); gl.glMatrixMode(GL.GL_TEXTURE); gl.glPushMatrix(); gl.glTranslated(-t.getCenter().x, -t.getCenter().y, 0); gl.glRotated(57.2957795 * t.getRotation(), 0, 0, 1); gl.glTranslated(t.getCenter().x, t.getCenter().y, 0); gl.glScaled(t.getScale().x, t.getScale().y, 0); gl.glTranslated(t.getOffset().x, t.getOffset().y, 0); gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, toEdgeMode(t.getEdgeMode())); gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, toEdgeMode(t.getEdgeMode())); gl.glTexParameterfv(GL.GL_TEXTURE_2D, GL2.GL_TEXTURE_BORDER_COLOR, colorClear, 0); gl.glMaterialfv(GL.GL_FRONT, GLLightingFunc.GL_DIFFUSE, colorWhite, 0); gl.glMaterialfv(GL.GL_FRONT, GLLightingFunc.GL_AMBIENT, colorWhite, 0); gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA); gl.glEnable(GL.GL_BLEND); gl.glDepthFunc(GL.GL_LEQUAL); gl.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); if (anisotrophy > 0) { gl.glTexParameterf(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotrophy); } g.render(gl); if (t.getEdgeMode() == Decal.EdgeMode.STICKER) { gl.glDepthFunc(GL.GL_LESS); } gl.glMatrixMode(GL.GL_TEXTURE); gl.glPopMatrix(); gl.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); tex.disable(gl); } } @Override public void flushTextureCache(GLAutoDrawable drawable) { textures.flushTextureCache(drawable); } protected Appearance getAppearance(RocketComponent c) { Appearance ret = c.getAppearance(); if (ret == null) { ret = DefaultAppearance.getDefaultAppearance(c); } return ret; } private int toEdgeMode(Decal.EdgeMode m) { switch (m) { case REPEAT: return GL.GL_REPEAT; case MIRROR: return GL.GL_MIRRORED_REPEAT; case CLAMP: return GL.GL_CLAMP_TO_EDGE; case STICKER: return GL2.GL_CLAMP_TO_BORDER; default: return GL.GL_CLAMP_TO_EDGE; } } protected static void convertColor(Color color, float[] out) { if (color == null) { out[0] = 1; out[1] = 1; out[2] = 0; out[3] = 1; } else { out[0] = (float) color.getRed() / 255f; out[1] = (float) color.getGreen() / 255f; out[2] = (float) color.getBlue() / 255f; out[3] = (float) color.getAlpha() / 255f; } } }