/* * JAME 6.2.1 * http://jame.sourceforge.net * * Copyright 2001, 2016 Andrea Medeghini * * This file is based on code from idx3dIII * Copyright 1999, 2000 Peter Walser * http://www.idx3d.ch/idx3d/idx3d.html * * This file is part of JAME. * * JAME is an application for creating fractals and other graphics artifacts. * * JAME is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * JAME is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with JAME. If not, see <http://www.gnu.org/licenses/>. * */ package net.sf.jame.core.media.g3d; import java.util.Enumeration; public final class RenderPipeline { private static final Matrix mu = Matrix.unit; public boolean debug = false; public boolean shading = true; public boolean flat_shading = true; public boolean texture_mapping = true; public boolean auto_animate = true; private Triangle[] triangles; private final java.util.Vector<Triangle> opaqueQueue = new java.util.Vector<Triangle>(); private final java.util.Vector<Triangle> transparentQueue = new java.util.Vector<Triangle>(); private Camera camera; private Scene scene; private Screen screen; private Texture texture; private Lightmap lightmap; private Rasterizer rasterizer; int[] pixels; int[] zbuffer; int[] idbuffer; int[][] diffuse; int[][] specular; int center_x; int center_y; int w; int h; public RenderPipeline() { setRasterizer(new DefaultRasterizer()); } public RenderPipeline(final Rasterizer rasterizer) { setRasterizer(rasterizer); } public void setRasterizer(final Rasterizer rasterizer) { if (rasterizer == null) { throw new IllegalArgumentException("illegal argument ! [rasterizer == null]"); } this.rasterizer = rasterizer; rasterizer.pipeline = this; } public void animate() { final boolean a = auto_animate; auto_animate = true; this.animate(scene); auto_animate = a; } private void animate(final Assembly assembly) { if (assembly != null) { if ((assembly.handler != null) && auto_animate) { assembly.handler.animate(); } Solid solid = null; final Enumeration<Solid> solids = assembly.getSolids(); while (solids.hasMoreElements()) { solid = solids.nextElement(); if (solid instanceof Assembly) { this.animate((Assembly) solid); } else if (solid instanceof Part) { this.animate((Part) solid); } } } } private void animate(final Part part) { if ((part.handler != null) && auto_animate) { part.handler.animate(); } } public void init(final Camera camera, final Scene scene) { if (camera == null) { throw new IllegalArgumentException("illegal argument ! [camera == null]"); } if (scene == null) { throw new IllegalArgumentException("illegal argument ! [scene == null]"); } this.scene = scene; this.camera = camera; } public void render() { screen = camera.getScreen(); texture = scene.getEnvironment().texture; if (texture != null) { screen.clear(texture); } else { screen.clear(scene.getEnvironment().background); } pixels = screen.getBuffer(); zbuffer = screen.getZBuffer(); idbuffer = screen.getIDBuffer(); w = screen.getWidth(); h = screen.getHeight(); center_x = w >> 1; center_y = h >> 1; scene.rebuildLightmap(); lightmap = scene.getLightmap(); specular = lightmap.specular; diffuse = lightmap.diffuse; scene.rebuild(); scene.project(RenderPipeline.mu, camera.mp, camera.vx, camera.vy, camera.vz); emptyQueues(); this.enqueueTriangles(scene); triangles = getOpaqueQueue(); if (triangles != null) { for (int i = triangles.length - 1; i >= 0; i--) { rasterizer.render_triangle(triangles[i], triangles[i].parent.material); } } triangles = getTransparentQueue(); if (triangles != null) { for (final Triangle element : triangles) { rasterizer.render_triangle(element, element.parent.material); } } } private void enqueueTriangles(final Assembly assembly) { if ((assembly.handler != null) && auto_animate) { assembly.handler.animate(); } if (!assembly.hidden) { Solid solid = null; final Enumeration<Solid> solids = assembly.getSolids(); while (solids.hasMoreElements()) { solid = solids.nextElement(); if (solid instanceof Assembly) { this.enqueueTriangles((Assembly) solid); } else if (solid instanceof Part) { this.enqueueTriangles((Part) solid); } } } else { this.animate(assembly); } } private void enqueueTriangles(final Part part) { if ((part.handler != null) && auto_animate) { part.handler.animate(); } if (!part.hidden) { for (final Triangle element : part.triangles) { enqueueTriangle(element, part.material); } } } private void enqueueTriangle(final Triangle triangle, final Material material) { if ((material == null) || (triangle.visible == false)) { return; } if ((material.transparency == 255) && (material.reflectivity == 0)) { return; } if (material.transparency > 0) { transparentQueue.addElement(triangle); } else { opaqueQueue.addElement(triangle); } } private void emptyQueues() { opaqueQueue.removeAllElements(); transparentQueue.removeAllElements(); } private Triangle[] getOpaqueQueue() { if (opaqueQueue.size() == 0) { return (null); } final Triangle[] triangles = new Triangle[opaqueQueue.size()]; final Enumeration<Triangle> e = opaqueQueue.elements(); int i = 0; while (e.hasMoreElements()) { triangles[i++] = e.nextElement(); } return (sortTriangles(triangles, 0, triangles.length - 1)); } private Triangle[] getTransparentQueue() { if (transparentQueue.size() == 0) { return (null); } final Triangle[] triangles = new Triangle[transparentQueue.size()]; final Enumeration<Triangle> e = transparentQueue.elements(); int i = 0; while (e.hasMoreElements()) { triangles[i++] = e.nextElement(); } return (sortTriangles(triangles, 0, triangles.length - 1)); } private Triangle[] sortTriangles(final Triangle[] triangles, final int l, final int r) { final float m = (triangles[l].distance + triangles[r].distance) / 2f; Triangle t = null; int i = l; int j = r; do { while (triangles[i].distance > m) { i++; } while (triangles[j].distance < m) { j--; } if (i <= j) { t = triangles[i]; triangles[i] = triangles[j]; triangles[j] = t; i++; j--; } } while (j >= i); if (l < j) { sortTriangles(triangles, l, j); } if (r > i) { sortTriangles(triangles, i, r); } return (triangles); } }