package cz.fidentis.analyst.scene; import com.jogamp.opengl.GL; import com.jogamp.opengl.GL2; import com.jogamp.opengl.glu.GLU; import cz.fidentis.analyst.mesh.core.MeshFacet; import java.awt.Color; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import javax.vecmath.Point3d; import javax.vecmath.Vector3d; /** * Handles {@link DrawableMesh}s - objects to be drawn, and (re-)renders them on demand. * * @author Natalia Bebjakova * @author Radek Oslejsek * @author Richard Pajersky */ public class SceneRenderer { public static final Color BRIGHT_BACKGROUND = new Color(0.9f, 0.9f, 0.9f); public static final Color DARK_BACKGROUND = new Color(0.25f, 0.25f, 0.25f); private final GLU glu = new GLU(); private GL2 gl; private boolean brightBackground = false; /** * Constructor. * * @param gl OpenGL context of drawable objects * @throws IllegalArgumentException if the {@code gl} is null */ public void initGLContext(GL2 gl) { if (gl == null) { throw new IllegalArgumentException("gl is null"); } this.gl = gl; gl.setSwapInterval(1); gl.glEnable(GL2.GL_LIGHTING); gl.glEnable(GL2.GL_LIGHT0); gl.glEnable(GL2.GL_LIGHT1); gl.glEnable(GL2.GL_DEPTH_TEST); gl.glClearColor(0,0,0,0); // background for GLCanvas gl.glClear(GL2.GL_COLOR_BUFFER_BIT); gl.glShadeModel(GL2.GL_SMOOTH); // use smooth shading gl.glDepthFunc(GL2.GL_LESS); gl.glDepthRange(0.0, 1.0); gl.glEnable(GL.GL_DEPTH_TEST); gl.glEnable(GL2.GL_NORMALIZE); gl.glDisable(GL2.GL_CULL_FACE); gl.glEnable(GL2.GL_BLEND); // enable transparency gl.glBlendFunc(GL2.GL_SRC_ALPHA, GL2.GL_ONE_MINUS_SRC_ALPHA); } /** * Sets the scene background to bright. */ public void setBrightBackground() { this.brightBackground = true; } /** * Sets the scene background to dark. */ public void setDarkBackground() { this.brightBackground = false; } /** * Sets the view-port. * * @param x X corner * @param y Y corner * @param width Width * @param height Height */ public void setViewport(int x, int y, int width, int height) { //OutputWindow out = OutputWindow.measureTime(); if (height == 0) { height = 1; // to avoid division by 0 in aspect ratio below } gl.glViewport(x, y, width, height); // size of drawing area float h = (float) height / (float) width; gl.glMatrixMode(GL2.GL_PROJECTION); gl.glLoadIdentity(); glu.gluPerspective(50, width / (float) height, 5.0f, 1500.0f); gl.glMatrixMode(GL2.GL_MODELVIEW); gl.glLoadIdentity(); gl.glTranslatef(0.0f, 0.0f, -40.0f); //out.printDuration("GL viewport set to " + width + "x" + height); } /** * Renders drawable objects. */ public void renderScene(Camera camera, Collection<Drawable> drawables) { //OutputWindow out = OutputWindow.measureTime(); clearScene(); // light backface gl.glLightfv(GL2.GL_LIGHT1, GL2.GL_POSITION, new float[] {0f, 0f, -1f, 0f}, 0); gl.glLightfv(GL2.GL_LIGHT1, GL2.GL_DIFFUSE, Color.white.getComponents(null), 0); setPosition(camera); List<Drawable> objects = new ArrayList<>(drawables); objects.sort(new Drawable.TransparencyComparator()); for (Drawable obj : objects) { if (obj.isShown()) { obj.render(gl); } } gl.glFlush(); //out.printDuration("Scene rendering"); } /** * Sets model to proper position * * @param camera Camera */ private void setPosition(Camera camera) { Vector3d currentPosition = camera.getPosition(); Vector3d center = camera.getCenter(); Vector3d upDirection = camera.getUpDirection(); glu.gluLookAt(currentPosition.x, currentPosition.y, currentPosition.z, center.x, center.y, center.z, upDirection.x, upDirection.y, upDirection.z); } /** * Sets up transparent objects to render later in order to render properly * Now works only for two meshes * * @param drawables List of meshes */ private List<DrawableFace> getOrderedFaces(Collection<Drawable> drawables) { List<DrawableFace> faces = new ArrayList<>(); for (Drawable obj: drawables) { if (obj instanceof DrawableFace) { faces.add((DrawableFace) obj); } } if (faces.get(0).getTransparency() != 1) { Collections.reverse(faces); } return faces; } /** * Clears the scene and prepares it for the re-drawing. */ protected void clearScene() { // join with the renderScene() ??? if (brightBackground) { gl.glClearColor( BRIGHT_BACKGROUND.getRed() / 255f, BRIGHT_BACKGROUND.getGreen() / 255f, BRIGHT_BACKGROUND.getBlue() / 255f, 0.0f); } else { gl.glClearColor( DARK_BACKGROUND.getRed() / 255f, DARK_BACKGROUND.getGreen() / 255f, DARK_BACKGROUND.getBlue() / 255f, 0.0f); } gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); gl.glLoadIdentity(); } /** * Loops through the facet and render all the vertices as they are stored in corner table * * @param facet facet of model */ protected void renderFacet(MeshFacet facet) { gl.glBegin(GL2.GL_TRIANGLES); //vertices are rendered as triangles // get the normal and tex coords indicies for face i for (int v = 0; v < facet.getCornerTable().getSize(); v++) { // render the normals Vector3d norm = facet.getVertices().get(facet.getCornerTable().getRow(v).getVertexIndex()).getNormal(); if(norm != null) { gl.glNormal3d(norm.x, norm.y, norm.z); } // render the vertices Point3d vert = facet.getVertices().get(facet.getCornerTable().getRow(v).getVertexIndex()).getPosition(); gl.glVertex3d(vert.x, vert.y, vert.z); } gl.glEnd(); } }