* Fixed issue 590 (Uniform.setVector4Length() re-allocating buffer even when not needed)

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@10544 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
3.0
Sha..om 12 years ago
parent c972861331
commit 3195940994
  1. 700
      engine/src/core/com/jme3/shader/Uniform.java

@ -1,350 +1,350 @@
/* /*
* Copyright (c) 2009-2012 jMonkeyEngine * Copyright (c) 2009-2012 jMonkeyEngine
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are * modification, are permitted provided that the following conditions are
* met: * met:
* *
* * Redistributions of source code must retain the above copyright * * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer. * notice, this list of conditions and the following disclaimer.
* *
* * Redistributions in binary form must reproduce the above copyright * * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the * notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution. * documentation and/or other materials provided with the distribution.
* *
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
* may be used to endorse or promote products derived from this software * may be used to endorse or promote products derived from this software
* without specific prior written permission. * without specific prior written permission.
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
package com.jme3.shader; package com.jme3.shader;
import com.jme3.math.*; import com.jme3.math.*;
import com.jme3.util.BufferUtils; import com.jme3.util.BufferUtils;
import java.nio.FloatBuffer; import java.nio.FloatBuffer;
import java.nio.IntBuffer; import java.nio.IntBuffer;
public class Uniform extends ShaderVariable { public class Uniform extends ShaderVariable {
private static final Integer ZERO_INT = Integer.valueOf(0); private static final Integer ZERO_INT = Integer.valueOf(0);
private static final Float ZERO_FLT = Float.valueOf(0); private static final Float ZERO_FLT = Float.valueOf(0);
private static final FloatBuffer ZERO_BUF = BufferUtils.createFloatBuffer(4*4); private static final FloatBuffer ZERO_BUF = BufferUtils.createFloatBuffer(4*4);
/** /**
* Currently set value of the uniform. * Currently set value of the uniform.
*/ */
protected Object value = null; protected Object value = null;
/** /**
* For arrays or matrices, efficient format * For arrays or matrices, efficient format
* that can be sent to GL faster. * that can be sent to GL faster.
*/ */
protected FloatBuffer multiData = null; protected FloatBuffer multiData = null;
/** /**
* Type of uniform * Type of uniform
*/ */
protected VarType varType; protected VarType varType;
/** /**
* Binding to a renderer value, or null if user-defined uniform * Binding to a renderer value, or null if user-defined uniform
*/ */
protected UniformBinding binding; protected UniformBinding binding;
/** /**
* Used to track which uniforms to clear to avoid * Used to track which uniforms to clear to avoid
* values leaking from other materials that use that shader. * values leaking from other materials that use that shader.
*/ */
protected boolean setByCurrentMaterial = false; protected boolean setByCurrentMaterial = false;
@Override @Override
public String toString(){ public String toString(){
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append("Uniform[name="); sb.append("Uniform[name=");
sb.append(name); sb.append(name);
if (varType != null){ if (varType != null){
sb.append(", type="); sb.append(", type=");
sb.append(varType); sb.append(varType);
sb.append(", value="); sb.append(", value=");
sb.append(value); sb.append(value);
}else{ }else{
sb.append(", value=<not set>"); sb.append(", value=<not set>");
} }
sb.append("]"); sb.append("]");
return sb.toString(); return sb.toString();
} }
public void setBinding(UniformBinding binding){ public void setBinding(UniformBinding binding){
this.binding = binding; this.binding = binding;
} }
public UniformBinding getBinding(){ public UniformBinding getBinding(){
return binding; return binding;
} }
public VarType getVarType() { public VarType getVarType() {
return varType; return varType;
} }
public Object getValue(){ public Object getValue(){
return value; return value;
} }
public boolean isSetByCurrentMaterial() { public boolean isSetByCurrentMaterial() {
return setByCurrentMaterial; return setByCurrentMaterial;
} }
public void clearSetByCurrentMaterial(){ public void clearSetByCurrentMaterial(){
setByCurrentMaterial = false; setByCurrentMaterial = false;
} }
private static void setVector4(Vector4f vec, Object value) { private static void setVector4(Vector4f vec, Object value) {
if (value instanceof ColorRGBA) { if (value instanceof ColorRGBA) {
ColorRGBA color = (ColorRGBA) value; ColorRGBA color = (ColorRGBA) value;
vec.set(color.r, color.g, color.b, color.a); vec.set(color.r, color.g, color.b, color.a);
} else if (value instanceof Quaternion) { } else if (value instanceof Quaternion) {
Quaternion quat = (Quaternion) value; Quaternion quat = (Quaternion) value;
vec.set(quat.getX(), quat.getY(), quat.getZ(), quat.getW()); vec.set(quat.getX(), quat.getY(), quat.getZ(), quat.getW());
} else if (value instanceof Vector4f) { } else if (value instanceof Vector4f) {
Vector4f vec4 = (Vector4f) value; Vector4f vec4 = (Vector4f) value;
vec.set(vec4); vec.set(vec4);
} else{ } else{
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
} }
public void clearValue(){ public void clearValue(){
updateNeeded = true; updateNeeded = true;
if (multiData != null){ if (multiData != null){
multiData.clear(); multiData.clear();
while (multiData.remaining() > 0){ while (multiData.remaining() > 0){
ZERO_BUF.clear(); ZERO_BUF.clear();
ZERO_BUF.limit( Math.min(multiData.remaining(), 16) ); ZERO_BUF.limit( Math.min(multiData.remaining(), 16) );
multiData.put(ZERO_BUF); multiData.put(ZERO_BUF);
} }
multiData.clear(); multiData.clear();
return; return;
} }
if (varType == null) { if (varType == null) {
return; return;
} }
switch (varType){ switch (varType){
case Int: case Int:
this.value = ZERO_INT; this.value = ZERO_INT;
break; break;
case Boolean: case Boolean:
this.value = Boolean.FALSE; this.value = Boolean.FALSE;
break; break;
case Float: case Float:
this.value = ZERO_FLT; this.value = ZERO_FLT;
break; break;
case Vector2: case Vector2:
this.value = Vector2f.ZERO; this.value = Vector2f.ZERO;
break; break;
case Vector3: case Vector3:
this.value = Vector3f.ZERO; this.value = Vector3f.ZERO;
break; break;
case Vector4: case Vector4:
this.value = Vector4f.ZERO; this.value = Vector4f.ZERO;
break; break;
default: default:
// won't happen because those are either textures // won't happen because those are either textures
// or multidata types // or multidata types
} }
} }
public void setValue(VarType type, Object value){ public void setValue(VarType type, Object value){
if (location == LOC_NOT_DEFINED) { if (location == LOC_NOT_DEFINED) {
return; return;
} }
if (varType != null && varType != type) { if (varType != null && varType != type) {
throw new IllegalArgumentException("Expected a " + varType.name() + " value!"); throw new IllegalArgumentException("Expected a " + varType.name() + " value!");
} }
if (value == null) { if (value == null) {
throw new NullPointerException(); throw new NullPointerException();
} }
setByCurrentMaterial = true; setByCurrentMaterial = true;
switch (type){ switch (type){
case Matrix3: case Matrix3:
Matrix3f m3 = (Matrix3f) value; Matrix3f m3 = (Matrix3f) value;
if (multiData == null) { if (multiData == null) {
multiData = BufferUtils.createFloatBuffer(9); multiData = BufferUtils.createFloatBuffer(9);
} }
m3.fillFloatBuffer(multiData, true); m3.fillFloatBuffer(multiData, true);
multiData.clear(); multiData.clear();
break; break;
case Matrix4: case Matrix4:
Matrix4f m4 = (Matrix4f) value; Matrix4f m4 = (Matrix4f) value;
if (multiData == null) { if (multiData == null) {
multiData = BufferUtils.createFloatBuffer(16); multiData = BufferUtils.createFloatBuffer(16);
} }
m4.fillFloatBuffer(multiData, true); m4.fillFloatBuffer(multiData, true);
multiData.clear(); multiData.clear();
break; break;
case IntArray: case IntArray:
int[] ia = (int[]) value; int[] ia = (int[]) value;
if (this.value == null) { if (this.value == null) {
this.value = BufferUtils.createIntBuffer(ia); this.value = BufferUtils.createIntBuffer(ia);
} else { } else {
this.value = BufferUtils.ensureLargeEnough((IntBuffer)this.value, ia.length); this.value = BufferUtils.ensureLargeEnough((IntBuffer)this.value, ia.length);
} }
((IntBuffer)this.value).clear(); ((IntBuffer)this.value).clear();
break; break;
case FloatArray: case FloatArray:
float[] fa = (float[]) value; float[] fa = (float[]) value;
if (multiData == null) { if (multiData == null) {
multiData = BufferUtils.createFloatBuffer(fa); multiData = BufferUtils.createFloatBuffer(fa);
} else { } else {
multiData = BufferUtils.ensureLargeEnough(multiData, fa.length); multiData = BufferUtils.ensureLargeEnough(multiData, fa.length);
} }
multiData.put(fa); multiData.put(fa);
multiData.clear(); multiData.clear();
break; break;
case Vector2Array: case Vector2Array:
Vector2f[] v2a = (Vector2f[]) value; Vector2f[] v2a = (Vector2f[]) value;
if (multiData == null) { if (multiData == null) {
multiData = BufferUtils.createFloatBuffer(v2a); multiData = BufferUtils.createFloatBuffer(v2a);
} else { } else {
multiData = BufferUtils.ensureLargeEnough(multiData, v2a.length * 2); multiData = BufferUtils.ensureLargeEnough(multiData, v2a.length * 2);
} }
for (int i = 0; i < v2a.length; i++) { for (int i = 0; i < v2a.length; i++) {
BufferUtils.setInBuffer(v2a[i], multiData, i); BufferUtils.setInBuffer(v2a[i], multiData, i);
} }
multiData.clear(); multiData.clear();
break; break;
case Vector3Array: case Vector3Array:
Vector3f[] v3a = (Vector3f[]) value; Vector3f[] v3a = (Vector3f[]) value;
if (multiData == null) { if (multiData == null) {
multiData = BufferUtils.createFloatBuffer(v3a); multiData = BufferUtils.createFloatBuffer(v3a);
} else { } else {
multiData = BufferUtils.ensureLargeEnough(multiData, v3a.length * 3); multiData = BufferUtils.ensureLargeEnough(multiData, v3a.length * 3);
} }
for (int i = 0; i < v3a.length; i++) { for (int i = 0; i < v3a.length; i++) {
BufferUtils.setInBuffer(v3a[i], multiData, i); BufferUtils.setInBuffer(v3a[i], multiData, i);
} }
multiData.clear(); multiData.clear();
break; break;
case Vector4Array: case Vector4Array:
Vector4f[] v4a = (Vector4f[]) value; Vector4f[] v4a = (Vector4f[]) value;
if (multiData == null) { if (multiData == null) {
multiData = BufferUtils.createFloatBuffer(v4a); multiData = BufferUtils.createFloatBuffer(v4a);
} else { } else {
multiData = BufferUtils.ensureLargeEnough(multiData, v4a.length * 4); multiData = BufferUtils.ensureLargeEnough(multiData, v4a.length * 4);
} }
for (int i = 0; i < v4a.length; i++) { for (int i = 0; i < v4a.length; i++) {
BufferUtils.setInBuffer(v4a[i], multiData, i); BufferUtils.setInBuffer(v4a[i], multiData, i);
} }
multiData.clear(); multiData.clear();
break; break;
case Matrix3Array: case Matrix3Array:
Matrix3f[] m3a = (Matrix3f[]) value; Matrix3f[] m3a = (Matrix3f[]) value;
if (multiData == null) { if (multiData == null) {
multiData = BufferUtils.createFloatBuffer(m3a.length * 9); multiData = BufferUtils.createFloatBuffer(m3a.length * 9);
} else { } else {
multiData = BufferUtils.ensureLargeEnough(multiData, m3a.length * 9); multiData = BufferUtils.ensureLargeEnough(multiData, m3a.length * 9);
} }
for (int i = 0; i < m3a.length; i++) { for (int i = 0; i < m3a.length; i++) {
m3a[i].fillFloatBuffer(multiData, true); m3a[i].fillFloatBuffer(multiData, true);
} }
multiData.clear(); multiData.clear();
break; break;
case Matrix4Array: case Matrix4Array:
Matrix4f[] m4a = (Matrix4f[]) value; Matrix4f[] m4a = (Matrix4f[]) value;
if (multiData == null) { if (multiData == null) {
multiData = BufferUtils.createFloatBuffer(m4a.length * 16); multiData = BufferUtils.createFloatBuffer(m4a.length * 16);
} else { } else {
multiData = BufferUtils.ensureLargeEnough(multiData, m4a.length * 16); multiData = BufferUtils.ensureLargeEnough(multiData, m4a.length * 16);
} }
for (int i = 0; i < m4a.length; i++) { for (int i = 0; i < m4a.length; i++) {
m4a[i].fillFloatBuffer(multiData, true); m4a[i].fillFloatBuffer(multiData, true);
} }
multiData.clear(); multiData.clear();
break; break;
// Only use check if equals optimization for primitive values // Only use check if equals optimization for primitive values
case Int: case Int:
case Float: case Float:
case Boolean: case Boolean:
if (this.value != null && this.value.equals(value)) { if (this.value != null && this.value.equals(value)) {
return; return;
} }
this.value = value; this.value = value;
break; break;
default: default:
this.value = value; this.value = value;
break; break;
} }
if (multiData != null) { if (multiData != null) {
this.value = multiData; this.value = multiData;
} }
varType = type; varType = type;
updateNeeded = true; updateNeeded = true;
} }
public void setVector4Length(int length){ public void setVector4Length(int length){
if (location == -1) if (location == -1)
return; return;
FloatBuffer fb = (FloatBuffer) value; FloatBuffer fb = (FloatBuffer) value;
if (fb == null || fb.capacity() < length) { if (fb == null || fb.capacity() < length * 4) {
value = BufferUtils.createFloatBuffer(length * 4); value = BufferUtils.createFloatBuffer(length * 4);
} }
varType = VarType.Vector4Array; varType = VarType.Vector4Array;
updateNeeded = true; updateNeeded = true;
setByCurrentMaterial = true; setByCurrentMaterial = true;
} }
public void setVector4InArray(float x, float y, float z, float w, int index){ public void setVector4InArray(float x, float y, float z, float w, int index){
if (location == -1) if (location == -1)
return; return;
if (varType != null && varType != VarType.Vector4Array) if (varType != null && varType != VarType.Vector4Array)
throw new IllegalArgumentException("Expected a "+varType.name()+" value!"); throw new IllegalArgumentException("Expected a "+varType.name()+" value!");
FloatBuffer fb = (FloatBuffer) value; FloatBuffer fb = (FloatBuffer) value;
fb.position(index * 4); fb.position(index * 4);
fb.put(x).put(y).put(z).put(w); fb.put(x).put(y).put(z).put(w);
fb.rewind(); fb.rewind();
updateNeeded = true; updateNeeded = true;
setByCurrentMaterial = true; setByCurrentMaterial = true;
} }
public boolean isUpdateNeeded(){ public boolean isUpdateNeeded(){
return updateNeeded; return updateNeeded;
} }
public void clearUpdateNeeded(){ public void clearUpdateNeeded(){
updateNeeded = false; updateNeeded = false;
} }
public void reset(){ public void reset(){
setByCurrentMaterial = false; setByCurrentMaterial = false;
location = -2; location = -2;
updateNeeded = true; updateNeeded = true;
} }
} }

Loading…
Cancel
Save