*merge from upstream

experimental
michael 10 years ago
commit f64eb5ff09
  1. 4
      CONTRIBUTING.md
  2. 14
      jme3-bullet/src/main/java/com/jme3/bullet/PhysicsSpace.java
  3. 9
      jme3-core/src/main/java/com/jme3/app/BasicProfilerState.java
  4. 52
      jme3-core/src/main/java/com/jme3/app/state/BaseAppState.java
  5. 45
      jme3-core/src/main/java/com/jme3/bounding/BoundingBox.java
  6. 42
      jme3-core/src/main/java/com/jme3/bounding/BoundingSphere.java
  7. 11
      jme3-core/src/main/java/com/jme3/bounding/BoundingVolume.java
  8. 28
      jme3-core/src/main/java/com/jme3/material/Material.java
  9. 37
      jme3-core/src/main/java/com/jme3/renderer/RenderManager.java
  10. 1
      jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java
  11. 55
      jme3-core/src/main/java/com/jme3/renderer/queue/RenderQueue.java
  12. 13
      jme3-core/src/main/java/com/jme3/scene/Node.java
  13. 1
      jme3-core/src/main/java/com/jme3/shader/Shader.java
  14. 33
      jme3-core/src/main/java/com/jme3/shadow/AbstractShadowRenderer.java
  15. 29
      jme3-core/src/main/java/com/jme3/shadow/BasicShadowRenderer.java
  16. 19
      jme3-core/src/main/java/com/jme3/shadow/DirectionalLightShadowRenderer.java
  17. 15
      jme3-core/src/main/java/com/jme3/shadow/PointLightShadowRenderer.java
  18. 22
      jme3-core/src/main/java/com/jme3/shadow/PssmShadowRenderer.java
  19. 309
      jme3-core/src/main/java/com/jme3/shadow/ShadowUtil.java
  20. 14
      jme3-core/src/main/java/com/jme3/shadow/SpotLightShadowRenderer.java
  21. 2
      jme3-core/src/main/java/com/jme3/util/MaterialDebugAppState.java
  22. 15
      jme3-core/src/main/resources/Common/MatDefs/Light/SPLighting.frag
  23. 10
      jme3-core/src/main/resources/Common/MatDefs/Light/SPLighting.vert
  24. 4
      jme3-core/src/plugins/java/com/jme3/asset/plugins/HttpZipLocator.java
  25. 380
      jme3-core/src/plugins/java/com/jme3/material/plugins/J3MLoader.java
  26. 573
      jme3-ios/src/main/java/com/jme3/renderer/ios/IosGL.java
  27. 22
      jme3-ios/src/main/java/com/jme3/system/ios/IGLESContext.java
  28. 14
      jme3-jbullet/src/main/java/com/jme3/bullet/PhysicsSpace.java
  29. 2
      jme3-networking/src/main/java/com/jme3/network/serializing/serializers/SavableSerializer.java
  30. 10
      jme3-plugins/src/ogre/java/com/jme3/scene/plugins/ogre/MaterialLoader.java

@ -5,7 +5,7 @@ First and foremost, you have to familiarize yourself with Git & GitHub. Dig thro
## Communication
Communication always comes first. **All** code changes and other contributions should start with the [forum](http://hub.jmonkeyengine.org/forum/). Make a thread to explain your change and show us the important bits of your code. If the code is too long to be posted within the forum’s code tags, please paste your code in a Gist or pastebin and link to the submission in your thread. You are required to register on our website in order to create threads.
Communication always comes first. **All** code changes and other contributions should start with the [forum](http://hub.jmonkeyengine.org/). Make a thread to explain your change and show us the important bits of your code. If the code is too long to be posted within the forum’s code tags, please paste your code in a Gist or pastebin and link to the submission in your thread. You are required to register on our website in order to create threads. (We do support login via GitHub though).
### New Contributors
@ -23,7 +23,7 @@ To import the local repository as a project follow these steps:
2. Navigate to the project directory in command line and execute command 'gradle eclipse'. This will load all the dependancies for eclipse.
3. In Eclipse, add the repository as an existing Java Project.
p.s. We will try hold ourselves to a [certain standard](http://www.defmacro.org/2013/04/03/issue-etiquette.html) when it comes to GitHub etiquette. If at any point we fail to uphold this standard, let us know.
#### Core Contributors

@ -405,8 +405,11 @@ public class PhysicsSpace {
((PhysicsControl) obj).setPhysicsSpace(this);
} else if (obj instanceof Spatial) {
Spatial node = (Spatial) obj;
PhysicsControl control = node.getControl(PhysicsControl.class);
control.setPhysicsSpace(this);
for (int i = 0; i < node.getNumControls(); i++) {
if (node.getControl(i) instanceof PhysicsControl) {
add(((PhysicsControl) node.getControl(i)));
}
}
} else if (obj instanceof PhysicsCollisionObject) {
addCollisionObject((PhysicsCollisionObject) obj);
} else if (obj instanceof PhysicsJoint) {
@ -438,7 +441,12 @@ public class PhysicsSpace {
if (obj instanceof PhysicsControl) {
((PhysicsControl) obj).setPhysicsSpace(null);
} else if (obj instanceof Spatial) {
remove(((Spatial) obj).getControl(PhysicsControl.class));
Spatial node = (Spatial) obj;
for (int i = 0; i < node.getNumControls(); i++) {
if (node.getControl(i) instanceof PhysicsControl) {
remove(((PhysicsControl) node.getControl(i)));
}
}
} else if (obj instanceof PhysicsCollisionObject) {
removeCollisionObject((PhysicsCollisionObject) obj);
} else if (obj instanceof PhysicsJoint) {

@ -61,7 +61,7 @@ public class BasicProfilerState extends BaseAppState {
private Geometry background;
private float scale = 2;
private ProfilerKeyListener keyListener = new ProfilerKeyListener();
private final ProfilerKeyListener keyListener = new ProfilerKeyListener();
public BasicProfilerState() {
this(false);
@ -84,6 +84,7 @@ public class BasicProfilerState extends BaseAppState {
* Sets the vertical scale of the visualization where
* each unit is a millisecond. Defaults to 2, ie: a
* single millisecond stretches two pixels high.
* @param scale the scale
*/
public void setGraphScale( float scale ) {
if( this.scale == scale ) {
@ -101,6 +102,7 @@ public class BasicProfilerState extends BaseAppState {
/**
* Sets the number frames displayed and tracked.
* @param count the number of frames
*/
public void setFrameCount( int count ) {
if( profiler.getFrameCount() == count ) {
@ -209,7 +211,7 @@ public class BasicProfilerState extends BaseAppState {
}
@Override
protected void enable() {
protected void onEnable() {
// Set the number of visible frames to the current width of the screen
setFrameCount(getApplication().getCamera().getWidth());
@ -221,7 +223,7 @@ public class BasicProfilerState extends BaseAppState {
}
@Override
protected void disable() {
protected void onDisable() {
getApplication().setAppProfiler(null);
graph.removeFromParent();
background.removeFromParent();
@ -229,6 +231,7 @@ public class BasicProfilerState extends BaseAppState {
private class ProfilerKeyListener implements ActionListener {
@Override
public void onAction(String name, boolean value, float tpf) {
if (!value) {
return;

@ -43,7 +43,7 @@ import java.util.logging.Logger;
* A base app state implementation the provides more built-in
* management convenience than AbstractAppState, including methods
* for enable/disable/initialize state management.
* The abstract enable() and disable() methods are called
* The abstract onEnable() and onDisable() methods are called
* appropriately during initialize(), terminate(), or setEnabled()
* depending on the mutual state of "initialized" and "enabled".
*
@ -52,20 +52,20 @@ import java.util.logging.Logger;
* app state is attached. This is useful for resources that might
* be expensive to create or load.</p>
*
* <p>enable()/disable() can be used for managing things that
* <p>onEnable()/onDisable() can be used for managing things that
* should only exist while the state is enabled. Prime examples
* would be scene graph attachment or input listener attachment.</p>
*
* <p>The base class logic is such that disable() will always be called
* <p>The base class logic is such that onDisable() will always be called
* before cleanup() if the state is enabled. Likewise, enable()
* will always be called after initialize() if the state is enable().
* enable()/disable() are also called appropriate when setEnabled()
* onEnable()/onDisable() are also called appropriate when setEnabled()
* is called that changes the enabled state AND if the state is attached.
* In other words, enable()/disable() are only ever called on an already
* In other words, onEnable()/onDisable() are only ever called on an already
* attached state.</p>
*
* <p>It is technically safe to do all initialization and cleanup in
* the enable()/disable() methods. Choosing to use initialize()
* the onEnable()/onDisable() methods. Choosing to use initialize()
* and cleanup() for this is a matter of performance specifics for the
* implementor.</p>
*
@ -81,15 +81,17 @@ public abstract class BaseAppState implements AppState {
/**
* Called during initialization once the app state is
* attached and before enable() is called.
* attached and before onEnable() is called.
* @param app the application
*/
protected abstract void initialize( Application app );
/**
* Called after the app state is detached or during
* application shutdown if the state is still attached.
* disable() is called before this cleanup() method if
* onDisable() is called before this cleanup() method if
* the state is enabled at the time of cleanup.
* @param app the application
*/
protected abstract void cleanup( Application app );
@ -98,21 +100,22 @@ public abstract class BaseAppState implements AppState {
* and isEnabled() is true or when the setEnabled() status
* changes after the state is attached.
*/
protected abstract void enable();
protected abstract void onEnable();
/**
* Called when the state was previously enabled but is
* now disabled either because setEnabled(false) was called
* or the state is being cleaned up.
*/
protected abstract void disable();
protected abstract void onDisable();
/**
* Do not call directly: Called by the state manager to initialize this
* state post-attachment.
* This implementation calls initialize(app) and then enable() if the
* This implementation calls initialize(app) and then onEnable() if the
* state is enabled.
*/
@Override
public final void initialize( AppStateManager stateManager, Application app ) {
log.log(Level.FINEST, "initialize():{0}", this);
@ -120,11 +123,12 @@ public abstract class BaseAppState implements AppState {
initialized = true;
initialize(app);
if( isEnabled() ) {
log.log(Level.FINEST, "enable():{0}", this);
enable();
log.log(Level.FINEST, "onEnable():{0}", this);
onEnable();
}
}
@Override
public final boolean isInitialized() {
return initialized;
}
@ -141,6 +145,7 @@ public abstract class BaseAppState implements AppState {
return getStateManager().getState(type);
}
@Override
public final void setEnabled( boolean enabled )
{
if( this.enabled == enabled )
@ -149,45 +154,52 @@ public abstract class BaseAppState implements AppState {
if( !isInitialized() )
return;
if( enabled ) {
log.log(Level.FINEST, "enable():{0}", this);
enable();
log.log(Level.FINEST, "onEnable():{0}", this);
onEnable();
} else {
log.log(Level.FINEST, "disable():{0}", this);
disable();
log.log(Level.FINEST, "onDisable():{0}", this);
onDisable();
}
}
@Override
public final boolean isEnabled() {
return enabled;
}
@Override
public void stateAttached( AppStateManager stateManager ) {
}
@Override
public void stateDetached( AppStateManager stateManager ) {
}
@Override
public void update( float tpf ) {
}
@Override
public void render( RenderManager rm ) {
}
@Override
public void postRender() {
}
/**
* Do not call directly: Called by the state manager to terminate this
* state post-detachment or during state manager termination.
* This implementation calls disable() if the state is enabled and
* This implementation calls onDisable() if the state is enabled and
* then cleanup(app).
*/
@Override
public final void cleanup() {
log.log(Level.FINEST, "cleanup():{0}", this);
if( isEnabled() ) {
log.log(Level.FINEST, "disable():{0}", this);
disable();
log.log(Level.FINEST, "onDisable():{0}", this);
onDisable();
}
cleanup(app);
initialized = false;

@ -761,6 +761,35 @@ public class BoundingBox extends BoundingVolume {
}
}
private int collideWithRay(Ray ray) {
TempVars vars = TempVars.get();
try {
Vector3f diff = vars.vect1.set(ray.origin).subtractLocal(center);
Vector3f direction = vars.vect2.set(ray.direction);
//float[] t = {0f, Float.POSITIVE_INFINITY};
float[] t = vars.fWdU; // use one of the tempvars arrays
t[0] = 0;
t[1] = Float.POSITIVE_INFINITY;
float saveT0 = t[0], saveT1 = t[1];
boolean notEntirelyClipped = clip(+direction.x, -diff.x - xExtent, t)
&& clip(-direction.x, +diff.x - xExtent, t)
&& clip(+direction.y, -diff.y - yExtent, t)
&& clip(-direction.y, +diff.y - yExtent, t)
&& clip(+direction.z, -diff.z - zExtent, t)
&& clip(-direction.z, +diff.z - zExtent, t);
if (notEntirelyClipped && (t[0] != saveT0 || t[1] != saveT1)) {
if (t[1] > t[0]) return 2;
else return 1;
}
return 0;
} finally {
vars.release();
}
}
public int collideWith(Collidable other, CollisionResults results) {
if (other instanceof Ray) {
Ray ray = (Ray) other;
@ -777,6 +806,22 @@ public class BoundingBox extends BoundingVolume {
throw new UnsupportedCollisionException("With: " + other.getClass().getSimpleName());
}
}
@Override
public int collideWith(Collidable other) {
if (other instanceof Ray) {
Ray ray = (Ray) other;
return collideWithRay(ray);
} else if (other instanceof Triangle) {
Triangle t = (Triangle) other;
if (intersects(t.get1(), t.get2(), t.get3())) {
return 1;
}
return 0;
} else {
throw new UnsupportedCollisionException("With: " + other.getClass().getSimpleName());
}
}
/**
* C code ported from <a href="http://www.cs.lth.se/home/Tomas_Akenine_Moller/code/tribox3.txt">

@ -792,7 +792,35 @@ public class BoundingSphere extends BoundingVolume {
return 1;
}
}
private int collideWithRay(Ray ray) {
TempVars vars = TempVars.get();
Vector3f diff = vars.vect1.set(ray.getOrigin()).subtractLocal(
center);
float a = diff.dot(diff) - (getRadius() * getRadius());
float a1, discr;
if (a <= 0.0) {
// inside sphere
vars.release();
return 1;
}
a1 = ray.direction.dot(diff);
vars.release();
if (a1 >= 0.0) {
return 0;
}
discr = a1 * a1 - a;
if (discr < 0.0) {
return 0;
} else if (discr >= FastMath.ZERO_TOLERANCE) {
return 2;
}
return 1;
}
private int collideWithTri(Triangle tri, CollisionResults results) {
TempVars tvars = TempVars.get();
try {
@ -991,6 +1019,18 @@ public class BoundingSphere extends BoundingVolume {
}
}
@Override public int collideWith(Collidable other) {
if (other instanceof Ray) {
Ray ray = (Ray) other;
return collideWithRay(ray);
} else if (other instanceof Triangle){
return super.collideWith(other);
} else {
throw new UnsupportedCollisionException();
}
}
@Override
public boolean contains(Vector3f point) {
return center.distanceSquared(point) < (getRadius() * getRadius());

@ -32,10 +32,12 @@
package com.jme3.bounding;
import com.jme3.collision.Collidable;
import com.jme3.collision.CollisionResults;
import com.jme3.export.JmeExporter;
import com.jme3.export.JmeImporter;
import com.jme3.export.Savable;
import com.jme3.math.*;
import com.jme3.util.TempVars;
import java.io.IOException;
import java.nio.FloatBuffer;
@ -322,6 +324,15 @@ public abstract class BoundingVolume implements Savable, Cloneable, Collidable {
public void read(JmeImporter e) throws IOException {
center = (Vector3f) e.getCapsule(this).readSavable("center", Vector3f.ZERO.clone());
}
public int collideWith(Collidable other) {
TempVars tempVars = TempVars.get();
CollisionResults tempResults = tempVars.collisionResults;
tempResults.clear();
int retval = collideWith(other, tempResults);
tempVars.release();
return retval;
}
}

@ -935,9 +935,9 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
renderMeshFromGeometry(r, g);
}
if (isFirstLight && lightList.size() > 0) {
// There are only ambient lights in the scene. Render
// a dummy "normal light" so we can see the ambient
if (isFirstLight) {
// Either there are no lights at all, or only ambient lights.
// Render a dummy "normal light" so we can see the ambient color.
ambientColor.setValue(VarType.Vector4, getAmbientColor(lightList, false));
lightColor.setValue(VarType.Vector4, ColorRGBA.BlackNoAlpha);
lightPos.setValue(VarType.Vector4, nullDirLight);
@ -1056,12 +1056,7 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
Collection<MatParam> params = paramValues.values();
for (MatParam param : params) {
if (param instanceof MatParamTexture) {
MatParamTexture texParam = (MatParamTexture) param;
r.setTexture(0, texParam.getTextureValue());
} else {
technique.updateUniformParam(param.getName(), param.getVarType(), param.getValue());
}
param.apply(r, technique);
}
r.setShader(technique.getShader());
@ -1157,11 +1152,6 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
TechniqueDef techDef = technique.getDef();
if (techDef.getLightMode() == LightMode.MultiPass
&& lights.size() == 0) {
return;
}
if (rm.getForcedRenderState() != null) {
r.applyRenderState(rm.getForcedRenderState());
} else {
@ -1196,10 +1186,16 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
case SinglePass:
int nbRenderedLights = 0;
resetUniformsNotSetByCurrent(shader);
while (nbRenderedLights < lights.size()) {
nbRenderedLights = updateLightListUniforms(shader, geom, lights, rm.getSinglePassLightBatchSize(), rm, nbRenderedLights);
if (lights.size() == 0) {
nbRenderedLights = updateLightListUniforms(shader, geom, lights, rm.getSinglePassLightBatchSize(), rm, 0);
r.setShader(shader);
renderMeshFromGeometry(r, geom);
} else {
while (nbRenderedLights < lights.size()) {
nbRenderedLights = updateLightListUniforms(shader, geom, lights, rm.getSinglePassLightBatchSize(), rm, nbRenderedLights);
r.setShader(shader);
renderMeshFromGeometry(r, geom);
}
}
return;
case FixedPipeline:

@ -586,29 +586,6 @@ public class RenderManager {
}
}
/**
* If a spatial is not inside the eye frustum, it
* 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) {
Node n = (Node) s;
List<Spatial> children = n.getChildren();
for (int i = 0; i < children.size(); i++) {
renderShadow(children.get(i), rq);
}
} else if (s instanceof Geometry) {
Geometry gm = (Geometry) s;
RenderQueue.ShadowMode shadowMode = s.getShadowMode();
if (shadowMode != RenderQueue.ShadowMode.Off && shadowMode != RenderQueue.ShadowMode.Receive && !gm.isGrouped()) {
//forcing adding to shadow cast mode, culled objects doesn't have to be in the receiver queue
rq.addToShadowQueue(gm, RenderQueue.ShadowMode.Cast);
}
}
}
/**
* Preloads a scene for rendering.
* <p>
@ -690,10 +667,6 @@ public class RenderManager {
// check culling first.
if (!scene.checkCulling(vp.getCamera())) {
// move on to shadow-only render
if ((scene.getShadowMode() != RenderQueue.ShadowMode.Off || scene instanceof Node) && scene.getCullHint() != Spatial.CullHint.Always) {
renderShadow(scene, vp.getQueue());
}
return;
}
@ -717,12 +690,6 @@ public class RenderManager {
}
vp.getQueue().addToQueue(gm, scene.getQueueBucket());
// add to shadow queue if needed
RenderQueue.ShadowMode shadowMode = scene.getShadowMode();
if (shadowMode != RenderQueue.ShadowMode.Off) {
vp.getQueue().addToShadowQueue(gm, shadowMode);
}
}
}
@ -898,8 +865,8 @@ public class RenderManager {
if (cam != prevCam || cam.isViewportChanged()) {
viewX = (int) (cam.getViewPortLeft() * cam.getWidth());
viewY = (int) (cam.getViewPortBottom() * cam.getHeight());
viewWidth = (int) ((cam.getViewPortRight() - cam.getViewPortLeft()) * cam.getWidth());
viewHeight = (int) ((cam.getViewPortTop() - cam.getViewPortBottom()) * cam.getHeight());
viewWidth = ((int)(cam.getViewPortRight() * cam.getWidth())) - ((int)(cam.getViewPortLeft() * cam.getWidth()));
viewHeight = ((int)(cam.getViewPortTop() * cam.getHeight())) - ((int)(cam.getViewPortBottom() * cam.getHeight()));
uniformBindingManager.setViewPort(viewX, viewY, viewWidth, viewHeight);
renderer.setViewPort(viewX, viewY, viewWidth, viewHeight);
renderer.setClipRect(viewX, viewY, viewWidth, viewHeight);

@ -351,6 +351,7 @@ public class GLRenderer implements Renderer {
if (hasExtension("GL_ARB_texture_non_power_of_two") ||
hasExtension("GL_OES_texture_npot") ||
hasExtension("GL_APPLE_texture_2D_limited_npot") ||
caps.contains(Caps.OpenGL30)) {
caps.add(Caps.NonPowerOfTwoTextures);
} else {

@ -51,7 +51,6 @@ public class RenderQueue {
private GeometryList translucentList;
private GeometryList skyList;
private GeometryList shadowRecv;
private GeometryList shadowCast;
/**
* Creates a new RenderQueue, the default {@link GeometryComparator comparators}
@ -64,7 +63,6 @@ public class RenderQueue {
this.translucentList = new GeometryList(new TransparentComparator());
this.skyList = new GeometryList(new NullComparator());
this.shadowRecv = new GeometryList(new OpaqueComparator());
this.shadowCast = new GeometryList(new OpaqueComparator());
}
/**
@ -229,40 +227,6 @@ public class RenderQueue {
}
}
/**
* Adds a geometry to a shadow bucket.
* Note that this operation is done automatically by the
* {@link RenderManager}. {@link SceneProcessor}s that handle
* shadow rendering should fetch the queue by using
* {@link #getShadowQueueContent(com.jme3.renderer.queue.RenderQueue.ShadowMode) },
* by default no action is taken on the shadow queues.
*
* @param g The geometry to add
* @param shadBucket The shadow bucket type, if it is
* {@link ShadowMode#CastAndReceive}, it is added to both the cast
* and the receive buckets.
*/
public void addToShadowQueue(Geometry g, ShadowMode shadBucket) {
switch (shadBucket) {
case Inherit:
break;
case Off:
break;
case Cast:
shadowCast.add(g);
break;
case Receive:
shadowRecv.add(g);
break;
case CastAndReceive:
shadowCast.add(g);
shadowRecv.add(g);
break;
default:
throw new UnsupportedOperationException("Unrecognized shadow bucket type: " + shadBucket);
}
}
/**
* Adds a geometry to the given bucket.
* The {@link RenderManager} automatically handles this task
@ -298,14 +262,11 @@ public class RenderQueue {
/**
*
* @param shadBucket The shadow mode to retrieve the {@link GeometryList
* queue content} for. Only {@link ShadowMode#Cast Cast} and
* {@link ShadowMode#Receive Receive} are valid.
* queue content} for. Only {@link ShadowMode#Receive Receive} is valid.
* @return The cast or receive {@link GeometryList}
*/
public GeometryList getShadowQueueContent(ShadowMode shadBucket) {
switch (shadBucket) {
case Cast:
return shadowCast;
case Receive:
return shadowRecv;
default:
@ -331,19 +292,6 @@ public class RenderQueue {
renderGeometryList(list, rm, cam, clear);
}
public void renderShadowQueue(ShadowMode shadBucket, RenderManager rm, Camera cam, boolean clear) {
switch (shadBucket) {
case Cast:
renderGeometryList(shadowCast, rm, cam, clear);
break;
case Receive:
renderGeometryList(shadowRecv, rm, cam, clear);
break;
default:
throw new IllegalArgumentException("Unexpected shadow bucket: " + shadBucket);
}
}
public boolean isQueueEmpty(Bucket bucket) {
switch (bucket) {
case Gui:
@ -394,7 +342,6 @@ public class RenderQueue {
transparentList.clear();
translucentList.clear();
skyList.clear();
shadowCast.clear();
shadowRecv.clear();
}
}

@ -39,6 +39,7 @@ import com.jme3.export.JmeImporter;
import com.jme3.export.Savable;
import com.jme3.material.Material;
import com.jme3.util.SafeArrayList;
import com.jme3.util.TempVars;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@ -565,6 +566,18 @@ public class Node extends Spatial implements Savable {
public int collideWith(Collidable other, CollisionResults results){
int total = 0;
// optimization: try collideWith BoundingVolume to avoid possibly redundant tests on children
// number 4 in condition is somewhat arbitrary. When there is only one child, the boundingVolume test is redundant at all.
// The idea is when there are few children, it can be too expensive to test boundingVolume first.
if (children.size() > 4)
{
BoundingVolume bv = this.getWorldBound();
if (bv==null) return 0;
// collideWith without CollisionResults parameter used to avoid allocation when possible
if (bv.collideWith(other) == 0) return 0;
}
for (Spatial child : children.getArray()){
total += child.collideWith(other, results);
}

@ -249,6 +249,7 @@ public final class Shader extends NativeObject {
}
public Uniform getUniform(String name){
assert name.startsWith("m_") || name.startsWith("g_");
Uniform uniform = uniforms.get(name);
if (uniform == null){
uniform = new Uniform();

@ -363,7 +363,7 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable
* @param shadowMapOcculders
* @return
*/
protected abstract GeometryList getOccludersToRender(int shadowMapIndex, GeometryList sceneOccluders, GeometryList sceneReceivers, GeometryList shadowMapOccluders);
protected abstract GeometryList getOccludersToRender(int shadowMapIndex, GeometryList shadowMapOccluders);
/**
* return the shadow camera to use for rendering the shadow map according
@ -385,10 +385,10 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable
@SuppressWarnings("fallthrough")
public void postQueue(RenderQueue rq) {
GeometryList occluders = rq.getShadowQueueContent(ShadowMode.Cast);
sceneReceivers = rq.getShadowQueueContent(ShadowMode.Receive);
lightReceivers.clear();
skipPostPass = false;
if (sceneReceivers.size() == 0 || occluders.size() == 0 || !checkCulling(viewPort.getCamera())) {
if ( !checkCulling(viewPort.getCamera()) ) {
skipPostPass = true;
return;
}
@ -404,14 +404,12 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable
if (debugfrustums) {
doDisplayFrustumDebug(shadowMapIndex);
}
renderShadowMap(shadowMapIndex, occluders, sceneReceivers);
renderShadowMap(shadowMapIndex);
}
debugfrustums = false;
if (flushQueues) {
occluders.clear();
}
//restore setting for future rendering
r.setFrameBuffer(viewPort.getOutputFrameBuffer());
renderManager.setForcedMaterial(null);
@ -420,8 +418,8 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable
}
protected void renderShadowMap(int shadowMapIndex, GeometryList occluders, GeometryList receivers) {
shadowMapOccluders = getOccludersToRender(shadowMapIndex, occluders, receivers, shadowMapOccluders);
protected void renderShadowMap(int shadowMapIndex) {
shadowMapOccluders = getOccludersToRender(shadowMapIndex, shadowMapOccluders);
Camera shadowCam = getShadowCam(shadowMapIndex);
//saving light view projection matrix for this split
@ -473,12 +471,12 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable
if (debug) {
displayShadowMap(renderManager.getRenderer());
}
lightReceivers = getReceivers(sceneReceivers, lightReceivers);
if (lightReceivers.size() != 0) {
//setting params to recieving geometry list
setMatParams();
setMatParams(lightReceivers);
Camera cam = viewPort.getCamera();
//some materials in the scene does not have a post shadow technique so we're using the fall back material
@ -491,9 +489,6 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable
//rendering the post shadow pass
viewPort.getQueue().renderShadowQueue(lightReceivers, renderManager, cam, false);
if (flushQueues) {
sceneReceivers.clear();
}
//resetting renderManager settings
renderManager.setForcedTechnique(null);
@ -504,6 +499,9 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable
clearMatParams();
}
if (flushQueues) {
sceneReceivers.clear();
}
}
/**
@ -541,10 +539,7 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable
*/
protected abstract void setMaterialParameters(Material material);
private void setMatParams() {
GeometryList l = viewPort.getQueue().getShadowQueueContent(ShadowMode.Receive);
private void setMatParams(GeometryList l) {
//iteration throught all the geometries of the list to gather the materials
matCache.clear();
@ -785,4 +780,4 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable
oc.write(flushQueues, "flushQueues", false);
oc.write(edgesThickness, "edgesThickness", 1.0f);
}
}
}

@ -40,8 +40,10 @@ import com.jme3.renderer.RenderManager;
import com.jme3.renderer.Renderer;
import com.jme3.renderer.ViewPort;
import com.jme3.renderer.queue.GeometryList;
import com.jme3.renderer.queue.OpaqueComparator;
import com.jme3.renderer.queue.RenderQueue;
import com.jme3.renderer.queue.RenderQueue.ShadowMode;
import com.jme3.scene.Spatial;
import com.jme3.texture.FrameBuffer;
import com.jme3.texture.Image.Format;
import com.jme3.texture.Texture2D;
@ -71,6 +73,9 @@ public class BasicShadowRenderer implements SceneProcessor {
protected Texture2D dummyTex;
private float shadowMapSize;
protected GeometryList lightReceivers = new GeometryList(new OpaqueComparator());
protected GeometryList shadowOccluders = new GeometryList(new OpaqueComparator());
/**
* Creates a BasicShadowRenderer
* @param manager the asset manager
@ -142,16 +147,10 @@ public class BasicShadowRenderer implements SceneProcessor {
}
public void postQueue(RenderQueue rq) {
GeometryList occluders = rq.getShadowQueueContent(ShadowMode.Cast);
if (occluders.size() == 0) {
noOccluders = true;
return;
} else {
noOccluders = false;
for (Spatial scene : viewPort.getScenes()) {
ShadowUtil.getGeometriesInCamFrustum(scene, viewPort.getCamera(), ShadowMode.Receive, lightReceivers);
}
GeometryList receivers = rq.getShadowQueueContent(ShadowMode.Receive);
// update frustum points based on current camera
Camera viewCam = viewPort.getCamera();
ShadowUtil.updateFrustumPoints(viewCam,
@ -178,15 +177,21 @@ public class BasicShadowRenderer implements SceneProcessor {
shadowCam.updateViewProjection();
// render shadow casters to shadow map
ShadowUtil.updateShadowCamera(occluders, receivers, shadowCam, points, shadowMapSize);
ShadowUtil.updateShadowCamera(viewPort, lightReceivers, shadowCam, points, shadowOccluders, shadowMapSize);
if (shadowOccluders.size() == 0) {
noOccluders = true;
return;
} else {
noOccluders = false;
}
Renderer r = renderManager.getRenderer();
renderManager.setCamera(shadowCam, false);
renderManager.setForcedMaterial(preshadowMat);
r.setFrameBuffer(shadowFB);
r.clearBuffers(false, true, false);
viewPort.getQueue().renderShadowQueue(ShadowMode.Cast, renderManager, shadowCam, true);
viewPort.getQueue().renderShadowQueue(shadowOccluders, renderManager, shadowCam, true);
r.setFrameBuffer(viewPort.getOutputFrameBuffer());
renderManager.setForcedMaterial(null);
@ -205,7 +210,7 @@ public class BasicShadowRenderer implements SceneProcessor {
if (!noOccluders) {
postshadowMat.setMatrix4("LightViewProjectionMatrix", shadowCam.getViewProjectionMatrix());
renderManager.setForcedMaterial(postshadowMat);
viewPort.getQueue().renderShadowQueue(ShadowMode.Receive, renderManager, viewPort.getCamera(), true);
viewPort.getQueue().renderShadowQueue(lightReceivers, renderManager, viewPort.getCamera(), true);
renderManager.setForcedMaterial(null);
}
}

@ -43,7 +43,9 @@ import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.renderer.Camera;
import com.jme3.renderer.queue.GeometryList;
import com.jme3.renderer.queue.RenderQueue;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import java.io.IOException;
/**
@ -173,19 +175,30 @@ public class DirectionalLightShadowRenderer extends AbstractShadowRenderer {
}
@Override
protected GeometryList getOccludersToRender(int shadowMapIndex, GeometryList sceneOccluders, GeometryList sceneReceivers, GeometryList shadowMapOccluders) {
protected GeometryList getOccludersToRender(int shadowMapIndex, GeometryList shadowMapOccluders) {
// update frustum points based on current camera and split
ShadowUtil.updateFrustumPoints(viewPort.getCamera(), splitsArray[shadowMapIndex], splitsArray[shadowMapIndex + 1], 1.0f, points);
//Updating shadow cam with curent split frustra
ShadowUtil.updateShadowCamera(sceneOccluders, sceneReceivers, shadowCam, points, shadowMapOccluders, stabilize?shadowMapSize:0);
//Updating shadow cam with curent split frustra
if (sceneReceivers.size()==0) {
for (Spatial scene : viewPort.getScenes()) {
ShadowUtil.getGeometriesInCamFrustum(scene, viewPort.getCamera(), RenderQueue.ShadowMode.Receive, sceneReceivers);
}
}
ShadowUtil.updateShadowCamera(viewPort, sceneReceivers, shadowCam, points, shadowMapOccluders, stabilize?shadowMapSize:0);
return shadowMapOccluders;
}
@Override
GeometryList getReceivers(GeometryList sceneReceivers, GeometryList lightReceivers) {
if (sceneReceivers.size()==0) {
for (Spatial scene : viewPort.getScenes()) {
ShadowUtil.getGeometriesInCamFrustum(scene, viewPort.getCamera(), RenderQueue.ShadowMode.Receive, sceneReceivers);
}
}
lightReceivers = sceneReceivers;
return sceneReceivers;
}

@ -41,8 +41,10 @@ import com.jme3.material.Material;
import com.jme3.math.Vector3f;
import com.jme3.renderer.Camera;
import com.jme3.renderer.queue.GeometryList;
import com.jme3.renderer.queue.RenderQueue;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.util.TempVars;
import java.io.IOException;
@ -129,15 +131,19 @@ public class PointLightShadowRenderer extends AbstractShadowRenderer {
}
@Override
protected GeometryList getOccludersToRender(int shadowMapIndex, GeometryList sceneOccluders, GeometryList sceneReceivers, GeometryList shadowMapOccluders) {
ShadowUtil.getGeometriesInCamFrustum(sceneOccluders, shadowCams[shadowMapIndex], shadowMapOccluders);
protected GeometryList getOccludersToRender(int shadowMapIndex, GeometryList shadowMapOccluders) {
for (Spatial scene : viewPort.getScenes()) {
ShadowUtil.getGeometriesInCamFrustum(scene, shadowCams[shadowMapIndex], RenderQueue.ShadowMode.Cast, shadowMapOccluders);
}
return shadowMapOccluders;
}
@Override
GeometryList getReceivers(GeometryList sceneReceivers, GeometryList lightReceivers) {
lightReceivers.clear();
ShadowUtil.getGeometriesInLightRadius(sceneReceivers, shadowCams, lightReceivers);
for (Spatial scene : viewPort.getScenes()) {
ShadowUtil.getLitGeometriesInViewPort(scene, viewPort.getCamera(), shadowCams, RenderQueue.ShadowMode.Receive, lightReceivers);
}
return lightReceivers;
}
@ -207,7 +213,7 @@ public class PointLightShadowRenderer extends AbstractShadowRenderer {
oc.write(light, "light", null);
}
/**
/**
*
* @param viewCam
* @return
@ -224,6 +230,5 @@ public class PointLightShadowRenderer extends AbstractShadowRenderer {
boolean intersects = light.intersectsFrustum(cam,vars);
vars.release();
return intersects;
}
}

@ -175,6 +175,8 @@ public class PssmShadowRenderer implements SceneProcessor {
protected float fadeLength;
protected boolean applyFadeInfo = false;
protected GeometryList lightReceivers = new GeometryList(new OpaqueComparator());
/**
* Create a PSSM Shadow Renderer More info on the technique at <a
* href="http://http.developer.nvidia.com/GPUGems3/gpugems3_ch10.html">http://http.developer.nvidia.com/GPUGems3/gpugems3_ch10.html</a>
@ -385,14 +387,8 @@ public class PssmShadowRenderer implements SceneProcessor {
@SuppressWarnings("fallthrough")
public void postQueue(RenderQueue rq) {
GeometryList occluders = rq.getShadowQueueContent(ShadowMode.Cast);
if (occluders.size() == 0) {
return;
}
GeometryList receivers = rq.getShadowQueueContent(ShadowMode.Receive);
if (receivers.size() == 0) {
return;
for (Spatial scene : viewPort.getScenes()) {
ShadowUtil.getGeometriesInCamFrustum(scene, viewPort.getCamera(), ShadowMode.Receive, lightReceivers);
}
Camera viewCam = viewPort.getCamera();
@ -437,7 +433,7 @@ public class PssmShadowRenderer implements SceneProcessor {
ShadowUtil.updateFrustumPoints(viewCam, splitsArray[i], splitsArray[i + 1], 1.0f, points);
//Updating shadow cam with curent split frustra
ShadowUtil.updateShadowCamera(occluders, receivers, shadowCam, points, splitOccluders, shadowMapSize);
ShadowUtil.updateShadowCamera(viewPort, lightReceivers, shadowCam, points, splitOccluders, shadowMapSize);
//saving light view projection matrix for this split
lightViewProjectionsMatrices[i].set(shadowCam.getViewProjectionMatrix());
@ -460,9 +456,7 @@ public class PssmShadowRenderer implements SceneProcessor {
viewPort.getQueue().renderShadowQueue(splitOccluders, renderManager, shadowCam, true);
}
debugfrustums = false;
if (flushQueues) {
occluders.clear();
}
//restore setting for future rendering
r.setFrameBuffer(viewPort.getOutputFrameBuffer());
renderManager.setForcedMaterial(null);
@ -518,7 +512,7 @@ public class PssmShadowRenderer implements SceneProcessor {
renderManager.setForcedTechnique(postTechniqueName);
//rendering the post shadow pass
viewPort.getQueue().renderShadowQueue(ShadowMode.Receive, renderManager, cam, flushQueues);
viewPort.getQueue().renderShadowQueue(lightReceivers, renderManager, cam, true);
//resetting renderManager settings
renderManager.setForcedTechnique(null);
@ -531,7 +525,7 @@ public class PssmShadowRenderer implements SceneProcessor {
private void setMatParams() {
GeometryList l = viewPort.getQueue().getShadowQueueContent(ShadowMode.Receive);
GeometryList l = lightReceivers;
//iteration throught all the geometries of the list to gather the materials

@ -39,8 +39,12 @@ import com.jme3.math.Transform;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.renderer.Camera;
import com.jme3.renderer.ViewPort;
import com.jme3.renderer.queue.GeometryList;
import com.jme3.renderer.queue.RenderQueue;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.util.TempVars;
import static java.lang.Math.max;
import static java.lang.Math.min;
@ -328,31 +332,128 @@ public class ShadowUtil {
}
/**
* Updates the shadow camera to properly contain the given points (which
* contain the eye camera frustum corners) and the shadow occluder objects.
*
* @param occluders
* @param receivers
* @param shadowCam
* @param points
* OccludersExtractor is a helper class to collect splitOccluders from scene recursively.
* It utilizes the scene hierarchy, instead of making the huge flat geometries list first.
* Instead of adding all geometries from scene to the RenderQueue.shadowCast and checking
* all of them one by one against camera frustum the whole Node is checked first
* to hopefully avoid the check on its children.
*/
public static void updateShadowCamera(GeometryList occluders,
GeometryList receivers,
Camera shadowCam,
Vector3f[] points,
float shadowMapSize) {
updateShadowCamera(occluders, receivers, shadowCam, points, null, shadowMapSize);
}
public static class OccludersExtractor
{
// global variables set in order not to have recursive process method with too many parameters
Matrix4f viewProjMatrix;
public Integer casterCount;
BoundingBox splitBB, casterBB;
GeometryList splitOccluders;
TempVars vars;
public OccludersExtractor() {}
// initialize the global OccludersExtractor variables
public OccludersExtractor(Matrix4f vpm, int cc, BoundingBox sBB, BoundingBox cBB, GeometryList sOCC, TempVars v) {
viewProjMatrix = vpm;
casterCount = cc;
splitBB = sBB;
casterBB = cBB;
splitOccluders = sOCC;
vars = v;
}
/**
* Check the rootScene against camera frustum and if intersects process it recursively.
* The global OccludersExtractor variables need to be initialized first.
* Variables are updated and used in {@link ShadowUtil#updateShadowCamera} at last.
*/
public int addOccluders(Spatial scene) {
if ( scene != null ) process(scene);
return casterCount;
}
private void process(Spatial scene) {
if (scene.getCullHint() == Spatial.CullHint.Always) return;
RenderQueue.ShadowMode shadowMode = scene.getShadowMode();
if ( scene instanceof Geometry )
{
// convert bounding box to light's viewproj space
Geometry occluder = (Geometry)scene;
if (shadowMode != RenderQueue.ShadowMode.Off && shadowMode != RenderQueue.ShadowMode.Receive
&& !occluder.isGrouped() && occluder.getWorldBound()!=null) {
BoundingVolume bv = occluder.getWorldBound();
BoundingVolume occBox = bv.transform(viewProjMatrix, vars.bbox);
boolean intersects = splitBB.intersects(occBox);
if (!intersects && occBox instanceof BoundingBox) {
BoundingBox occBB = (BoundingBox) occBox;
//Kirill 01/10/2011
// Extend the occluder further into the frustum
// This fixes shadow dissapearing issues when
// the caster itself is not in the view camera
// but its shadow is in the camera
// The number is in world units
occBB.setZExtent(occBB.getZExtent() + 50);
occBB.setCenter(occBB.getCenter().addLocal(0, 0, 25));
if (splitBB.intersects(occBB)) {
//Nehon : prevent NaN and infinity values to screw the final bounding box
if (!Float.isNaN(occBox.getCenter().x) && !Float.isInfinite(occBox.getCenter().x)) {
// To prevent extending the depth range too much
// We return the bound to its former shape
// Before adding it
occBB.setZExtent(occBB.getZExtent() - 50);
occBB.setCenter(occBB.getCenter().subtractLocal(0, 0, 25));
casterBB.mergeLocal(occBox);
casterCount++;
}
if (splitOccluders != null) {
splitOccluders.add(occluder);
}
}
} else if (intersects) {
casterBB.mergeLocal(occBox);
casterCount++;
if (splitOccluders != null) {
splitOccluders.add(occluder);
}
}
}
}
else if ( scene instanceof Node && ((Node)scene).getWorldBound()!=null )
{
Node nodeOcc = (Node)scene;
boolean intersects = false;
// some
BoundingVolume bv = nodeOcc.getWorldBound();
BoundingVolume occBox = bv.transform(viewProjMatrix, vars.bbox);
intersects = splitBB.intersects(occBox);
if (!intersects && occBox instanceof BoundingBox) {
BoundingBox occBB = (BoundingBox) occBox;
//Kirill 01/10/2011
// Extend the occluder further into the frustum
// This fixes shadow dissapearing issues when
// the caster itself is not in the view camera
// but its shadow is in the camera
// The number is in world units
occBB.setZExtent(occBB.getZExtent() + 50);
occBB.setCenter(occBB.getCenter().addLocal(0, 0, 25));
intersects = splitBB.intersects(occBB);
}
if ( intersects ) {
for (Spatial child : ((Node)scene).getChildren()) {
process(child);
}
}
}
}
}
/**
* Updates the shadow camera to properly contain the given points (which
* contain the eye camera frustum corners) and the shadow occluder objects.
*
* @param occluders
* @param shadowCam
* @param points
* contain the eye camera frustum corners) and the shadow occluder objects
* collected through the traverse of the scene hierarchy
*/
public static void updateShadowCamera(GeometryList occluders,
public static void updateShadowCamera(ViewPort viewPort,
GeometryList receivers,
Camera shadowCam,
Vector3f[] points,
@ -394,48 +495,13 @@ public class ShadowUtil {
}
}
for (int i = 0; i < occluders.size(); i++) {
// convert bounding box to light's viewproj space
Geometry occluder = occluders.get(i);
BoundingVolume bv = occluder.getWorldBound();
BoundingVolume occBox = bv.transform(viewProjMatrix, vars.bbox);
boolean intersects = splitBB.intersects(occBox);
if (!intersects && occBox instanceof BoundingBox) {
BoundingBox occBB = (BoundingBox) occBox;
//Kirill 01/10/2011
// Extend the occluder further into the frustum
// This fixes shadow dissapearing issues when
// the caster itself is not in the view camera
// but its shadow is in the camera
// The number is in world units
occBB.setZExtent(occBB.getZExtent() + 50);
occBB.setCenter(occBB.getCenter().addLocal(0, 0, 25));
if (splitBB.intersects(occBB)) {
//Nehon : prevent NaN and infinity values to screw the final bounding box
if (!Float.isNaN(occBox.getCenter().x) && !Float.isInfinite(occBox.getCenter().x)) {
// To prevent extending the depth range too much
// We return the bound to its former shape
// Before adding it
occBB.setZExtent(occBB.getZExtent() - 50);
occBB.setCenter(occBB.getCenter().subtractLocal(0, 0, 25));
casterBB.mergeLocal(occBox);
casterCount++;
}
if (splitOccluders != null) {
splitOccluders.add(occluder);
}
}
} else if (intersects) {
casterBB.mergeLocal(occBox);
casterCount++;
if (splitOccluders != null) {
splitOccluders.add(occluder);
}
}
// collect splitOccluders through scene recursive traverse
OccludersExtractor occExt = new OccludersExtractor(viewProjMatrix, casterCount, splitBB, casterBB, splitOccluders, vars);
for (Spatial scene : viewPort.getScenes()) {
occExt.addOccluders(scene);
}
casterCount = occExt.casterCount;
//Nehon 08/18/2010 this is to avoid shadow bleeding when the ground is set to only receive shadows
if (casterCount != receiverCount) {
casterBB.setXExtent(casterBB.getXExtent() + 2.0f);
@ -523,9 +589,8 @@ public class ShadowUtil {
vars.release();
shadowCam.setProjectionMatrix(result);
}
/**
* Populates the outputGeometryList with the geometry of the
* inputGeomtryList that are in the frustum of the given camera
@ -551,10 +616,76 @@ public class ShadowUtil {
}
/**
* Populates the outputGeometryList with the rootScene children geometries
* that are in the frustum of the given camera
*
* @param rootScene the rootNode of the scene to traverse
* @param camera the camera to check geometries against
* @param outputGeometryList the list of all geometries that are in the
* camera frustum
*/
public static void getGeometriesInCamFrustum(Spatial rootScene, Camera camera, RenderQueue.ShadowMode mode, GeometryList outputGeometryList) {
if (rootScene != null && rootScene instanceof Node) {
int planeState = camera.getPlaneState();
addGeometriesInCamFrustumFromNode(camera, (Node)rootScene, mode, outputGeometryList);
camera.setPlaneState(planeState);
}
}
/**
* Helper function to distinguish between Occluders and Receivers
*
* @param shadowMode the ShadowMode tested
* @param desired the desired ShadowMode
* @return true if tested ShadowMode matches the desired one
*/
static private boolean checkShadowMode(RenderQueue.ShadowMode shadowMode, RenderQueue.ShadowMode desired)
{
if (shadowMode != RenderQueue.ShadowMode.Off)
{
switch (desired) {
case Cast :
return shadowMode==RenderQueue.ShadowMode.Cast || shadowMode==RenderQueue.ShadowMode.CastAndReceive;
case Receive:
return shadowMode==RenderQueue.ShadowMode.Receive || shadowMode==RenderQueue.ShadowMode.CastAndReceive;
case CastAndReceive:
return true;
}
}
return false;
}
/**
* Helper function used to recursively populate the outputGeometryList
* with geometry children of scene node
*
* @param camera
* @param scene
* @param outputGeometryList
*/
private static void addGeometriesInCamFrustumFromNode(Camera camera, Node scene, RenderQueue.ShadowMode mode, GeometryList outputGeometryList) {
if (scene.getCullHint() == Spatial.CullHint.Always) return;
camera.setPlaneState(0);
if (camera.contains(scene.getWorldBound()) != Camera.FrustumIntersect.Outside) {
for (Spatial child: scene.getChildren()) {
if (child instanceof Node) addGeometriesInCamFrustumFromNode(camera, (Node)child, mode, outputGeometryList);
else if (child instanceof Geometry && child.getCullHint() != Spatial.CullHint.Always) {
camera.setPlaneState(0);
if (checkShadowMode(child.getShadowMode(), mode) &&
!((Geometry)child).isGrouped() &&
camera.contains(child.getWorldBound()) != Camera.FrustumIntersect.Outside) {
outputGeometryList.add((Geometry)child);
}
}
}
}
}
/**
* Populates the outputGeometryList with the geometry of the
* inputGeomtryList that are in the radius of a light.
* The array of camera must be an array of 6 cameara initialized so they represent the light viewspace of a pointlight
* The array of camera must be an array of 6 cameras initialized so they represent the light viewspace of a pointlight
*
* @param inputGeometryList The list containing all geometry to check
* against the camera frustum
@ -581,4 +712,54 @@ public class ShadowUtil {
}
}
/**
* Populates the outputGeometryList with the geometries of the children
* of OccludersExtractor.rootScene node that are both in the frustum of the given vpCamera and some camera inside cameras array.
* The array of cameras must be initialized to represent the light viewspace of some light like pointLight or spotLight
*
* @param camera the viewPort camera
* @param cameras the camera array to check geometries against, representing the light viewspace
* @param outputGeometryList the output list of all geometries that are in the camera frustum
*/
public static void getLitGeometriesInViewPort(Spatial rootScene, Camera vpCamera, Camera[] cameras, RenderQueue.ShadowMode mode, GeometryList outputGeometryList) {
if (rootScene != null && rootScene instanceof Node) {
addGeometriesInCamFrustumAndViewPortFromNode(vpCamera, cameras, (Node)rootScene, mode, outputGeometryList);
}
}
/**
* Helper function to recursively collect the geometries for getLitGeometriesInViewPort function.
*
* @param vpCamera the viewPort camera
* @param cameras the camera array to check geometries against, representing the light viewspace
* @param scene the Node to traverse or geometry to possibly add
* @param outputGeometryList the output list of all geometries that are in the camera frustum
*/
private static void addGeometriesInCamFrustumAndViewPortFromNode(Camera vpCamera, Camera[] cameras, Spatial scene, RenderQueue.ShadowMode mode, GeometryList outputGeometryList) {
if (scene.getCullHint() == Spatial.CullHint.Always) return;
boolean inFrustum = false;
for (int j = 0; j < cameras.length && inFrustum == false; j++) {
Camera camera = cameras[j];
int planeState = camera.getPlaneState();
camera.setPlaneState(0);
inFrustum = camera.contains(scene.getWorldBound()) != Camera.FrustumIntersect.Outside && scene.checkCulling(vpCamera);
camera.setPlaneState(planeState);
}
if (inFrustum) {
if (scene instanceof Node)
{
Node node = (Node)scene;
for (Spatial child: node.getChildren()) {
addGeometriesInCamFrustumAndViewPortFromNode(vpCamera, cameras, child, mode, outputGeometryList);
}
}
else if (scene instanceof Geometry) {
if (checkShadowMode(scene.getShadowMode(), mode) && !((Geometry)scene).isGrouped() ) {
outputGeometryList.add((Geometry)scene);
}
}
}
}
}

@ -43,7 +43,9 @@ import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.renderer.Camera;
import com.jme3.renderer.queue.GeometryList;
import com.jme3.renderer.queue.RenderQueue;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.util.TempVars;
import java.io.IOException;
@ -141,15 +143,21 @@ public class SpotLightShadowRenderer extends AbstractShadowRenderer {
}
@Override
protected GeometryList getOccludersToRender(int shadowMapIndex, GeometryList sceneOccluders, GeometryList sceneReceivers, GeometryList shadowMapOccluders) {
ShadowUtil.getGeometriesInCamFrustum(sceneOccluders, shadowCam, shadowMapOccluders);
protected GeometryList getOccludersToRender(int shadowMapIndex, GeometryList shadowMapOccluders) {
for (Spatial scene : viewPort.getScenes()) {
ShadowUtil.getGeometriesInCamFrustum(scene, shadowCam, RenderQueue.ShadowMode.Cast, shadowMapOccluders);
}
return shadowMapOccluders;
}
@Override
GeometryList getReceivers(GeometryList sceneReceivers, GeometryList lightReceivers) {
lightReceivers.clear();
ShadowUtil.getGeometriesInCamFrustum(sceneReceivers, shadowCam, lightReceivers);
Camera[] cameras = new Camera[1];
cameras[0] = shadowCam;
for (Spatial scene : viewPort.getScenes()) {
ShadowUtil.getLitGeometriesInViewPort(scene, viewPort.getCamera(), cameras, RenderQueue.ShadowMode.Receive, lightReceivers);
}
return lightReceivers;
}

@ -317,7 +317,7 @@ public class MaterialDebugAppState extends AbstractAppState {
if (field.getType().isInstance(p)) {
field.setAccessible(true);
p = (Filter.Pass) field.get(filter);
if (p.getPassMaterial() != null) {
if (p!= null && p.getPassMaterial() != null) {
Material mat = reloadMaterial(p.getPassMaterial());
if (mat == null) {
return;

@ -205,11 +205,6 @@ void main(){
vec2 light = computeLighting(normal, viewDir, lightDir.xyz, lightDir.w * spotFallOff , m_Shininess);
#ifdef COLORRAMP
diffuseColor.rgb *= texture2D(m_ColorRamp, vec2(light.x, 0.0)).rgb;
specularColor.rgb *= texture2D(m_ColorRamp, vec2(light.y, 0.0)).rgb;
#endif
// Workaround, since it is not possible to modify varying variables
vec4 SpecularSum2 = vec4(SpecularSum, 1.0);
#ifdef USE_REFLECTION
@ -221,8 +216,14 @@ void main(){
light.y = 1.0;
#endif
gl_FragColor.rgb += DiffuseSum.rgb * lightColor.rgb * diffuseColor.rgb * vec3(light.x) +
SpecularSum2.rgb * specularColor.rgb * vec3(light.y);
#ifdef COLORRAMP
DiffuseSum2.rgb *= texture2D(m_ColorRamp, vec2(light.x, 0.0)).rgb;
SpecularSum2.rgb *= texture2D(m_ColorRamp, vec2(light.y, 0.0)).rgb;
light.xy = vec2(1.0);
#endif
gl_FragColor.rgb += DiffuseSum2.rgb * lightColor.rgb * diffuseColor.rgb * vec3(light.x) +
SpecularSum2.rgb * lightColor.rgb * specularColor.rgb * vec3(light.y);
}
#endif

@ -160,8 +160,14 @@ void main(){
}
#endif
vec2 v = computeLighting(wvNormal, viewDir, lightDir.xyz, lightDir.w * spotFallOff, m_Shininess);
diffuseAccum +=v.x * diffuseColor;
specularAccum += v.y * specularColor;
#ifdef COLORRAMP
diffuseAccum += texture2D(m_ColorRamp, vec2(light.x, 0.0)).rgb * diffuseColor;
specularAccum += texture2D(m_ColorRamp, vec2(light.y, 0.0)).rgb * specularColor;
#else
diffuseAccum += v.x * diffuseColor;
specularAccum += v.y * specularColor;
#endif
}
#endif

@ -298,8 +298,8 @@ public class HttpZipLocator implements AssetLocator {
}
public void load(URL url) throws IOException {
if (!url.getProtocol().equals("http"))
throw new UnsupportedOperationException();
if (!url.getProtocol().equals("http") && !url.getProtocol().equals("https"))
throw new UnsupportedOperationException("HttpZipLocator only supports HTTP(S) URLs");
zipUrl = url;
readEndHeader();

@ -40,7 +40,6 @@ import com.jme3.material.TechniqueDef.ShadowMode;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.shader.Shader;
import com.jme3.shader.VarType;
import com.jme3.texture.Texture;
import com.jme3.texture.Texture.WrapMode;
@ -49,10 +48,8 @@ import com.jme3.texture.image.ColorSpace;
import com.jme3.util.PlaceholderAssets;
import com.jme3.util.blockparser.BlockLanguageParser;
import com.jme3.util.blockparser.Statement;
import java.io.IOException;
import java.io.InputStream;
import java.util.EnumMap;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
@ -60,10 +57,10 @@ import java.util.logging.Logger;
public class J3MLoader implements AssetLoader {
private static final Logger logger = Logger.getLogger(J3MLoader.class.getName());
// private ErrorLogger errors;
// private ErrorLogger errors;
private ShaderNodeLoaderDelegate nodesLoaderDelegate;
boolean isUseNodes = false;
private AssetManager assetManager;
private AssetKey key;
@ -71,15 +68,16 @@ public class J3MLoader implements AssetLoader {
private Material material;
private TechniqueDef technique;
private RenderState renderState;
private EnumMap<Shader.ShaderType, String> shaderLanguage;
private EnumMap<Shader.ShaderType, String> shaderName;
private String vertLanguage;
private String fragLanguage;
private String vertName;
private String fragName;
private static final String whitespacePattern = "\\p{javaWhitespace}+";
public J3MLoader() {
shaderLanguage = new EnumMap<Shader.ShaderType, String>(Shader.ShaderType.class);
shaderName = new EnumMap<Shader.ShaderType, String>(Shader.ShaderType.class);
public J3MLoader(){
}
@ -93,23 +91,20 @@ public class J3MLoader implements AssetLoader {
if (typeAndLang.length != 2) {
throw new IOException("Shader statement syntax incorrect: " + statement);
}
for (Shader.ShaderType shaderType : Shader.ShaderType.values()) {
if (typeAndLang[0].equals(shaderType.toString() + "Shader")) {
readShaderDefinition(shaderType, split[1].trim(), typeAndLang[1]);
}
if (typeAndLang[0].equals("VertexShader")) {
vertName = split[1].trim();
vertLanguage = typeAndLang[1];
} else if (typeAndLang[0].equals("FragmentShader")) {
fragName = split[1].trim();
fragLanguage = typeAndLang[1];
}
}
private void readShaderDefinition(Shader.ShaderType shaderType, String name, String language) {
shaderName.put(shaderType, name);
shaderLanguage.put(shaderType, language);
}
// LightMode <MODE>
private void readLightMode(String statement) throws IOException {
private void readLightMode(String statement) throws IOException{
String[] split = statement.split(whitespacePattern);
if (split.length != 2) {
if (split.length != 2){
throw new IOException("LightMode statement syntax incorrect");
}
LightMode lm = LightMode.valueOf(split[1]);
@ -117,29 +112,29 @@ public class J3MLoader implements AssetLoader {
}
// ShadowMode <MODE>
private void readShadowMode(String statement) throws IOException {
private void readShadowMode(String statement) throws IOException{
String[] split = statement.split(whitespacePattern);
if (split.length != 2) {
if (split.length != 2){
throw new IOException("ShadowMode statement syntax incorrect");
}
ShadowMode sm = ShadowMode.valueOf(split[1]);
technique.setShadowMode(sm);
}
private Object readValue(VarType type, String value) throws IOException {
if (type.isTextureType()) {
private Object readValue(VarType type, String value) throws IOException{
if (type.isTextureType()){
// String texturePath = readString("[\n;(//)(\\})]");
String texturePath = value.trim();
boolean flipY = false;
boolean repeat = false;
if (texturePath.startsWith("Flip Repeat ")) {
if (texturePath.startsWith("Flip Repeat ")){
texturePath = texturePath.substring(12).trim();
flipY = true;
repeat = true;
} else if (texturePath.startsWith("Flip ")) {
}else if (texturePath.startsWith("Flip ")){
texturePath = texturePath.substring(5).trim();
flipY = true;
} else if (texturePath.startsWith("Repeat ")) {
}else if (texturePath.startsWith("Repeat ")){
texturePath = texturePath.substring(7).trim();
repeat = true;
}
@ -161,273 +156,270 @@ public class J3MLoader implements AssetLoader {
Texture tex;
try {
tex = assetManager.loadTexture(texKey);
} catch (AssetNotFoundException ex) {
} catch (AssetNotFoundException ex){
logger.log(Level.WARNING, "Cannot locate {0} for material {1}", new Object[]{texKey, key});
tex = null;
}
if (tex != null) {
if (repeat) {
if (tex != null){
if (repeat){
tex.setWrap(WrapMode.Repeat);
}
} else {
}
}else{
tex = new Texture2D(PlaceholderAssets.getPlaceholderImage(assetManager));
if (repeat) {
if (repeat){
tex.setWrap(WrapMode.Repeat);
}
tex.setKey(texKey);
}
}
return tex;
} else {
}else{
String[] split = value.trim().split(whitespacePattern);
switch (type) {
switch (type){
case Float:
if (split.length != 1) {
if (split.length != 1){
throw new IOException("Float value parameter must have 1 entry: " + value);
}
return Float.parseFloat(split[0]);
return Float.parseFloat(split[0]);
case Vector2:
if (split.length != 2) {
if (split.length != 2){
throw new IOException("Vector2 value parameter must have 2 entries: " + value);
}
return new Vector2f(Float.parseFloat(split[0]),
Float.parseFloat(split[1]));
Float.parseFloat(split[1]));
case Vector3:
if (split.length != 3) {
if (split.length != 3){
throw new IOException("Vector3 value parameter must have 3 entries: " + value);
}
return new Vector3f(Float.parseFloat(split[0]),
Float.parseFloat(split[1]),
Float.parseFloat(split[2]));
Float.parseFloat(split[1]),
Float.parseFloat(split[2]));
case Vector4:
if (split.length != 4) {
if (split.length != 4){
throw new IOException("Vector4 value parameter must have 4 entries: " + value);
}
return new ColorRGBA(Float.parseFloat(split[0]),
Float.parseFloat(split[1]),
Float.parseFloat(split[2]),
Float.parseFloat(split[3]));
Float.parseFloat(split[1]),
Float.parseFloat(split[2]),
Float.parseFloat(split[3]));
case Int:
if (split.length != 1) {
if (split.length != 1){
throw new IOException("Int value parameter must have 1 entry: " + value);
}
return Integer.parseInt(split[0]);
case Boolean:
if (split.length != 1) {
if (split.length != 1){
throw new IOException("Boolean value parameter must have 1 entry: " + value);
}
return Boolean.parseBoolean(split[0]);
default:
throw new UnsupportedOperationException("Unknown type: " + type);
throw new UnsupportedOperationException("Unknown type: "+type);
}
}
}
// <TYPE> <NAME> [ "(" <FFBINDING> ")" ] [ ":" <DEFAULTVAL> ] [-LINEAR]
private void readParam(String statement) throws IOException {
private void readParam(String statement) throws IOException{
String name;
String defaultVal = null;
ColorSpace colorSpace = null;
String[] split = statement.split("-");
if (split.length > 1) {
if (split[1].equalsIgnoreCase("LINEAR")) {
if(split.length>1){
if(split[1].equalsIgnoreCase("LINEAR")){
colorSpace = ColorSpace.Linear;
}
statement = split[0].trim();
}
split = statement.split(":");
// Parse default val
if (split.length == 1) {
if (split.length == 1){
// Doesn't contain default value
} else {
if (split.length != 2) {
}else{
if (split.length != 2){
throw new IOException("Parameter statement syntax incorrect");
}
statement = split[0].trim();
defaultVal = split[1].trim();
defaultVal = split[1].trim();
}
// Parse ffbinding
int startParen = statement.indexOf("(");
if (startParen != -1) {
if (startParen != -1){
// get content inside parentheses
int endParen = statement.indexOf(")", startParen);
String bindingStr = statement.substring(startParen + 1, endParen).trim();
String bindingStr = statement.substring(startParen+1, endParen).trim();
// don't care about bindingStr
statement = statement.substring(0, startParen);
}
// Parse type + name
split = statement.split(whitespacePattern);
if (split.length != 2) {
if (split.length != 2){
throw new IOException("Parameter statement syntax incorrect");
}
VarType type;
if (split[0].equals("Color")) {
if (split[0].equals("Color")){
type = VarType.Vector4;
} else {
}else{
type = VarType.valueOf(split[0]);
}
name = split[1];
Object defaultValObj = null;
if (defaultVal != null) {
if (defaultVal != null){
defaultValObj = readValue(type, defaultVal);
}
if (type.isTextureType()) {
materialDef.addMaterialParamTexture(type, name, colorSpace);
} else {
if(type.isTextureType()){
materialDef.addMaterialParamTexture(type, name, colorSpace);
}else{
materialDef.addMaterialParam(type, name, defaultValObj);
}
}
private void readValueParam(String statement) throws IOException {
private void readValueParam(String statement) throws IOException{
// Use limit=1 incase filename contains colons
String[] split = statement.split(":", 2);
if (split.length != 2) {
if (split.length != 2){
throw new IOException("Value parameter statement syntax incorrect");
}
String name = split[0].trim();
// parse value
MatParam p = material.getMaterialDef().getMaterialParam(name);
if (p == null) {
throw new IOException("The material parameter: " + name + " is undefined.");
if (p == null){
throw new IOException("The material parameter: "+name+" is undefined.");
}
Object valueObj = readValue(p.getVarType(), split[1]);
if (p.getVarType().isTextureType()) {
if (p.getVarType().isTextureType()){
material.setTextureParam(name, p.getVarType(), (Texture) valueObj);
} else {
}else{
material.setParam(name, p.getVarType(), valueObj);
}
}
private void readMaterialParams(List<Statement> paramsList) throws IOException {
for (Statement statement : paramsList) {
private void readMaterialParams(List<Statement> paramsList) throws IOException{
for (Statement statement : paramsList){
readParam(statement.getLine());
}
}
private void readExtendingMaterialParams(List<Statement> paramsList) throws IOException {
for (Statement statement : paramsList) {
private void readExtendingMaterialParams(List<Statement> paramsList) throws IOException{
for (Statement statement : paramsList){
readValueParam(statement.getLine());
}
}
private void readWorldParams(List<Statement> worldParams) throws IOException {
for (Statement statement : worldParams) {
private void readWorldParams(List<Statement> worldParams) throws IOException{
for (Statement statement : worldParams){
technique.addWorldParam(statement.getLine());
}
}
private boolean parseBoolean(String word) {
private boolean parseBoolean(String word){
return word != null && word.equals("On");
}
private void readRenderStateStatement(Statement statement) throws IOException {
private void readRenderStateStatement(Statement statement) throws IOException{
String[] split = statement.getLine().split(whitespacePattern);
if (split[0].equals("Wireframe")) {
if (split[0].equals("Wireframe")){
renderState.setWireframe(parseBoolean(split[1]));
} else if (split[0].equals("FaceCull")) {
}else if (split[0].equals("FaceCull")){
renderState.setFaceCullMode(FaceCullMode.valueOf(split[1]));
} else if (split[0].equals("DepthWrite")) {
}else if (split[0].equals("DepthWrite")){
renderState.setDepthWrite(parseBoolean(split[1]));
} else if (split[0].equals("DepthTest")) {
}else if (split[0].equals("DepthTest")){
renderState.setDepthTest(parseBoolean(split[1]));
} else if (split[0].equals("Blend")) {
}else if (split[0].equals("Blend")){
renderState.setBlendMode(BlendMode.valueOf(split[1]));
} else if (split[0].equals("AlphaTestFalloff")) {
}else if (split[0].equals("AlphaTestFalloff")){
renderState.setAlphaTest(true);
renderState.setAlphaFallOff(Float.parseFloat(split[1]));
} else if (split[0].equals("PolyOffset")) {
}else if (split[0].equals("PolyOffset")){
float factor = Float.parseFloat(split[1]);
float units = Float.parseFloat(split[2]);
renderState.setPolyOffset(factor, units);
} else if (split[0].equals("ColorWrite")) {
}else if (split[0].equals("ColorWrite")){
renderState.setColorWrite(parseBoolean(split[1]));
} else if (split[0].equals("PointSprite")) {
}else if (split[0].equals("PointSprite")){
renderState.setPointSprite(parseBoolean(split[1]));
} else if (split[0].equals("DepthFunc")) {
}else if (split[0].equals("DepthFunc")){
renderState.setDepthFunc(RenderState.TestFunction.valueOf(split[1]));
} else if (split[0].equals("AlphaFunc")) {
}else if (split[0].equals("AlphaFunc")){
renderState.setAlphaFunc(RenderState.TestFunction.valueOf(split[1]));
} else {
throw new MatParseException(null, split[0], statement);
}
}
private void readAdditionalRenderState(List<Statement> renderStates) throws IOException {
private void readAdditionalRenderState(List<Statement> renderStates) throws IOException{
renderState = material.getAdditionalRenderState();
for (Statement statement : renderStates) {
for (Statement statement : renderStates){
readRenderStateStatement(statement);
}
renderState = null;
}
private void readRenderState(List<Statement> renderStates) throws IOException {
private void readRenderState(List<Statement> renderStates) throws IOException{
renderState = new RenderState();
for (Statement statement : renderStates) {
for (Statement statement : renderStates){
readRenderStateStatement(statement);
}
technique.setRenderState(renderState);
renderState = null;
}
private void readForcedRenderState(List<Statement> renderStates) throws IOException {
private void readForcedRenderState(List<Statement> renderStates) throws IOException{
renderState = new RenderState();
for (Statement statement : renderStates) {
for (Statement statement : renderStates){
readRenderStateStatement(statement);
}
technique.setForcedRenderState(renderState);
renderState = null;
}
// <DEFINENAME> [ ":" <PARAMNAME> ]
private void readDefine(String statement) throws IOException {
private void readDefine(String statement) throws IOException{
String[] split = statement.split(":");
if (split.length == 1) {
if (split.length == 1){
// add preset define
technique.addShaderPresetDefine(split[0].trim(), VarType.Boolean, true);
} else if (split.length == 2) {
}else if (split.length == 2){
technique.addShaderParamDefine(split[1].trim(), split[0].trim());
} else {
}else{
throw new IOException("Define syntax incorrect");
}
}
private void readDefines(List<Statement> defineList) throws IOException {
for (Statement statement : defineList) {
private void readDefines(List<Statement> defineList) throws IOException{
for (Statement statement : defineList){
readDefine(statement.getLine());
}
}
private void readTechniqueStatement(Statement statement) throws IOException {
String[] split = statement.getLine().split("[ \\{]");
private void readTechniqueStatement(Statement statement) throws IOException{
String[] split = statement.getLine().split("[ \\{]");
if (split[0].equals("VertexShader") ||
split[0].equals("FragmentShader") ||
split[0].equals("GeometryShader") ||
split[0].equals("TesselationControlShader") ||
split[0].equals("TesselationEvaluationShader")) {
split[0].equals("FragmentShader")){
readShaderStatement(statement.getLine());
} else if (split[0].equals("LightMode")) {
}else if (split[0].equals("LightMode")){
readLightMode(statement.getLine());
} else if (split[0].equals("ShadowMode")) {
}else if (split[0].equals("ShadowMode")){
readShadowMode(statement.getLine());
} else if (split[0].equals("WorldParameters")) {
}else if (split[0].equals("WorldParameters")){
readWorldParams(statement.getContents());
} else if (split[0].equals("RenderState")) {
}else if (split[0].equals("RenderState")){
readRenderState(statement.getContents());
} else if (split[0].equals("ForcedRenderState")) {
}else if (split[0].equals("ForcedRenderState")){
readForcedRenderState(statement.getContents());
} else if (split[0].equals("Defines")) {
readDefines(statement.getContents());
}else if (split[0].equals("Defines")){
readDefines(statement.getContents());
} else if (split[0].equals("ShaderNodesDefinitions")) {
initNodesLoader();
if (isUseNodes) {
@ -440,23 +432,23 @@ public class J3MLoader implements AssetLoader {
}
} else if (split[0].equals("FragmentShaderNodes")) {
initNodesLoader();
if (isUseNodes) {
if (isUseNodes) {
nodesLoaderDelegate.readFragmentShaderNodes(statement.getContents());
}
} else {
throw new MatParseException(null, split[0], statement);
}
}
private void readTransparentStatement(String statement) throws IOException {
private void readTransparentStatement(String statement) throws IOException{
String[] split = statement.split(whitespacePattern);
if (split.length != 2) {
if (split.length != 2){
throw new IOException("Transparent statement syntax incorrect");
}
material.setTransparent(parseBoolean(split[1]));
}
private void readTechnique(Statement techStat) throws IOException {
private void readTechnique(Statement techStat) throws IOException{
isUseNodes = false;
String[] split = techStat.getLine().split(whitespacePattern);
if (split.length == 1) {
@ -467,62 +459,64 @@ public class J3MLoader implements AssetLoader {
} else {
throw new IOException("Technique statement syntax incorrect");
}
for (Statement statement : techStat.getContents()) {
for (Statement statement : techStat.getContents()){
readTechniqueStatement(statement);
}
if (isUseNodes) {
if(isUseNodes){
nodesLoaderDelegate.computeConditions();
//used for caching later, the shader here is not a file.
technique.setShaderFile(technique.hashCode() + "", technique.hashCode() + "", "GLSL100", "GLSL100");
}
if (shaderName.containsKey(Shader.ShaderType.Vertex) && shaderName.containsKey(Shader.ShaderType.Fragment)) {
technique.setShaderFile(shaderName, shaderLanguage);
if (vertName != null && fragName != null){
technique.setShaderFile(vertName, fragName, vertLanguage, fragLanguage);
}
materialDef.addTechniqueDef(technique);
technique = null;
shaderLanguage.clear();
shaderName.clear();
vertName = null;
fragName = null;
vertLanguage = null;
fragLanguage = null;
}
private void loadFromRoot(List<Statement> roots) throws IOException {
if (roots.size() == 2) {
private void loadFromRoot(List<Statement> roots) throws IOException{
if (roots.size() == 2){
Statement exception = roots.get(0);
String line = exception.getLine();
if (line.startsWith("Exception")) {
if (line.startsWith("Exception")){
throw new AssetLoadException(line.substring("Exception ".length()));
} else {
}else{
throw new IOException("In multiroot material, expected first statement to be 'Exception'");
}
} else if (roots.size() != 1) {
}else if (roots.size() != 1){
throw new IOException("Too many roots in J3M/J3MD file");
}
boolean extending = false;
Statement materialStat = roots.get(0);
String materialName = materialStat.getLine();
if (materialName.startsWith("MaterialDef")) {
if (materialName.startsWith("MaterialDef")){
materialName = materialName.substring("MaterialDef ".length()).trim();
extending = false;
} else if (materialName.startsWith("Material")) {
}else if (materialName.startsWith("Material")){
materialName = materialName.substring("Material ".length()).trim();
extending = true;
} else {
}else{
throw new IOException("Specified file is not a Material file");
}
String[] split = materialName.split(":", 2);
if (materialName.equals("")) {
throw new MatParseException("Material name cannot be empty", materialStat);
if (materialName.equals("")){
throw new MatParseException("Material name cannot be empty", materialStat);
}
if (split.length == 2) {
if (!extending) {
throw new MatParseException("Must use 'Material' when extending.", materialStat);
if (split.length == 2){
if (!extending){
throw new MatParseException("Must use 'Material' when extending.", materialStat);
}
String extendedMat = split[1].trim();
@ -535,65 +529,65 @@ public class J3MLoader implements AssetLoader {
material = new Material(def);
material.setKey(key);
// material.setAssetName(fileName);
} else if (split.length == 1) {
if (extending) {
throw new MatParseException("Expected ':', got '{'", materialStat);
}else if (split.length == 1){
if (extending){
throw new MatParseException("Expected ':', got '{'", materialStat);
}
materialDef = new MaterialDef(assetManager, materialName);
// NOTE: pass file name for defs so they can be loaded later
materialDef.setAssetName(key.getName());
} else {
throw new MatParseException("Cannot use colon in material name/path", materialStat);
}else{
throw new MatParseException("Cannot use colon in material name/path", materialStat);
}
for (Statement statement : materialStat.getContents()) {
for (Statement statement : materialStat.getContents()){
split = statement.getLine().split("[ \\{]");
String statType = split[0];
if (extending) {
if (statType.equals("MaterialParameters")) {
if (extending){
if (statType.equals("MaterialParameters")){
readExtendingMaterialParams(statement.getContents());
} else if (statType.equals("AdditionalRenderState")) {
}else if (statType.equals("AdditionalRenderState")){
readAdditionalRenderState(statement.getContents());
} else if (statType.equals("Transparent")) {
}else if (statType.equals("Transparent")){
readTransparentStatement(statement.getLine());
}
} else {
if (statType.equals("Technique")) {
}else{
if (statType.equals("Technique")){
readTechnique(statement);
} else if (statType.equals("MaterialParameters")) {
}else if (statType.equals("MaterialParameters")){
readMaterialParams(statement.getContents());
} else {
throw new MatParseException("Expected material statement, got '" + statType + "'", statement);
}else{
throw new MatParseException("Expected material statement, got '"+statType+"'", statement);
}
}
}
}
public Object load(AssetInfo info) throws IOException {
public Object load(AssetInfo info) throws IOException {
this.assetManager = info.getManager();
InputStream in = info.openStream();
InputStream in = info.openStream();
try {
key = info.getKey();
key = info.getKey();
loadFromRoot(BlockLanguageParser.parse(in));
} finally {
if (in != null) {
if (in != null){
in.close();
}
}
if (material != null) {
if (!(info.getKey() instanceof MaterialKey)) {
if (material != null){
if (!(info.getKey() instanceof MaterialKey)){
throw new IOException("Material instances must be loaded via MaterialKey");
}
// material implementation
return material;
} else {
}else{
// material definition
return materialDef;
}
}
public MaterialDef loadMaterialDef(List<Statement> roots, AssetManager manager, AssetKey key) throws IOException {
this.key = key;
this.assetManager = manager;
@ -603,11 +597,11 @@ public class J3MLoader implements AssetLoader {
protected void initNodesLoader() {
if (!isUseNodes) {
isUseNodes = shaderName.get(Shader.ShaderType.Vertex) == null && shaderName.get(Shader.ShaderType.Fragment) == null;
if (isUseNodes) {
if (nodesLoaderDelegate == null) {
isUseNodes = fragName == null && vertName == null;
if (isUseNodes) {
if(nodesLoaderDelegate == null){
nodesLoaderDelegate = new ShaderNodeLoaderDelegate();
} else {
}else{
nodesLoaderDelegate.clear();
}
nodesLoaderDelegate.setTechniqueDef(technique);
@ -615,6 +609,6 @@ public class J3MLoader implements AssetLoader {
nodesLoaderDelegate.setAssetManager(assetManager);
}
}
}
}
}

@ -0,0 +1,573 @@
/*
* Copyright (c) 2009-2015 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.jme3.renderer.ios;
import com.jme3.renderer.RendererException;
import com.jme3.renderer.opengl.GL;
import com.jme3.renderer.opengl.GLExt;
import java.nio.Buffer;
import java.nio.BufferOverflowException;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;
/**
* Implements OpenGL ES 2.0 for iOS.
*
* @author Kirill Vainer
*/
public class IosGL implements GL, GLExt {
private final int[] temp_array = new int[16];
private static int getLimitBytes(ByteBuffer buffer) {
checkLimit(buffer);
return buffer.limit();
}
private static int getLimitBytes(ShortBuffer buffer) {
checkLimit(buffer);
return buffer.limit() * 2;
}
private static int getLimitBytes(IntBuffer buffer) {
checkLimit(buffer);
return buffer.limit() * 4;
}
private static int getLimitBytes(FloatBuffer buffer) {
checkLimit(buffer);
return buffer.limit() * 4;
}
private static int getLimitCount(Buffer buffer, int elementSize) {
checkLimit(buffer);
return buffer.limit() / elementSize;
}
private int toArray(IntBuffer buffer) {
int remain = buffer.remaining();
if (buffer.remaining() > 16) {
throw new ArrayIndexOutOfBoundsException();
}
int pos = buffer.position();
buffer.get(temp_array, 0, remain);
buffer.position(pos);
return remain;
}
private void fromArray(int n, int[] array, IntBuffer buffer) {
if (buffer.remaining() < n) {
throw new BufferOverflowException();
}
buffer.put(array, 0, n);
}
private static void checkLimit(Buffer buffer) {
if (buffer == null) {
return;
}
if (buffer.limit() == 0) {
throw new RendererException("Attempting to upload empty buffer (limit = 0), that's an error");
}
if (buffer.remaining() == 0) {
throw new RendererException("Attempting to upload empty buffer (remaining = 0), that's an error");
}
}
public void glActiveTexture(int texture) {
JmeIosGLES.glActiveTexture(texture);
}
public void glAttachShader(int program, int shader) {
JmeIosGLES.glAttachShader(program, shader);
}
public void glBindBuffer(int target, int buffer) {
JmeIosGLES.glBindBuffer(target, buffer);
}
public void glBindTexture(int target, int texture) {
JmeIosGLES.glBindTexture(target, texture);
}
public void glBlendFunc(int sfactor, int dfactor) {
JmeIosGLES.glBlendFunc(sfactor, dfactor);
}
public void glBufferData(int target, FloatBuffer data, int usage) {
JmeIosGLES.glBufferData(target, getLimitBytes(data), data, usage);
}
public void glBufferData(int target, ShortBuffer data, int usage) {
JmeIosGLES.glBufferData(target, getLimitBytes(data), data, usage);
}
public void glBufferData(int target, ByteBuffer data, int usage) {
JmeIosGLES.glBufferData(target, getLimitBytes(data), data, usage);
}
public void glBufferData(int target, long data_size, int usage) {
JmeIosGLES.glBufferData(target, (int) data_size, null, usage);
}
public void glBufferSubData(int target, long offset, FloatBuffer data) {
JmeIosGLES.glBufferSubData(target, (int) offset, getLimitBytes(data), data);
}
public void glBufferSubData(int target, long offset, ShortBuffer data) {
JmeIosGLES.glBufferSubData(target, (int) offset, getLimitBytes(data), data);
}
public void glBufferSubData(int target, long offset, ByteBuffer data) {
JmeIosGLES.glBufferSubData(target, (int) offset, getLimitBytes(data), data);
}
public void glGetBufferSubData(int target, long offset, ByteBuffer data) {
throw new UnsupportedOperationException("OpenGL ES 2 does not support glGetBufferSubData");
}
public void glClear(int mask) {
JmeIosGLES.glClear(mask);
}
public void glClearColor(float red, float green, float blue, float alpha) {
JmeIosGLES.glClearColor(red, green, blue, alpha);
}
public void glColorMask(boolean red, boolean green, boolean blue, boolean alpha) {
JmeIosGLES.glColorMask(red, green, blue, alpha);
}
public void glCompileShader(int shader) {
JmeIosGLES.glCompileShader(shader);
}
public void glCompressedTexImage2D(int target, int level, int internalformat, int width, int height, int border, ByteBuffer data) {
JmeIosGLES.glCompressedTexImage2D(target, level, internalformat, width, height, 0, getLimitBytes(data), data);
}
public void glCompressedTexSubImage2D(int target, int level, int xoffset, int yoffset, int width, int height, int format, ByteBuffer data) {
JmeIosGLES.glCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, getLimitBytes(data), data);
}
public int glCreateProgram() {
return JmeIosGLES.glCreateProgram();
}
public int glCreateShader(int shaderType) {
return JmeIosGLES.glCreateShader(shaderType);
}
public void glCullFace(int mode) {
JmeIosGLES.glCullFace(mode);
}
public void glDeleteBuffers(IntBuffer buffers) {
checkLimit(buffers);
int n = toArray(buffers);
JmeIosGLES.glDeleteBuffers(n, temp_array, 0);
}
public void glDeleteProgram(int program) {
JmeIosGLES.glDeleteProgram(program);
}
public void glDeleteShader(int shader) {
JmeIosGLES.glDeleteShader(shader);
}
public void glDeleteTextures(IntBuffer textures) {
checkLimit(textures);
int n = toArray(textures);
JmeIosGLES.glDeleteTextures(n, temp_array, 0);
}
public void glDepthFunc(int func) {
JmeIosGLES.glDepthFunc(func);
}
public void glDepthMask(boolean flag) {
JmeIosGLES.glDepthMask(flag);
}
public void glDepthRange(double nearVal, double farVal) {
JmeIosGLES.glDepthRangef((float)nearVal, (float)farVal);
}
public void glDetachShader(int program, int shader) {
JmeIosGLES.glDetachShader(program, shader);
}
public void glDisable(int cap) {
JmeIosGLES.glDisable(cap);
}
public void glDisableVertexAttribArray(int index) {
JmeIosGLES.glDisableVertexAttribArray(index);
}
public void glDrawArrays(int mode, int first, int count) {
JmeIosGLES.glDrawArrays(mode, first, count);
}
public void glDrawRangeElements(int mode, int start, int end, int count, int type, long indices) {
JmeIosGLES.glDrawElementsIndex(mode, count, type, (int)indices);
}
public void glEnable(int cap) {
JmeIosGLES.glEnable(cap);
}
public void glEnableVertexAttribArray(int index) {
JmeIosGLES.glEnableVertexAttribArray(index);
}
public void glGenBuffers(IntBuffer buffers) {
checkLimit(buffers);
JmeIosGLES.glGenBuffers(buffers.remaining(), temp_array, 0);
fromArray(buffers.remaining(), temp_array, buffers);
}
public void glGenTextures(IntBuffer textures) {
checkLimit(textures);
JmeIosGLES.glGenTextures(textures.remaining(), temp_array, 0);
fromArray(textures.remaining(), temp_array, textures);
}
public int glGetAttribLocation(int program, String name) {
return JmeIosGLES.glGetAttribLocation(program, name);
}
public void glGetBoolean(int pname, ByteBuffer params) {
// TODO: fix me!!!
// JmeIosGLES.glGetBoolean(pname, params);
throw new UnsupportedOperationException("Today is not a good day for this");
}
public int glGetError() {
return JmeIosGLES.glGetError();
}
public void glGetInteger(int pname, IntBuffer params) {
checkLimit(params);
JmeIosGLES.glGetIntegerv(pname, temp_array, 0);
fromArray(params.remaining(), temp_array, params);
}
public void glGetProgram(int program, int pname, IntBuffer params) {
checkLimit(params);
JmeIosGLES.glGetProgramiv(program, pname, temp_array, 0);
fromArray(params.remaining(), temp_array, params);
}
public String glGetProgramInfoLog(int program, int maxLength) {
return JmeIosGLES.glGetProgramInfoLog(program);
}
public void glGetShader(int shader, int pname, IntBuffer params) {
checkLimit(params);
JmeIosGLES.glGetShaderiv(shader, pname, temp_array, 0);
fromArray(params.remaining(), temp_array, params);
}
public String glGetShaderInfoLog(int shader, int maxLength) {
return JmeIosGLES.glGetShaderInfoLog(shader);
}
public String glGetString(int name) {
return JmeIosGLES.glGetString(name);
}
public int glGetUniformLocation(int program, String name) {
return JmeIosGLES.glGetUniformLocation(program, name);
}
public boolean glIsEnabled(int cap) {
// TODO: fix me!!!
if (cap == GLExt.GL_MULTISAMPLE_ARB) {
return true;
} else {
throw new UnsupportedOperationException();
}
}
public void glLineWidth(float width) {
JmeIosGLES.glLineWidth(width);
}
public void glLinkProgram(int program) {
JmeIosGLES.glLinkProgram(program);
}
public void glPixelStorei(int pname, int param) {
JmeIosGLES.glPixelStorei(pname, param);
}
public void glPolygonOffset(float factor, float units) {
JmeIosGLES.glPolygonOffset(factor, units);
}
public void glReadPixels(int x, int y, int width, int height, int format, int type, ByteBuffer data) {
JmeIosGLES.glReadPixels(x, y, width, height, format, type, data);
}
public void glScissor(int x, int y, int width, int height) {
JmeIosGLES.glScissor(x, y, width, height);
}
public void glShaderSource(int shader, String[] string, IntBuffer length) {
if (string.length != 1) {
throw new UnsupportedOperationException("Today is not a good day");
}
JmeIosGLES.glShaderSource(shader, string[0]);
}
public void glStencilFuncSeparate(int face, int func, int ref, int mask) {
// TODO: fix me!!!
// JmeIosGLES.glStencilFuncSeparate(face, func, ref, mask);
}
public void glStencilOpSeparate(int face, int sfail, int dpfail, int dppass) {
// TODO: fix me!!!
// JmeIosGLES.glStencilOpSeparate(face, sfail, dpfail, dppass);
}
public void glTexImage2D(int target, int level, int internalFormat, int width, int height, int border, int format, int type, ByteBuffer data) {
JmeIosGLES.glTexImage2D(target, level, format, width, height, 0, format, type, data);
}
public void glTexParameterf(int target, int pname, float param) {
// TODO: fix me!!!
// JmeIosGLES.glTexParameterf(target, pname, param);
}
public void glTexParameteri(int target, int pname, int param) {
JmeIosGLES.glTexParameteri(target, pname, param);
}
public void glTexSubImage2D(int target, int level, int xoffset, int yoffset, int width, int height, int format, int type, ByteBuffer data) {
JmeIosGLES.glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, data);
}
public void glUniform1(int location, FloatBuffer value) {
JmeIosGLES.glUniform1fv(location, getLimitCount(value, 1), value);
}
public void glUniform1(int location, IntBuffer value) {
JmeIosGLES.glUniform1iv(location, getLimitCount(value, 1), value);
}
public void glUniform1f(int location, float v0) {
JmeIosGLES.glUniform1f(location, v0);
}
public void glUniform1i(int location, int v0) {
JmeIosGLES.glUniform1i(location, v0);
}
public void glUniform2(int location, IntBuffer value) {
// TODO: fix me!!!
// JmeIosGLES.glUniform2iv(location, getLimitCount(value, 2), value);
throw new UnsupportedOperationException();
}
public void glUniform2(int location, FloatBuffer value) {
JmeIosGLES.glUniform2fv(location, getLimitCount(value, 2), value);
}
public void glUniform2f(int location, float v0, float v1) {
JmeIosGLES.glUniform2f(location, v0, v1);
}
public void glUniform3(int location, IntBuffer value) {
// TODO: fix me!!!
// JmeIosGLES.glUniform3iv(location, getLimitCount(value, 3), value);
throw new UnsupportedOperationException();
}
public void glUniform3(int location, FloatBuffer value) {
JmeIosGLES.glUniform3fv(location, getLimitCount(value, 3), value);
}
public void glUniform3f(int location, float v0, float v1, float v2) {
JmeIosGLES.glUniform3f(location, v0, v1, v2);
}
public void glUniform4(int location, FloatBuffer value) {
JmeIosGLES.glUniform4fv(location, getLimitCount(value, 4), value);
}
public void glUniform4(int location, IntBuffer value) {
// TODO: fix me!!!
// JmeIosGLES.glUniform4iv(location, getLimitCount(value, 4), value);
throw new UnsupportedOperationException();
}
public void glUniform4f(int location, float v0, float v1, float v2, float v3) {
JmeIosGLES.glUniform4f(location, v0, v1, v2, v3);
}
public void glUniformMatrix3(int location, boolean transpose, FloatBuffer value) {
JmeIosGLES.glUniformMatrix3fv(location, getLimitCount(value, 3 * 3), transpose, value);
}
public void glUniformMatrix4(int location, boolean transpose, FloatBuffer value) {
JmeIosGLES.glUniformMatrix4fv(location, getLimitCount(value, 4 * 4), transpose, value);
}
public void glUseProgram(int program) {
JmeIosGLES.glUseProgram(program);
}
public void glVertexAttribPointer(int index, int size, int type, boolean normalized, int stride, long pointer) {
JmeIosGLES.glVertexAttribPointer2(index, size, type, normalized, stride, (int)pointer);
}
public void glViewport(int x, int y, int width, int height) {
JmeIosGLES.glViewport(x, y, width, height);
}
public void glBlitFramebufferEXT(int srcX0, int srcY0, int srcX1, int srcY1, int dstX0, int dstY0, int dstX1, int dstY1, int mask, int filter) {
throw new UnsupportedOperationException("FBO blit not available on iOS");
}
public void glBufferData(int target, IntBuffer data, int usage) {
JmeIosGLES.glBufferData(target, getLimitBytes(data), data, usage);
}
public void glBufferSubData(int target, long offset, IntBuffer data) {
JmeIosGLES.glBufferSubData(target, (int)offset, getLimitBytes(data), data);
}
public void glDrawArraysInstancedARB(int mode, int first, int count, int primcount) {
throw new UnsupportedOperationException("Instancing not available on iOS");
}
public void glDrawBuffers(IntBuffer bufs) {
throw new UnsupportedOperationException("MRT not available on iOS");
}
public void glDrawElementsInstancedARB(int mode, int indices_count, int type, long indices_buffer_offset, int primcount) {
throw new UnsupportedOperationException("Instancing not available on iOS");
}
public void glGetMultisample(int pname, int index, FloatBuffer val) {
throw new UnsupportedOperationException("Multisample renderbuffers not available on iOS");
}
public void glRenderbufferStorageMultisampleEXT(int target, int samples, int internalformat, int width, int height) {
throw new UnsupportedOperationException("Multisample renderbuffers not available on iOS");
}
public void glTexImage2DMultisample(int target, int samples, int internalformat, int width, int height, boolean fixedsamplelocations) {
throw new UnsupportedOperationException("Multisample textures not available on iOS");
}
public void glVertexAttribDivisorARB(int index, int divisor) {
throw new UnsupportedOperationException("Instancing not available on iOS");
}
public void glBindFramebufferEXT(int param1, int param2) {
JmeIosGLES.glBindFramebuffer(param1, param2);
}
public void glBindRenderbufferEXT(int param1, int param2) {
JmeIosGLES.glBindRenderbuffer(param1, param2);
}
public int glCheckFramebufferStatusEXT(int param1) {
return JmeIosGLES.glCheckFramebufferStatus(param1);
}
public void glDeleteFramebuffersEXT(IntBuffer param1) {
checkLimit(param1);
int n = toArray(param1);
JmeIosGLES.glDeleteFramebuffers(n, temp_array, 0);
}
public void glDeleteRenderbuffersEXT(IntBuffer param1) {
checkLimit(param1);
int n = toArray(param1);
JmeIosGLES.glDeleteRenderbuffers(n, temp_array, 0);
}
public void glFramebufferRenderbufferEXT(int param1, int param2, int param3, int param4) {
JmeIosGLES.glFramebufferRenderbuffer(param1, param2, param3, param4);
}
public void glFramebufferTexture2DEXT(int param1, int param2, int param3, int param4, int param5) {
JmeIosGLES.glFramebufferTexture2D(param1, param2, param3, param4, param5);
}
public void glGenFramebuffersEXT(IntBuffer param1) {
checkLimit(param1);
JmeIosGLES.glGenFramebuffers(param1.remaining(), temp_array, 0);
fromArray(param1.remaining(), temp_array, param1);
}
public void glGenRenderbuffersEXT(IntBuffer param1) {
checkLimit(param1);
JmeIosGLES.glGenRenderbuffers(param1.remaining(), temp_array, 0);
fromArray(param1.remaining(), temp_array, param1);
}
public void glGenerateMipmapEXT(int param1) {
JmeIosGLES.glGenerateMipmap(param1);
}
public void glRenderbufferStorageEXT(int param1, int param2, int param3, int param4) {
JmeIosGLES.glRenderbufferStorage(param1, param2, param3, param4);
}
@Override
public void glReadPixels(int x, int y, int width, int height, int format, int type, long offset) {
// TODO: no offset???
JmeIosGLES.glReadPixels(x, y, width, height, format, type, null);
}
@Override
public int glClientWaitSync(Object sync, int flags, long timeout) {
throw new UnsupportedOperationException("OpenGL ES 2 does not support sync fences");
}
@Override
public void glDeleteSync(Object sync) {
throw new UnsupportedOperationException("OpenGL ES 2 does not support sync fences");
}
@Override
public Object glFenceSync(int condition, int flags) {
throw new UnsupportedOperationException("OpenGL ES 2 does not support sync fences");
}
}

@ -32,12 +32,15 @@
package com.jme3.system.ios;
import com.jme3.input.*;
import com.jme3.input.controls.SoftTextDialogInputListener;
import com.jme3.input.dummy.DummyKeyInput;
import com.jme3.input.dummy.DummyMouseInput;
import com.jme3.renderer.ios.IGLESShaderRenderer;
import com.jme3.system.*;
import com.jme3.input.ios.IosInputHandler;
import com.jme3.renderer.ios.IosGL;
import com.jme3.renderer.opengl.GL;
import com.jme3.renderer.opengl.GLDebugES;
import com.jme3.renderer.opengl.GLExt;
import com.jme3.renderer.opengl.GLRenderer;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level;
import java.util.logging.Logger;
@ -54,7 +57,7 @@ public class IGLESContext implements JmeContext {
/*
* >= OpenGL ES 2.0 (iOS)
*/
protected IGLESShaderRenderer renderer;
protected GLRenderer renderer;
protected Timer timer;
protected SystemListener listener;
protected IosInputHandler input;
@ -150,7 +153,18 @@ public class IGLESContext implements JmeContext {
@Override
public void create(boolean waitFor) {
logger.log(Level.FINE, "IGLESContext create");
renderer = new IGLESShaderRenderer();
GL gl = new IosGL();
GLExt glext = (GLExt) gl;
// if (settings.getBoolean("GraphicsDebug")) {
gl = new GLDebugES(gl, glext);
glext = (GLExt) gl;
// }
renderer = new GLRenderer(gl, glext);
renderer.initialize();
input = new IosInputHandler();
timer = new NanoTimer();

@ -391,7 +391,12 @@ public class PhysicsSpace {
if (obj instanceof PhysicsControl) {
((PhysicsControl) obj).setPhysicsSpace(this);
} else if (obj instanceof Spatial) {
add(((Spatial) obj).getControl(PhysicsControl.class));
Spatial node = (Spatial) obj;
for (int i = 0; i < node.getNumControls(); i++) {
if (node.getControl(i) instanceof PhysicsControl) {
add(((PhysicsControl) node.getControl(i)));
}
}
} else if (obj instanceof PhysicsCollisionObject) {
addCollisionObject((PhysicsCollisionObject) obj);
} else if (obj instanceof PhysicsJoint) {
@ -423,7 +428,12 @@ public class PhysicsSpace {
if (obj instanceof PhysicsControl) {
((PhysicsControl) obj).setPhysicsSpace(null);
} else if (obj instanceof Spatial) {
remove(((Spatial) obj).getControl(PhysicsControl.class));
Spatial node = (Spatial) obj;
for (int i = 0; i < node.getNumControls(); i++) {
if (node.getControl(i) instanceof PhysicsControl) {
remove(((PhysicsControl) node.getControl(i)));
}
}
} else if (obj instanceof PhysicsCollisionObject) {
removeCollisionObject((PhysicsCollisionObject) obj);
} else if (obj instanceof PhysicsJoint) {

@ -93,7 +93,7 @@ public class SavableSerializer extends Serializer {
@Override
public int read(byte[] b, int off, int len){
int toRead = len > input.remaining() ? input.remaining() : len;
input.get(b, off, len);
input.get(b, off, toRead);
return toRead;
}

@ -336,8 +336,7 @@ public class MaterialLoader implements AssetLoader {
mat.setName(matName);
if (blend){
RenderState rs = mat.getAdditionalRenderState();
rs.setAlphaTest(true);
rs.setAlphaFallOff(0.01f);
mat.setFloat("AlphaDiscardThreshold", 0.01f);
rs.setBlendMode(RenderState.BlendMode.Alpha);
if (twoSide){
@ -422,13 +421,18 @@ public class MaterialLoader implements AssetLoader {
noLight = false;
Arrays.fill(textures, null);
ambient = null;
diffuse = null;
specular = null;
emissive = null;
shinines = 0f;
vcolor = false;
blend = false;
texUnit = 0;
separateTexCoord = false;
twoSide = false;
matName = null;
texName = null;
return mat;
}
@ -464,7 +468,7 @@ public class MaterialLoader implements AssetLoader {
}
readMaterial(statement);
Material mat = compileMaterial();
list.put(matName, mat);
list.put(mat.getName(), mat);
}
}

Loading…
Cancel
Save