package org.osm2world.core.target.jogl;
import static java.util.Arrays.asList;
import static javax.media.opengl.GL.*;
import static javax.media.opengl.GL2.GL_POLYGON;
import static org.osm2world.core.target.jogl.NonAreaPrimitive.Type.*;
import java.awt.Color;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.List;
import javax.media.opengl.GL;
import org.osm2world.core.math.VectorXYZ;
import org.osm2world.core.math.VectorXZ;
import org.osm2world.core.target.common.Primitive;
import org.osm2world.core.target.common.Primitive.Type;
import org.osm2world.core.target.common.PrimitiveTarget;
import org.osm2world.core.target.common.TextureData;
import org.osm2world.core.target.common.lighting.GlobalLightingParameters;
import org.osm2world.core.target.common.material.Material;
import org.osm2world.core.target.common.rendering.Camera;
import org.osm2world.core.target.common.rendering.Projection;
/**
* Common implementation base for the new shader based {@link JOGLTargetShader} and the old {@link JOGLTargetFixedFunction}
*/
public abstract class AbstractJOGLTarget extends PrimitiveTarget<RenderableToJOGL> implements JOGLTarget {
protected PrimitiveBuffer primitiveBuffer;
protected List<NonAreaPrimitive> nonAreaPrimitives;
protected JOGLRenderer renderer;
protected JOGLTextureManager textureManager;
protected JOGLRenderingParameters renderingParameters;
protected GlobalLightingParameters globalLightingParameters;
public AbstractJOGLTarget(GL gl, JOGLRenderingParameters renderingParameters,
GlobalLightingParameters globalLightingParameters) {
this.textureManager = new JOGLTextureManager(gl);
this.renderingParameters = renderingParameters;
this.globalLightingParameters = globalLightingParameters;
}
@Override
public Class<RenderableToJOGL> getRenderableType() {
return RenderableToJOGL.class;
}
@Override
public void render(RenderableToJOGL renderable) {
renderable.renderTo(this);
}
@Override
public void render(Camera camera, Projection projection) {
renderPart(camera, projection, 0, 1, 0, 1);
}
@Override
protected void drawPrimitive(Primitive.Type type, Material material,
List<VectorXYZ> vertices, List<VectorXYZ> normals,
List<List<VectorXZ>> texCoordLists) {
primitiveBuffer.drawPrimitive(type, material, vertices, normals, texCoordLists);
// cache textures. they should not be loaded in the render function (see https://www.opengl.org/wiki/Common_Mistakes#glGenTextures_in_render_function)
// in some situations even errors were encountered
if (material.getNumTextureLayers() > 0) {
for (TextureData t : material.getTextureDataList()) {
textureManager.getTextureForFile(t.file, true);
}
}
}
private void drawNonAreaPrimitive(NonAreaPrimitive.Type type,
Color color, int width, List<VectorXYZ> vs) {
nonAreaPrimitives.add(new NonAreaPrimitive(
type, color, width, vs));
}
@Override
public void drawPoints(Color color, VectorXYZ... vs) {
drawNonAreaPrimitive(POINTS, color, 1, asList(vs));
}
@Override
public void drawLineStrip(Color color, int width, VectorXYZ... vs) {
drawNonAreaPrimitive(LINE_STRIP, color, width, asList(vs));
}
@Override
public void drawLineStrip(Color color, int width, List<VectorXYZ> vs) {
drawNonAreaPrimitive(LINE_STRIP, color, width, vs);
}
@Override
public void drawLineLoop(Color color, int width, List<VectorXYZ> vs) {
drawNonAreaPrimitive(LINE_LOOP, color, width, vs);
}
/**
* set global lighting parameters. Using this method affects all primitives
* (even those from previous draw calls).
*
* @param parameters parameter object; null disables lighting
*/
public void setGlobalLightingParameters(
GlobalLightingParameters parameters) {
this.globalLightingParameters = parameters;
}
/**
* set global rendering parameters. Using this method affects all primitives
* (even those from previous draw calls).
*/
public void setRenderingParameters(
JOGLRenderingParameters renderingParameters) {
this.renderingParameters = renderingParameters;
}
@Override
public void reset() {
this.primitiveBuffer = new PrimitiveBuffer();
this.nonAreaPrimitives = new ArrayList<NonAreaPrimitive>();
if (renderer != null) {
renderer.freeResources();
renderer = null;
}
}
@Override
public void freeResources() {
textureManager.releaseAll();
reset();
}
@Override
public boolean isFinished() {
return renderer != null;
}
static final int getGLConstant(Type type) {
switch (type) {
case TRIANGLE_STRIP: return GL_TRIANGLE_STRIP;
case TRIANGLE_FAN: return GL_TRIANGLE_FAN;
case TRIANGLES: return GL_TRIANGLES;
case CONVEX_POLYGON: return GL_POLYGON;
default: throw new Error("programming error: unhandled primitive type");
}
}
static final int getGLConstant(NonAreaPrimitive.Type type) {
switch (type) {
case POINTS: return GL_POINTS;
case LINES: return GL_LINES;
case LINE_STRIP: return GL_LINE_STRIP;
case LINE_LOOP: return GL_LINE_LOOP;
default: throw new Error("programming error: unhandled primitive type");
}
}
/**
* clears the rendering surface, the z buffer and the stencil buffer
*
* @param clearColor background color before rendering any primitives;
* null uses a previously defined clear color
*/
public static final void clearGL(GL gl, Color clearColor) {
if (clearColor != null) {
float[] c = {0f, 0f, 0f};
clearColor.getColorComponents(c);
gl.glClearColor(c[0], c[1], c[2], clearColor.getAlpha()/255f);
}
gl.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL.GL_STENCIL_BUFFER_BIT);
}
static final FloatBuffer getFloatBuffer(Color color) {
float colorArray[] = {0, 0, 0, color.getAlpha() / 255f};
color.getRGBColorComponents(colorArray);
return FloatBuffer.wrap(colorArray);
}
}