package com.jme3.renderer;
import com.jme3.material.Material;
+import com.jme3.material.MaterialDef;
import com.jme3.material.RenderState;
+import com.jme3.material.Technique;
import com.jme3.math.Matrix3f;
import com.jme3.math.Matrix4f;
import com.jme3.math.Quaternion;
import com.jme3.renderer.queue.GeometryList;
import com.jme3.renderer.queue.RenderQueue;
import com.jme3.renderer.queue.RenderQueue.Bucket;
+import com.jme3.renderer.queue.RenderQueue.ShadowMode;
import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.VertexBuffer;
import com.jme3.shader.Uniform;
+import com.jme3.shader.UniformBinding;
import com.jme3.shader.VarType;
import com.jme3.system.NullRenderer;
import com.jme3.system.Timer;
+import com.jme3.util.BufferUtils;
import com.jme3.util.IntMap.Entry;
import com.jme3.util.TempVars;
+import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
private int viewX, viewY, viewWidth, viewHeight;
private float near, far;
private Matrix4f orthoMatrix = new Matrix4f();
+// private FloatBuffer orthoMatrixBuf = BufferUtils.createFloatBuffer(16);
private Matrix4f viewMatrix = new Matrix4f();
+ private FloatBuffer viewMatrixBuf = BufferUtils.createFloatBuffer(16);
private Matrix4f projMatrix = new Matrix4f();
+ private FloatBuffer projMatrixBuf = BufferUtils.createFloatBuffer(16);
private Matrix4f viewProjMatrix = new Matrix4f();
+ private FloatBuffer viewProjMatrixBuf = BufferUtils.createFloatBuffer(16);
private Matrix4f worldMatrix = new Matrix4f();
+ private FloatBuffer worldMatrixBuf = BufferUtils.createFloatBuffer(16);
+ private FloatBuffer worldViewMatrixBuf = BufferUtils.createFloatBuffer(16);
+ private boolean worldViewMatrixBufDirty = true;
+ private FloatBuffer worldViewProjectionMatrixBuf = BufferUtils.createFloatBuffer(16);
+ private boolean worldViewProjectionMatrixBufDirty = true;
+ private FloatBuffer normalMatrixBuf = BufferUtils.createFloatBuffer(9);
+ private boolean normalMatrixBufDirty = true;
private Vector3f camUp = new Vector3f(),
camLeft = new Vector3f(),
camDir = new Vector3f(),
camLoc = new Vector3f();
//temp technique
private String tmpTech;
+ private boolean handleTranlucentBucket = true;
/**
* Create a high-level rendering interface over the
//this.shader = renderer.getCaps().contains(Caps.GLSL100);
}
+ /**
+ * Returns the pre ViewPort with the given name.
+ *
+ * @param viewName The name of the pre ViewPort to look up
+ * @return The ViewPort, or null if not found.
+ *
+ * @see #createPreView(java.lang.String, com.jme3.renderer.Camera)
+ */
public ViewPort getPreView(String viewName) {
for (int i = 0; i < preViewPorts.size(); i++) {
if (preViewPorts.get(i).getName().equals(viewName)) {
return null;
}
+ /**
+ * Removes the specified pre ViewPort.
+ *
+ * @param view The pre ViewPort to remove
+ * @return True if the ViewPort was removed successfully.
+ *
+ * @see #createPreView(java.lang.String, com.jme3.renderer.Camera)
+ */
public boolean removePreView(ViewPort view) {
return preViewPorts.remove(view);
}
+ /**
+ * Returns the main ViewPort with the given name.
+ *
+ * @param viewName The name of the main ViewPort to look up
+ * @return The ViewPort, or null if not found.
+ *
+ * @see #createMainView(java.lang.String, com.jme3.renderer.Camera)
+ */
public ViewPort getMainView(String viewName) {
for (int i = 0; i < viewPorts.size(); i++) {
if (viewPorts.get(i).getName().equals(viewName)) {
return null;
}
+ /**
+ * Removes the main ViewPort with the specified name.
+ *
+ * @param view The main ViewPort name to remove
+ * @return True if the ViewPort was removed successfully.
+ *
+ * @see #createMainView(java.lang.String, com.jme3.renderer.Camera)
+ */
public boolean removeMainView(String viewName) {
for (int i = 0; i < viewPorts.size(); i++) {
if (viewPorts.get(i).getName().equals(viewName)) {
return false;
}
+ /**
+ * Removes the specified main ViewPort.
+ *
+ * @param view The main ViewPort to remove
+ * @return True if the ViewPort was removed successfully.
+ *
+ * @see #createMainView(java.lang.String, com.jme3.renderer.Camera)
+ */
public boolean removeMainView(ViewPort view) {
return viewPorts.remove(view);
}
+ /**
+ * Returns the post ViewPort with the given name.
+ *
+ * @param viewName The name of the post ViewPort to look up
+ * @return The ViewPort, or null if not found.
+ *
+ * @see #createPostView(java.lang.String, com.jme3.renderer.Camera)
+ */
public ViewPort getPostView(String viewName) {
for (int i = 0; i < postViewPorts.size(); i++) {
if (postViewPorts.get(i).getName().equals(viewName)) {
return null;
}
+ /**
+ * Removes the post ViewPort with the specified name.
+ *
+ * @param view The post ViewPort name to remove
+ * @return True if the ViewPort was removed successfully.
+ *
+ * @see #createPostView(java.lang.String, com.jme3.renderer.Camera)
+ */
public boolean removePostView(String viewName) {
for (int i = 0; i < postViewPorts.size(); i++) {
if (postViewPorts.get(i).getName().equals(viewName)) {
return false;
}
+ /**
+ * Removes the specified post ViewPort.
+ *
+ * @param view The post ViewPort to remove
+ * @return True if the ViewPort was removed successfully.
+ *
+ * @see #createPostView(java.lang.String, com.jme3.renderer.Camera)
+ */
public boolean removePostView(ViewPort view) {
return postViewPorts.remove(view);
}
+ /**
+ * Returns a read-only list of all pre ViewPorts
+ * @return a read-only list of all pre ViewPorts
+ * @see #createPreView(java.lang.String, com.jme3.renderer.Camera)
+ */
public List<ViewPort> getPreViews() {
return Collections.unmodifiableList(preViewPorts);
}
+ /**
+ * Returns a read-only list of all main ViewPorts
+ * @return a read-only list of all main ViewPorts
+ * @see #createMainView(java.lang.String, com.jme3.renderer.Camera)
+ */
public List<ViewPort> getMainViews() {
return Collections.unmodifiableList(viewPorts);
}
+ /**
+ * Returns a read-only list of all post ViewPorts
+ * @return a read-only list of all post ViewPorts
+ * @see #createPostView(java.lang.String, com.jme3.renderer.Camera)
+ */
public List<ViewPort> getPostViews() {
return Collections.unmodifiableList(postViewPorts);
}
/**
- * Creates a new viewport, to display the given camera's content.
- * The view will be processed before the primary viewport.
- * @param viewName
- * @param cam
- * @return
+ * Creates a new pre ViewPort, to display the given camera's content.
+ * <p>
+ * The view will be processed before the main and post viewports.
*/
public ViewPort createPreView(String viewName, Camera cam) {
ViewPort vp = new ViewPort(viewName, cam);
return vp;
}
+ /**
+ * Creates a new main ViewPort, to display the given camera's content.
+ * <p>
+ * The view will be processed before the post viewports but after
+ * the pre viewports.
+ */
public ViewPort createMainView(String viewName, Camera cam) {
ViewPort vp = new ViewPort(viewName, cam);
viewPorts.add(vp);
return vp;
}
+ /**
+ * Creates a new post ViewPort, to display the given camera's content.
+ * <p>
+ * The view will be processed after the pre and main viewports.
+ */
public ViewPort createPostView(String viewName, Camera cam) {
ViewPort vp = new ViewPort(viewName, cam);
postViewPorts.add(vp);
}
/**
- * @param w
- * @param h
+ * Internal use only.
+ * Updates the resolution of all on-screen cameras to match
+ * the given width and height.
*/
public void notifyReshape(int w, int h) {
for (ViewPort vp : preViewPorts) {
}
}
+ /**
+ * Internal use only.
+ * Updates the given list of uniforms with {@link UniformBinding uniform bindings}
+ * based on the current world state.
+ */
public void updateUniformBindings(List<Uniform> params) {
// assums worldMatrix is properly set.
TempVars vars = TempVars.get();
- assert vars.lock();
Matrix4f tempMat4 = vars.tempMat4;
Matrix3f tempMat3 = vars.tempMat3;
Uniform u = params.get(i);
switch (u.getBinding()) {
case WorldMatrix:
- u.setValue(VarType.Matrix4, worldMatrix);
+ u.setValue(VarType.Matrix4, worldMatrixBuf);
break;
case ViewMatrix:
u.setValue(VarType.Matrix4, viewMatrix);
break;
case ProjectionMatrix:
- u.setValue(VarType.Matrix4, projMatrix);
+ u.setValue(VarType.Matrix4, projMatrixBuf);
break;
case ViewProjectionMatrix:
- u.setValue(VarType.Matrix4, viewProjMatrix);
+ u.setValue(VarType.Matrix4, viewProjMatrixBuf);
break;
case WorldViewMatrix:
- tempMat4.set(viewMatrix);
- tempMat4.multLocal(worldMatrix);
- u.setValue(VarType.Matrix4, tempMat4);
+// tempMat4.set(viewMatrix);
+// tempMat4.multLocal(worldMatrix);
+// u.setValue(VarType.Matrix4, tempMat4);
+ u.setValue(VarType.Matrix4, getWorldViewMatrixBuf());
break;
case NormalMatrix:
tempMat4.set(viewMatrix);
u.setValue(VarType.Matrix3, tempMat3);
break;
case WorldViewProjectionMatrix:
- tempMat4.set(viewProjMatrix);
- tempMat4.multLocal(worldMatrix);
- u.setValue(VarType.Matrix4, tempMat4);
+// tempMat4.set(viewProjMatrix);
+// tempMat4.multLocal(worldMatrix);
+// u.setValue(VarType.Matrix4, tempMat4);
+ u.setValue(VarType.Matrix4, getWorldViewProjectionMatrixBuf());
break;
case WorldMatrixInverse:
tempMat4.multLocal(worldMatrix);
case FrameRate:
u.setValue(VarType.Float, timer.getFrameRate());
break;
- case AmbientLightColor:
- break;
}
}
- assert vars.unlock();
+ vars.release();
}
/**
* with the provided material instead.
* Use null to clear the material and return renderer to normal
* functionality.
- * @param mat
+ * @param mat The forced material to set, or null to return to normal
*/
public void setForcedMaterial(Material mat) {
forcedMaterial = mat;
}
+ /**
+ * Returns the forced render state previously set with
+ * {@link #setForcedRenderState(com.jme3.material.RenderState) }.
+ * @return the forced render state
+ */
public RenderState getForcedRenderState() {
return forcedRenderState;
}
+ /**
+ * Set the render state to use for all future objects.
+ * This overrides the render state set on the material and instead
+ * forces this render state to be applied for all future materials
+ * rendered. Set to null to return to normal functionality.
+ *
+ * @param forcedRenderState The forced render state to set, or null
+ * to return to normal
+ */
public void setForcedRenderState(RenderState forcedRenderState) {
this.forcedRenderState = forcedRenderState;
}
+ /**
+ * Set the timer that should be used to query the time based
+ * {@link UniformBinding}s for material world parameters.
+ *
+ * @param timer The timer to query time world parameters
+ */
+ public void setTimer(Timer timer) {
+ this.timer = timer;
+ }
+
+ /**
+ * Returns the forced technique name set.
+ *
+ * @return the forced technique name set.
+ *
+ * @see #setForcedTechnique(java.lang.String)
+ */
+ public String getForcedTechnique() {
+ return forcedTechnique;
+ }
+
+ /**
+ * Sets the forced technique to use when rendering geometries.
+ * <p>
+ * If the specified technique name is available on the geometry's
+ * material, then it is used, otherwise, the
+ * {@link #setForcedMaterial(com.jme3.material.Material) forced material} is used.
+ * If a forced material is not set and the forced technique name cannot
+ * be found on the material, the geometry will <em>not</em> be rendered.
+ *
+ * @param forcedTechnique The forced technique name to use, set to null
+ * to return to normal functionality.
+ *
+ * @see #renderGeometry(com.jme3.scene.Geometry)
+ */
+ public void setForcedTechnique(String forcedTechnique) {
+ this.forcedTechnique = forcedTechnique;
+ }
+
+ /**
+ * Enable or disable alpha-to-coverage.
+ * <p>
+ * When alpha to coverage is enabled and the renderer implementation
+ * supports it, then alpha blending will be replaced with alpha dissolve
+ * if multi-sampling is also set on the renderer.
+ * This feature allows avoiding of alpha blending artifacts due to
+ * lack of triangle-level back-to-front sorting.
+ *
+ * @param value True to enable alpha-to-coverage, false otherwise.
+ */
+ public void setAlphaToCoverage(boolean value) {
+ renderer.setAlphaToCoverage(value);
+ }
+
+ /**
+ * True if the translucent bucket should automatically be rendered
+ * by the RenderManager.
+ *
+ * @return Whether or not the translucent bucket is rendered.
+ *
+ * @see #setHandleTranslucentBucket(boolean)
+ */
+ public boolean isHandleTranslucentBucket() {
+ return handleTranlucentBucket;
+ }
+
+ /**
+ * Enable or disable rendering of the
+ * {@link Bucket#Translucent translucent bucket}
+ * by the RenderManager. The default is enabled.
+ *
+ * @param handleTranslucentBucket Whether or not the translucent bucket should
+ * be rendered.
+ */
+ public void setHandleTranslucentBucket(boolean handleTranslucentBucket) {
+ this.handleTranlucentBucket = handleTranslucentBucket;
+ }
+
+ /**
+ * Internal use only. Sets the world matrix to use for future
+ * rendering. This has no effect unless objects are rendered manually
+ * using {@link Material#render(com.jme3.scene.Geometry, com.jme3.renderer.RenderManager) }.
+ * Using {@link #renderGeometry(com.jme3.scene.Geometry) } will
+ * override this value.
+ *
+ * @param mat The world matrix to set
+ */
public void setWorldMatrix(Matrix4f mat) {
if (shader) {
worldMatrix.set(mat);
+ worldMatrix.fillFloatBuffer(worldMatrixBuf, true);
+ worldMatrixBuf.position(0);
+ worldViewProjectionMatrixBufDirty = true;
+ normalMatrixBufDirty = true;
} else {
renderer.setWorldMatrix(mat);
}
}
+ /**
+ * Renders the given geometry.
+ * <p>
+ * First the proper world matrix is set, if
+ * the geometry's {@link Geometry#setIgnoreTransform(boolean) ignore transform}
+ * feature is enabled, the identity world matrix is used, otherwise, the
+ * geometry's {@link Geometry#getWorldMatrix() world transform matrix} is used.
+ * <p>
+ * Once the world matrix is applied, the proper material is chosen for rendering.
+ * If a {@link #setForcedMaterial(com.jme3.material.Material) forced material} is
+ * set on this RenderManager, then it is used for rendering the geometry,
+ * otherwise, the {@link Geometry#getMaterial() geometry's material} is used.
+ * <p>
+ * If a {@link #setForcedTechnique(java.lang.String) forced technique} is
+ * set on this RenderManager, then it is selected automatically
+ * on the geometry's material and is used for rendering. Otherwise, one
+ * of the {@link MaterialDef#getDefaultTechniques() default techniques} is
+ * used.
+ * <p>
+ * If a {@link #setForcedRenderState(com.jme3.material.RenderState) forced
+ * render state} is set on this RenderManager, then it is used
+ * for rendering the material, and the material's own render state is ignored.
+ * Otherwise, the material's render state is used as intended.
+ *
+ * @param g The geometry to render
+ *
+ * @see Technique
+ * @see RenderState
+ * @see Material#selectTechnique(java.lang.String, com.jme3.renderer.RenderManager)
+ * @see Material#render(com.jme3.scene.Geometry, com.jme3.renderer.RenderManager)
+ */
public void renderGeometry(Geometry g) {
if (g.isIgnoreTransform()) {
setWorldMatrix(Matrix4f.IDENTITY);
} else if (forcedMaterial != null) {
// use forced material
forcedMaterial.render(g, this);
- } else {
+ } else {
g.getMaterial().render(g, this);
}
- //re applying default render state at the end of the render to avoid depth write issues, MUST BE A BETTER WAY
- renderer.applyRenderState(RenderState.DEFAULT);
}
+ /**
+ * Renders the given GeometryList.
+ * <p>
+ * For every geometry in the list, the
+ * {@link #renderGeometry(com.jme3.scene.Geometry) } method is called.
+ *
+ * @param gl The geometry list to render.
+ *
+ * @see GeometryList
+ * @see #renderGeometry(com.jme3.scene.Geometry)
+ */
public void renderGeometryList(GeometryList gl) {
for (int i = 0; i < gl.size(); i++) {
renderGeometry(gl.get(i));
}
-
}
/**
* If a spatial is not inside the eye frustum, it
- * is still rendered in the shadow frustum through this
- * recursive method.
- * @param s
- * @param r
+ * is still rendered in the shadow frustum (shadow casting queue)
+ * through this recursive method.
*/
private void renderShadow(Spatial s, RenderQueue rq) {
if (s instanceof Node) {
}
}
+ /**
+ * Preloads a scene for rendering.
+ * <p>
+ * After invocation of this method, the underlying
+ * renderer would have uploaded any textures, shaders and meshes
+ * used by the given scene to the video driver.
+ * Using this method is useful when wishing to avoid the initial pause
+ * when rendering a scene for the first time. Note that it is not
+ * guaranteed that the underlying renderer will actually choose to upload
+ * the data to the GPU so some pause is still to be expected.
+ *
+ * @param scene The scene to preload
+ */
public void preloadScene(Spatial scene) {
if (scene instanceof Node) {
// recurse for all children
}
/**
- * Render scene graph
- * @param s
- * @param r
- * @param cam
+ * Flattens the given scene graph into the ViewPort's RenderQueue,
+ * checking for culling as the call goes down the graph recursively.
+ * <p>
+ * First, the scene is checked for culling based on the <code>Spatial</code>s
+ * {@link Spatial#setCullHint(com.jme3.scene.Spatial.CullHint) cull hint},
+ * if the camera frustum contains the scene, then this method is recursively
+ * called on its children.
+ * <p>
+ * When the scene's leaves or {@link Geometry geometries} are reached,
+ * they are each enqueued into the
+ * {@link ViewPort#getQueue() ViewPort's render queue}.
+ * <p>
+ * In addition to enqueuing the visible geometries, this method
+ * also scenes which cast or receive shadows, by putting them into the
+ * RenderQueue's
+ * {@link RenderQueue#addToShadowQueue(com.jme3.scene.Geometry, com.jme3.renderer.queue.RenderQueue.ShadowMode)
+ * shadow queue}. Each Spatial which has its
+ * {@link Spatial#setShadowMode(com.jme3.renderer.queue.RenderQueue.ShadowMode) shadow mode}
+ * set to not off, will be put into the appropriate shadow queue, note that
+ * this process does not check for frustum culling on any
+ * {@link ShadowMode#Cast shadow casters}, as they don't have to be
+ * in the eye camera frustum to cast shadows on objects that are inside it.
+ *
+ * @param scene The scene to flatten into the queue
+ * @param vp The ViewPort provides the {@link ViewPort#getCamera() camera}
+ * used for culling and the {@link ViewPort#getQueue() queue} used to
+ * contain the flattened scene graph.
*/
public void renderScene(Spatial scene, ViewPort vp) {
+ if (scene.getParent() == null) {
+ vp.getCamera().setPlaneState(0);
+ }
// check culling first.
if (!scene.checkCulling(vp.getCamera())) {
// move on to shadow-only render
- if (scene.getShadowMode() != RenderQueue.ShadowMode.Off || scene instanceof Node) {
+ if ((scene.getShadowMode() != RenderQueue.ShadowMode.Off || scene instanceof Node) && scene.getCullHint()!=Spatial.CullHint.Always) {
renderShadow(scene, vp.getQueue());
}
return;
// recurse for all children
Node n = (Node) scene;
List<Spatial> children = n.getChildren();
+ //saving cam state for culling
+ int camState = vp.getCamera().getPlaneState();
for (int i = 0; i < children.size(); i++) {
+ //restoring cam state before proceeding children recusively
+ vp.getCamera().setPlaneState(camState);
renderScene(children.get(i), vp);
+
}
} else if (scene instanceof Geometry) {
}
}
+ /**
+ * Returns the camera currently used for rendering.
+ * <p>
+ * The camera can be set with {@link #setCamera(com.jme3.renderer.Camera, boolean) }.
+ *
+ * @return the camera currently used for rendering.
+ */
public Camera getCurrentCamera() {
return prevCam;
}
+ /**
+ * The renderer implementation used for rendering operations.
+ *
+ * @return The renderer implementation
+ *
+ * @see #RenderManager(com.jme3.renderer.Renderer)
+ * @see Renderer
+ */
public Renderer getRenderer() {
return renderer;
}
/**
- * Render the given viewport queues, flushing the geometryList
- * @param vp the viewport
+ * Flushes the ViewPort's {@link ViewPort#getQueue() render queue}
+ * by rendering each of its visible buckets.
+ * By default the queues will automatically be cleared after rendering,
+ * so there's no need to clear them manually.
+ *
+ * @param vp The ViewPort of which the queue will be flushed
+ *
+ * @see RenderQueue#renderQueue(com.jme3.renderer.queue.RenderQueue.Bucket, com.jme3.renderer.RenderManager, com.jme3.renderer.Camera)
+ * @see #renderGeometryList(com.jme3.renderer.queue.GeometryList)
*/
public void flushQueue(ViewPort vp) {
renderViewPortQueues(vp, true);
}
+ /**
+ * Clears the queue of the given ViewPort.
+ * Simply calls {@link RenderQueue#clear() } on the ViewPort's
+ * {@link ViewPort#getQueue() render queue}.
+ *
+ * @param vp The ViewPort of which the queue will be cleared.
+ *
+ * @see RenderQueue#clear()
+ * @see ViewPort#getQueue()
+ */
public void clearQueue(ViewPort vp) {
vp.getQueue().clear();
}
- //Nehon 08/18/2010 changed flushQueue to renderViewPortQueues with a flush boolean param
/**
- * Render the given viewport queues
- * @param vp the viewport
- * @param flush true to flush geometryList
+ * Render the given viewport queues.
+ * <p>
+ * Changes the {@link Renderer#setDepthRange(float, float) depth range}
+ * appropriately as expected by each queue and then calls
+ * {@link RenderQueue#renderQueue(com.jme3.renderer.queue.RenderQueue.Bucket, com.jme3.renderer.RenderManager, com.jme3.renderer.Camera, boolean) }
+ * on the queue. Makes sure to restore the depth range to [0, 1]
+ * at the end of the call.
+ * Note that the {@link Bucket#Translucent translucent bucket} is NOT
+ * rendered by this method. Instead the user should call
+ * {@link #renderTranslucentQueue(com.jme3.renderer.ViewPort) }
+ * after this call.
+ *
+ * @param vp the viewport of which queue should be rendered
+ * @param flush If true, the queues will be cleared after
+ * rendering.
+ *
+ * @see RenderQueue
+ * @see #renderTranslucentQueue(com.jme3.renderer.ViewPort)
*/
public void renderViewPortQueues(ViewPort vp, boolean flush) {
RenderQueue rq = vp.getQueue();
}
if (!rq.isQueueEmpty(Bucket.Gui)) {
- renderer.setDepthRange(0, 0);
+// renderer.setDepthRange(0, 0);
setCamera(cam, true);
rq.renderQueue(Bucket.Gui, this, cam, flush);
setCamera(cam, false);
}
}
+ /**
+ * Renders the {@link Bucket#Translucent translucent queue} on the viewPort.
+ * <p>
+ * This call does nothing unless {@link #setHandleTranslucentBucket(boolean) }
+ * is set to true. This method clears the translucent queue after rendering
+ * it.
+ *
+ * @param vp The viewport of which the translucent queue should be rendered.
+ *
+ * @see #renderViewPortQueues(com.jme3.renderer.ViewPort, boolean)
+ * @see #setHandleTranslucentBucket(boolean)
+ */
+ public void renderTranslucentQueue(ViewPort vp) {
+ RenderQueue rq = vp.getQueue();
+ if (!rq.isQueueEmpty(Bucket.Translucent) && handleTranlucentBucket) {
+ rq.renderQueue(Bucket.Translucent, this, vp.getCamera(), true);
+ }
+ }
+
private void setViewPort(Camera cam) {
// this will make sure to update viewport only if needed
if (cam != prevCam || cam.isViewportChanged()) {
viewWidth = (int) ((cam.getViewPortRight() - cam.getViewPortLeft()) * cam.getWidth());
viewHeight = (int) ((cam.getViewPortTop() - cam.getViewPortBottom()) * cam.getHeight());
renderer.setViewPort(viewX, viewY, viewWidth, viewHeight);
- renderer.setClipRect(viewX, viewY, viewWidth, viewHeight);
+// renderer.setClipRect(viewX, viewY, viewWidth, viewHeight);
cam.clearViewportChanged();
prevCam = cam;
- float translateX = viewWidth == viewX ? 0 : -(viewWidth + viewX) / (viewWidth - viewX);
- float translateY = viewHeight == viewY ? 0 : -(viewHeight + viewY) / (viewHeight - viewY);
- float scaleX = viewWidth == viewX ? 1f : 2f / (viewWidth - viewX);
- float scaleY = viewHeight == viewY ? 1f : 2f / (viewHeight - viewY);
+// float translateX = viewWidth == viewX ? 0 : -(viewWidth + viewX) / (viewWidth - viewX);
+// float translateY = viewHeight == viewY ? 0 : -(viewHeight + viewY) / (viewHeight - viewY);
+// float scaleX = viewWidth == viewX ? 1f : 2f / (viewWidth - viewX);
+// float scaleY = viewHeight == viewY ? 1f : 2f / (viewHeight - viewY);
+//
+// orthoMatrix.loadIdentity();
+// orthoMatrix.setTranslation(translateX, translateY, 0);
+// orthoMatrix.setScale(scaleX, scaleY, 0);
+
orthoMatrix.loadIdentity();
- orthoMatrix.setTranslation(translateX, translateY, 0);
- orthoMatrix.setScale(scaleX, scaleY, /*-1f*/ 0f);
-// System.out.println(orthoMatrix);
+ orthoMatrix.setTranslation(-1f, -1f, 0f);
+ orthoMatrix.setScale(2f / cam.getWidth(), 2f / cam.getHeight(), 0f);
+// orthoMatrix.fillFloatBuffer(orthoMatrixBuf, true);
}
}
projMatrix.set(cam.getProjectionMatrix());
viewProjMatrix.set(cam.getViewProjectionMatrix());
}
-
-
+// viewMatrix.fillFloatBuffer(viewMatrixBuf, true);
+// viewMatrixBuf.position(0);
+ projMatrix.fillFloatBuffer(projMatrixBuf, true);
+ projMatrixBuf.position(0);
+ viewProjMatrix.fillFloatBuffer(viewProjMatrixBuf, true);
+ viewProjMatrixBuf.position(0);
+ worldViewMatrixBufDirty = true;
+ worldViewProjectionMatrixBufDirty = true;
+ normalMatrixBufDirty = true;
camLoc.set(cam.getLocation());
cam.getLeft(camLeft);
cam.getUp(camUp);
}
}
-
+ private FloatBuffer getWorldViewMatrixBuf() {
+ if (worldViewMatrixBufDirty) {
+ TempVars tmp = TempVars.get();
+ tmp.tempMat4.set(viewMatrix);
+ tmp.tempMat4.multLocal(worldMatrix);
+ tmp.tempMat4.fillFloatBuffer(worldViewMatrixBuf, true);
+ worldViewMatrixBuf.position(0);
+ tmp.release();
+ worldViewMatrixBufDirty = false;
+ }
+ return worldViewMatrixBuf;
+ }
+ private FloatBuffer getWorldViewProjectionMatrixBuf() {
+ if (worldViewProjectionMatrixBufDirty) {
+ TempVars tmp = TempVars.get();
+ tmp.tempMat4.set(viewProjMatrix);
+ tmp.tempMat4.multLocal(worldMatrix);
+ tmp.tempMat4.fillFloatBuffer(worldViewProjectionMatrixBuf, true);
+ worldViewProjectionMatrixBuf.position(0);
+ tmp.release();
+ worldViewProjectionMatrixBufDirty = false;
+ }
+ return worldViewProjectionMatrixBuf;
+ }
+ private FloatBuffer getNormalMatrixBuf() {
+ if (normalMatrixBufDirty) {
+ TempVars tmp = TempVars.get();
+ tmp.tempMat4.set(viewMatrix);
+ tmp.tempMat4.multLocal(worldMatrix);
+ tmp.tempMat4.toRotationMatrix(tmp.tempMat3);
+ tmp.tempMat3.invertLocal();
+ tmp.tempMat3.transposeLocal();
+ tmp.tempMat3.fillFloatBuffer(normalMatrixBuf, true);
+ normalMatrixBuf.position(0);
+ tmp.release();
+ normalMatrixBufDirty = false;
+ }
+ return worldViewProjectionMatrixBuf;
+ }
+ /**
+ * Set the camera to use for rendering.
+ * <p>
+ * First, the camera's
+ * {@link Camera#setViewPort(float, float, float, float) view port parameters}
+ * are applied. Then, the camera's {@link Camera#getViewMatrix() view} and
+ * {@link Camera#getProjectionMatrix() projection} matrices are set
+ * on the renderer. If <code>ortho</code> is <code>true</code>, then
+ * instead of using the camera's view and projection matrices, an ortho
+ * matrix is computed and used instead of the view projection matrix.
+ * The ortho matrix converts from the range (0 ~ Width, 0 ~ Height, -1 ~ +1)
+ * to the clip range (-1 ~ +1, -1 ~ +1, -1 ~ +1).
+ *
+ * @param cam The camera to set
+ * @param ortho True if to use orthographic projection (for GUI rendering),
+ * false if to use the camera's view and projection matrices.
+ */
public void setCamera(Camera cam, boolean ortho) {
setViewPort(cam);
setViewProjection(cam, ortho);
}
/**
- * Draws the viewport but doesn't invoke processors.
- * @param vp
+ * Draws the viewport but without notifying {@link SceneProcessor scene
+ * processors} of any rendering events.
+ *
+ * @param vp The ViewPort to render
+ *
+ * @see #renderViewPort(com.jme3.renderer.ViewPort, float)
*/
public void renderViewPortRaw(ViewPort vp) {
setCamera(vp.getCamera(), false);
flushQueue(vp);
}
+ /**
+ * Renders the {@link ViewPort}.
+ * <p>
+ * If the ViewPort is {@link ViewPort#isEnabled() disabled}, this method
+ * returns immediately. Otherwise, the ViewPort is rendered by
+ * the following process:<br>
+ * <ul>
+ * <li>All {@link SceneProcessor scene processors} that are attached
+ * to the ViewPort are {@link SceneProcessor#initialize(com.jme3.renderer.RenderManager, com.jme3.renderer.ViewPort) initialized}.
+ * </li>
+ * <li>The SceneProcessors' {@link SceneProcessor#preFrame(float) } method
+ * is called.</li>
+ * <li>The ViewPort's {@link ViewPort#getOutputFrameBuffer() output framebuffer}
+ * is set on the Renderer</li>
+ * <li>The camera is set on the renderer, including its view port parameters.
+ * (see {@link #setCamera(com.jme3.renderer.Camera, boolean) })</li>
+ * <li>Any buffers that the ViewPort requests to be cleared are cleared
+ * and the {@link ViewPort#getBackgroundColor() background color} is set</li>
+ * <li>Every scene that is attached to the ViewPort is flattened into
+ * the ViewPort's render queue
+ * (see {@link #renderViewPortQueues(com.jme3.renderer.ViewPort, boolean) })
+ * </li>
+ * <li>The SceneProcessors' {@link SceneProcessor#postQueue(com.jme3.renderer.queue.RenderQueue) }
+ * method is called.</li>
+ * <li>The render queue is sorted and then flushed, sending
+ * rendering commands to the underlying Renderer implementation.
+ * (see {@link #flushQueue(com.jme3.renderer.ViewPort) })</li>
+ * <li>The SceneProcessors' {@link SceneProcessor#postFrame(com.jme3.texture.FrameBuffer) }
+ * method is called.</li>
+ * <li>The translucent queue of the ViewPort is sorted and then flushed
+ * (see {@link #renderTranslucentQueue(com.jme3.renderer.ViewPort) })</li>
+ * <li>If any objects remained in the render queue, they are removed
+ * from the queue. This is generally objects added to the
+ * {@link RenderQueue#renderShadowQueue(com.jme3.renderer.queue.RenderQueue.ShadowMode, com.jme3.renderer.RenderManager, com.jme3.renderer.Camera, boolean)
+ * shadow queue}
+ * which were not rendered because of a missing shadow renderer.</li>
+ * </ul>
+ *
+ * @param vp
+ * @param tpf
+ */
public void renderViewPort(ViewPort vp, float tpf) {
- if (!vp.isEnabled()) {
- return;
- }
+ if (!vp.isEnabled()) {
+ return;
+ }
List<SceneProcessor> processors = vp.getProcessors();
- if (processors.size() == 0) {
+ if (processors.isEmpty()) {
processors = null;
}
if (processors != null) {
- for (SceneProcessor proc : processors) {
+ int procSize = processors.size();
+// for (SceneProcessor proc : processors) {
+ for(int i=0;i<procSize;i++) {
+ SceneProcessor proc = processors.get(i);
if (!proc.isInitialized()) {
proc.initialize(this, vp);
}
renderer.setFrameBuffer(vp.getOutputFrameBuffer());
setCamera(vp.getCamera(), false);
- if (vp.isClearEnabled()) {
- renderer.setBackgroundColor(vp.getBackgroundColor());
+ if (vp.isClearDepth() || vp.isClearColor() || vp.isClearStencil()) {
+ if (vp.isClearColor()) {
+ renderer.setBackgroundColor(vp.getBackgroundColor());
+ }
renderer.clearBuffers(vp.isClearColor(),
vp.isClearDepth(),
vp.isClearStencil());
}
if (processors != null) {
- for (SceneProcessor proc : processors) {
+ int procSize = processors.size();
+// for (SceneProcessor proc : processors) {
+ for(int i=0;i<procSize;i++) {
+ SceneProcessor proc = processors.get(i);
proc.postQueue(vp.getQueue());
}
}
flushQueue(vp);
if (processors != null) {
- for (SceneProcessor proc : processors) {
+ int procSize = processors.size();
+// for (SceneProcessor proc : processors) {
+ for(int i=0;i<procSize;i++) {
+ SceneProcessor proc = processors.get(i);
proc.postFrame(vp.getOutputFrameBuffer());
}
}
-
+ //renders the translucent objects queue after processors have been rendered
+ renderTranslucentQueue(vp);
// clear any remaining spatials that were not rendered.
clearQueue(vp);
}
- public void render(float tpf) {
+ /**
+ * Called by the application to render any ViewPorts
+ * added to this RenderManager.
+ * <p>
+ * Renders any viewports that were added using the following methods:
+ * <ul>
+ * <li>{@link #createPreView(java.lang.String, com.jme3.renderer.Camera) }</li>
+ * <li>{@link #createMainView(java.lang.String, com.jme3.renderer.Camera) }</li>
+ * <li>{@link #createPostView(java.lang.String, com.jme3.renderer.Camera) }</li>
+ * </ul>
+ *
+ * @param tpf Time per frame value
+ */
+ public void render(float tpf, boolean mainFrameBufferActive) {
if (renderer instanceof NullRenderer) {
return;
}
this.shader = renderer.getCaps().contains(Caps.GLSL100);
for (int i = 0; i < preViewPorts.size(); i++) {
- renderViewPort(preViewPorts.get(i), tpf);
+ ViewPort vp = preViewPorts.get(i);
+ if (vp.getOutputFrameBuffer() != null || mainFrameBufferActive){
+ renderViewPort(vp, tpf);
+ }
}
for (int i = 0; i < viewPorts.size(); i++) {
- renderViewPort(viewPorts.get(i), tpf);
+ ViewPort vp = viewPorts.get(i);
+ if (vp.getOutputFrameBuffer() != null || mainFrameBufferActive){
+ renderViewPort(vp, tpf);
+ }
}
for (int i = 0; i < postViewPorts.size(); i++) {
- renderViewPort(postViewPorts.get(i), tpf);
+ ViewPort vp = postViewPorts.get(i);
+ if (vp.getOutputFrameBuffer() != null || mainFrameBufferActive){
+ renderViewPort(vp, tpf);
+ }
}
}
-
- //Remy - 09/14/2010 - added a setter for the timer in order to correctly populate g_Time and g_Tpf in the shaders
- public void setTimer(Timer timer) {
- this.timer = timer;
- }
-
- public String getForcedTechnique() {
- return forcedTechnique;
- }
-
- public void setForcedTechnique(String forcedTechnique) {
- this.forcedTechnique = forcedTechnique;
- }
-
- public void setAlphaToCoverage(boolean value) {
- renderer.setAlphaToCoverage(value);
- }
}