Move rules about how to render what into RenderStrategies. Implement Figure & Realistic strategies.

This commit is contained in:
Bill Kuker 2012-07-01 14:49:52 +00:00 committed by U-WINDOWS-C28163E\Administrator
parent 0621c1971d
commit fef4c39f73
4 changed files with 340 additions and 125 deletions

View File

@ -0,0 +1,118 @@
package net.sf.openrocket.gui.figure3d;
import java.util.HashMap;
import javax.media.opengl.GL;
import javax.media.opengl.GL2;
import javax.media.opengl.GL2ES1;
import javax.media.opengl.fixedfunc.GLLightingFunc;
import net.sf.openrocket.rocketcomponent.BodyTube;
import net.sf.openrocket.rocketcomponent.ExternalComponent;
import net.sf.openrocket.rocketcomponent.NoseCone;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.rocketcomponent.SymmetricComponent;
import net.sf.openrocket.rocketcomponent.Transition;
import net.sf.openrocket.startup.Application;
import net.sf.openrocket.util.Color;
public class FigureRenderStrategy extends RenderStrategy {
private final float[] color = new float[4];
@Override
public boolean isDrawn(RocketComponent c) {
return true;
}
@Override
public boolean isDrawnTransparent(RocketComponent c) {
if (c instanceof BodyTube)
return true;
if (c instanceof NoseCone)
return false;
if (c instanceof SymmetricComponent) {
if (((SymmetricComponent) c).isFilled())
return false;
}
if (c instanceof Transition) {
Transition t = (Transition) c;
return !t.isAftShoulderCapped() && !t.isForeShoulderCapped();
}
return false;
}
private static final HashMap<Class<?>, Color> defaultColorCache = new HashMap<Class<?>, Color>();
@Override
public void preGeometry(GL2 gl, RocketComponent c, float alpha) {
gl.glLightModeli(GL2ES1.GL_LIGHT_MODEL_TWO_SIDE, 1);
Color figureColor = c.getColor();
if (figureColor == null) {
if (defaultColorCache.containsKey(c.getClass())) {
figureColor = defaultColorCache.get(c.getClass());
} else {
figureColor = Application.getPreferences().getDefaultColor(c.getClass());
defaultColorCache.put(c.getClass(), figureColor);
}
}
// Set up the front A&D color
convertColor(figureColor, color);
color[3] = alpha;
gl.glMaterialfv(GL.GL_FRONT, GLLightingFunc.GL_DIFFUSE, color, 0);
gl.glMaterialfv(GL.GL_FRONT, GLLightingFunc.GL_AMBIENT, color, 0);
// Set up the Specular color & Shine
convertColor(figureColor, color);
float d = 0.9f;
float m = (float) getShine(c) / 128.0f;
color[0] = Math.max(color[0], d) * m;
color[1] = Math.max(color[1], d) * m;
color[2] = Math.max(color[2], d) * m;
gl.glMaterialfv(GL.GL_FRONT, GLLightingFunc.GL_SPECULAR, color, 0);
gl.glMateriali(GL.GL_FRONT, GLLightingFunc.GL_SHININESS, getShine(c));
color[0] = color[1] = color[2] = 0;
gl.glMaterialfv(GL.GL_BACK, GLLightingFunc.GL_SPECULAR, color, 0);
//Back A&D
convertColor(figureColor, color);
color[0] = color[0] * 0.4f;
color[1] = color[1] * 0.4f;
color[2] = color[2] * 0.4f;
color[3] = alpha;
gl.glMaterialfv(GL.GL_BACK, GLLightingFunc.GL_DIFFUSE, color, 0);
gl.glMaterialfv(GL.GL_BACK, GLLightingFunc.GL_AMBIENT, color, 0);
}
@Override
public void postGeometry(GL2 gl, RocketComponent c, float alpha) {
//Nothing to do here
}
private static int getShine(RocketComponent c) {
if (c instanceof ExternalComponent) {
switch (((ExternalComponent) c).getFinish()) {
case ROUGH:
return 10;
case UNFINISHED:
return 30;
case NORMAL:
return 40;
case SMOOTH:
return 80;
case POLISHED:
return 128;
default:
return 100;
}
}
return 20;
}
}

View File

@ -0,0 +1,153 @@
package net.sf.openrocket.gui.figure3d;
import java.util.HashMap;
import java.util.Map;
import javax.media.opengl.GL;
import javax.media.opengl.GL2;
import javax.media.opengl.GL2ES1;
import javax.media.opengl.GLProfile;
import javax.media.opengl.fixedfunc.GLLightingFunc;
import javax.media.opengl.fixedfunc.GLMatrixFunc;
import com.jogamp.opengl.util.texture.Texture;
import com.jogamp.opengl.util.texture.TextureData;
import com.jogamp.opengl.util.texture.TextureIO;
import net.sf.openrocket.appearance.Appearance;
import net.sf.openrocket.appearance.Decal;
import net.sf.openrocket.logging.LogHelper;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.startup.Application;
public class RealisticRenderStrategy extends RenderStrategy {
private final float[] color = new float[4];
private static final LogHelper log = Application.getLogger();
private Map<RocketComponent, Appearance> apMap = new HashMap<RocketComponent, Appearance>();
private Map<Decal, Texture> texCache = new HashMap<Decal, Texture>();
@Override
public void clearCaches() {
apMap.clear();
texCache.clear();
}
@Override
public boolean isDrawn(RocketComponent c) {
return true;
}
@Override
public boolean isDrawnTransparent(RocketComponent c) {
return false;
}
@Override
public void preGeometry(GL2 gl, RocketComponent c, float alpha) {
Appearance a = getAppearance(c);
gl.glLightModeli(GL2ES1.GL_LIGHT_MODEL_TWO_SIDE, 1);
convertColor(a.getDiffuse(), color);
color[3] = alpha;
gl.glMaterialfv(GL.GL_FRONT, GLLightingFunc.GL_DIFFUSE, color, 0);
convertColor(a.getAmbient(), color);
color[3] = alpha;
gl.glMaterialfv(GL.GL_FRONT, GLLightingFunc.GL_AMBIENT, color, 0);
convertColor(a.getSpecular(), color);
color[3] = alpha;
gl.glMaterialfv(GL.GL_FRONT, GLLightingFunc.GL_SPECULAR, color, 0);
gl.glMateriali(GL.GL_FRONT, GLLightingFunc.GL_SHININESS, a.getShininess());
convertColor(a.getDiffuse(), color);
color[3] = alpha;
gl.glMaterialfv(GL.GL_BACK, GLLightingFunc.GL_DIFFUSE, color, 0);
gl.glMaterialfv(GL.GL_BACK, GLLightingFunc.GL_AMBIENT, color, 0);
Decal t = a.getTexture();
Texture tex = null;
if (t != null) {
tex = getTexture(t);
}
if (t != null && tex != null) {
tex.enable(gl);
tex.bind(gl);
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_S, toEdgeMode(t.getEdgeMode()));
gl.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
}
}
@Override
public void postGeometry(GL2 gl, RocketComponent c, float alpha) {
Appearance a = getAppearance(c);
Decal t = a.getTexture();
Texture tex = null;
if (t != null) {
tex = getTexture(t);
}
if (tex != null) {
gl.glMatrixMode(GL.GL_TEXTURE);
gl.glPopMatrix();
gl.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
tex.disable(gl);
}
}
private Texture getTexture(Decal t) {
if (texCache.containsKey(t))
return texCache.get(t);
Texture tex = null;
try {
log.debug("Loading texture " + t);
TextureData data = TextureIO.newTextureData(GLProfile.getDefault(), t.getImageURL().openStream(), true,
null);
tex = TextureIO.newTexture(data);
} catch (Throwable e) {
log.error("Error loading Texture", e);
}
texCache.put(t, tex);
return tex;
}
private Appearance getAppearance(RocketComponent c) {
if (apMap.containsKey(c))
return apMap.get(c);
Appearance ret = c.getAppearance();
if (ret == null) {
ret = Appearance.MISSING;
}
apMap.put(c, ret);
System.out.println(c + ": " + ret);
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;
default:
return GL.GL_CLAMP_TO_EDGE;
}
}
}

View File

@ -0,0 +1,31 @@
package net.sf.openrocket.gui.figure3d;
import javax.media.opengl.GL2;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.util.Color;
public abstract class RenderStrategy {
public abstract boolean isDrawn(RocketComponent c);
public abstract boolean isDrawnTransparent(RocketComponent c);
public abstract void preGeometry(GL2 gl, RocketComponent c, float alpha);
public abstract void postGeometry(GL2 gl, RocketComponent c, float alpha);
public void clearCaches(){
}
protected static void convertColor(Color color, float[] out) {
if ( color == null ){
out[0] = 1;
out[1] = 1;
out[2] = 0;
} else {
out[0] = Math.max(0.2f, (float) color.getRed() / 255f);
out[1] = Math.max(0.2f, (float) color.getGreen() / 255f);
out[2] = Math.max(0.2f, (float) color.getBlue() / 255f);
}
}
}

View File

@ -2,40 +2,38 @@ package net.sf.openrocket.gui.figure3d;
import java.awt.Point;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;
import java.util.Vector;
import javax.media.opengl.GL;
import javax.media.opengl.GL2;
import javax.media.opengl.GL2ES1;
import javax.media.opengl.GL2GL3;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.fixedfunc.GLLightingFunc;
import net.sf.openrocket.logging.LogHelper;
import net.sf.openrocket.motor.Motor;
import net.sf.openrocket.rocketcomponent.BodyTube;
import net.sf.openrocket.rocketcomponent.Configuration;
import net.sf.openrocket.rocketcomponent.ExternalComponent;
import net.sf.openrocket.rocketcomponent.MotorMount;
import net.sf.openrocket.rocketcomponent.NoseCone;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.rocketcomponent.SymmetricComponent;
import net.sf.openrocket.rocketcomponent.Transition;
import net.sf.openrocket.startup.Application;
import net.sf.openrocket.util.Color;
import net.sf.openrocket.util.Coordinate;
/*
* @author Bill Kuker <bkuker@billkuker.com>
*/
public class RocketRenderer {
@SuppressWarnings("unused")
private static final LogHelper log = Application.getLogger();
RenderStrategy currentStrategy = new RealisticRenderStrategy();
ComponentRenderer cr;
private final float[] selectedEmissive = { 1, 0, 0, 1 };
private final float[] colorBlack = { 0, 0, 0, 1 };
private final float[] color = new float[4];
public void init(GLAutoDrawable drawable) {
cr = new ComponentRenderer();
@ -43,28 +41,10 @@ public class RocketRenderer {
}
public void updateFigure() {
currentStrategy.clearCaches();
cr.updateFigure();
}
private boolean isDrawn(RocketComponent c) {
return true;
}
private boolean isDrawnTransparent(RocketComponent c) {
if (c instanceof BodyTube)
return true;
if (c instanceof NoseCone)
return false;
if (c instanceof SymmetricComponent) {
if (((SymmetricComponent) c).isFilled())
return false;
}
if (c instanceof Transition) {
Transition t = (Transition) c;
return !t.isAftShoulderCapped() && !t.isForeShoulderCapped();
}
return false;
}
public RocketComponent pick(GLAutoDrawable drawable,
Configuration configuration, Point p, Set<RocketComponent> ignore) {
@ -87,7 +67,7 @@ public class RocketRenderer {
(byte) ((pickParts.size() << 4) & 0xF0), (byte) 1);
pickParts.add(c);
if (isDrawnTransparent(c)) {
if (currentStrategy.isDrawnTransparent(c)) {
gl.glEnable(GL.GL_CULL_FACE);
gl.glCullFace(GL.GL_FRONT);
cr.renderGeometry(gl, c);
@ -102,8 +82,8 @@ public class RocketRenderer {
gl.glReadPixels(p.x, p.y, 1, 1, GL.GL_RGB, GL.GL_UNSIGNED_BYTE, bb);
final int pickColor = bb.getInt();
final int pickIndex = ((pickColor >> 20) & 0xF00) | ((pickColor >> 16) & 0x0F0)
| ((pickColor >> 12) & 0x00F);
final int pickIndex = ((pickColor >> 20) & 0xF00)
| ((pickColor >> 16) & 0x0F0) | ((pickColor >> 12) & 0x00F);
if (pickIndex < 0 || pickIndex > pickParts.size() - 1)
return null;
@ -123,8 +103,8 @@ public class RocketRenderer {
// Draw all inner components
for (RocketComponent c : configuration) {
if (isDrawn(c)) {
if (!isDrawnTransparent(c)) {
if (currentStrategy.isDrawn(c)) {
if (!currentStrategy.isDrawnTransparent(c)) {
renderComponent(gl, c, 1.0f);
}
}
@ -137,8 +117,8 @@ public class RocketRenderer {
gl.glEnable(GL.GL_CULL_FACE);
gl.glCullFace(GL.GL_FRONT);
for (RocketComponent c : configuration) {
if (isDrawn(c)) {
if (isDrawnTransparent(c)) {
if (currentStrategy.isDrawn(c)) {
if (currentStrategy.isDrawnTransparent(c)) {
renderComponent(gl, c, 1.0f);
}
}
@ -150,8 +130,8 @@ public class RocketRenderer {
gl.glEnable(GL.GL_CULL_FACE);
gl.glCullFace(GL.GL_BACK);
for (RocketComponent c : configuration) {
if (isDrawn(c)) {
if (isDrawnTransparent(c)) {
if (currentStrategy.isDrawn(c)) {
if (currentStrategy.isDrawnTransparent(c)) {
renderComponent(gl, c, 0.2f);
}
}
@ -161,9 +141,12 @@ public class RocketRenderer {
gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GLLightingFunc.GL_EMISSION,
selectedEmissive, 0);
gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GLLightingFunc.GL_DIFFUSE, colorBlack, 0);
gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GLLightingFunc.GL_AMBIENT, colorBlack, 0);
gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GLLightingFunc.GL_SPECULAR, colorBlack, 0);
gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GLLightingFunc.GL_DIFFUSE,
colorBlack, 0);
gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GLLightingFunc.GL_AMBIENT,
colorBlack, 0);
gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GLLightingFunc.GL_SPECULAR,
colorBlack, 0);
gl.glDepthMask(false);
gl.glDisable(GL.GL_DEPTH_TEST);
@ -224,80 +207,10 @@ public class RocketRenderer {
}
public void renderComponent(GL2 gl, RocketComponent c, float alpha) {
gl.glLightModeli(GL2ES1.GL_LIGHT_MODEL_TWO_SIDE, 1);
getOutsideColor(c, alpha, color);
gl.glMaterialfv(GL.GL_FRONT, GLLightingFunc.GL_DIFFUSE, color, 0);
gl.glMaterialfv(GL.GL_FRONT, GLLightingFunc.GL_AMBIENT, color, 0);
getSpecularColor(c, alpha, color);
gl.glMaterialfv(GL.GL_FRONT, GLLightingFunc.GL_SPECULAR, color, 0);
gl.glMateriali(GL.GL_FRONT, GLLightingFunc.GL_SHININESS,
getShininess(c));
getInsideColor(c, alpha, color);
gl.glMaterialfv(GL.GL_BACK, GLLightingFunc.GL_DIFFUSE, color, 0);
gl.glMaterialfv(GL.GL_BACK, GLLightingFunc.GL_AMBIENT, color, 0);
currentStrategy.preGeometry(gl, c, alpha);
cr.renderGeometry(gl, c);
currentStrategy.postGeometry(gl, c, alpha);
}
private int getShininess(RocketComponent c) {
if (c instanceof ExternalComponent) {
switch (((ExternalComponent) c).getFinish()) {
case ROUGH:
return 10;
case UNFINISHED:
return 30;
case NORMAL:
return 40;
case SMOOTH:
return 80;
case POLISHED:
return 128;
}
return 100;
} else {
return 20;
}
}
private void getSpecularColor(RocketComponent c, float alpha, float[] out) {
int shine = getShininess(c);
float m = (float) shine / 128.0f;
float d = 0.9f;
getOutsideColor(c, alpha, out);
out[0] = Math.max(out[0], d) * m;
out[1] = Math.max(out[1], d) * m;
out[2] = Math.max(out[2], d) * m;
}
private void getInsideColor(RocketComponent c, float alpha, float[] out) {
float d = 0.4f;
getOutsideColor(c, alpha, out);
out[0] *= d;
out[1] *= d;
out[2] *= d;
}
private HashMap<Class<?>, Color> defaultColorCache = new HashMap<Class<?>, Color>();
private void getOutsideColor(RocketComponent c, float alpha, float[] out) {
Color col;
col = c.getColor();
if (col == null){
if ( defaultColorCache.containsKey(c.getClass()) ){
col = defaultColorCache.get(c.getClass());
} else {
col = Application.getPreferences().getDefaultColor(c.getClass());
defaultColorCache.put(c.getClass(), col);
}
}
out[0] = Math.max(0.2f, (float) col.getRed() / 255f);
out[1] = Math.max(0.2f, (float) col.getGreen() / 255f);
out[2] = Math.max(0.2f, (float) col.getBlue() / 255f);
out[3] = alpha;
}
}