Home | History | Annotate | Download | only in shader
      1 /*
      2  * Copyright (c) 2009-2010 jMonkeyEngine
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions are
      7  * met:
      8  *
      9  * * Redistributions of source code must retain the above copyright
     10  *   notice, this list of conditions and the following disclaimer.
     11  *
     12  * * Redistributions in binary form must reproduce the above copyright
     13  *   notice, this list of conditions and the following disclaimer in the
     14  *   documentation and/or other materials provided with the distribution.
     15  *
     16  * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
     17  *   may be used to endorse or promote products derived from this software
     18  *   without specific prior written permission.
     19  *
     20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
     28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31  */
     32 
     33 package com.jme3.shader;
     34 
     35 import com.jme3.export.InputCapsule;
     36 import com.jme3.export.JmeExporter;
     37 import com.jme3.export.JmeImporter;
     38 import com.jme3.export.OutputCapsule;
     39 import com.jme3.math.*;
     40 import com.jme3.util.BufferUtils;
     41 import java.io.IOException;
     42 import java.nio.FloatBuffer;
     43 
     44 public class Uniform extends ShaderVariable {
     45 
     46     private static final Integer ZERO_INT = Integer.valueOf(0);
     47     private static final Float ZERO_FLT = Float.valueOf(0);
     48     private static final FloatBuffer ZERO_BUF = BufferUtils.createFloatBuffer(4*4);
     49 
     50     /**
     51      * Currently set value of the uniform.
     52      */
     53     protected Object value = null;
     54     protected FloatBuffer multiData = null;
     55 
     56     /**
     57      * Type of uniform
     58      */
     59     protected VarType varType;
     60 
     61     /**
     62      * Binding to a renderer value, or null if user-defined uniform
     63      */
     64     protected UniformBinding binding;
     65 
     66     protected boolean setByCurrentMaterial = false;
     67 //    protected Object lastChanger = null;
     68 
     69     @Override
     70     public void write(JmeExporter ex) throws IOException{
     71         super.write(ex);
     72         OutputCapsule oc = ex.getCapsule(this);
     73         oc.write(varType, "varType", null);
     74         oc.write(binding, "binding", null);
     75         switch (varType){
     76             case Boolean:
     77                 oc.write( ((Boolean)value).booleanValue(), "valueBoolean", false );
     78                 break;
     79             case Float:
     80                 oc.write( ((Float)value).floatValue(), "valueFloat", 0);
     81                 break;
     82             case FloatArray:
     83                 oc.write( (FloatBuffer)value, "valueFloatArray", null);
     84                 break;
     85             case Int:
     86                 oc.write( ((Integer)value).intValue(), "valueInt", 0);
     87                 break;
     88             case Matrix3:
     89                 oc.write( (Matrix3f)value, "valueMatrix3", null);
     90                 break;
     91             case Matrix3Array:
     92             case Matrix4Array:
     93             case Vector2Array:
     94                 throw new UnsupportedOperationException("Come again?");
     95             case Matrix4:
     96                 oc.write( (Matrix4f)value, "valueMatrix4", null);
     97                 break;
     98             case Vector2:
     99                 oc.write( (Vector2f)value, "valueVector2", null);
    100                 break;
    101             case Vector3:
    102                 oc.write( (Vector3f)value, "valueVector3", null);
    103                 break;
    104             case Vector3Array:
    105                 oc.write( (FloatBuffer)value, "valueVector3Array", null);
    106                 break;
    107             case Vector4:
    108                 oc.write( (ColorRGBA)value, "valueVector4", null);
    109                 break;
    110             case Vector4Array:
    111                 oc.write( (FloatBuffer)value, "valueVector4Array", null);
    112                 break;
    113         }
    114     }
    115 
    116     @Override
    117     public void read(JmeImporter im) throws IOException{
    118         super.read(im);
    119         InputCapsule ic = im.getCapsule(this);
    120         varType = ic.readEnum("varType", VarType.class, null);
    121         binding = ic.readEnum("binding", UniformBinding.class, null);
    122         switch (varType){
    123             case Boolean:
    124                 value = ic.readBoolean("valueBoolean", false);
    125                 break;
    126             case Float:
    127                 value = ic.readFloat("valueFloat", 0);
    128                 break;
    129             case FloatArray:
    130                 value = ic.readFloatBuffer("valueFloatArray", null);
    131                 break;
    132             case Int:
    133                 value = ic.readInt("valueInt", 0);
    134                 break;
    135             case Matrix3:
    136                 multiData = ic.readFloatBuffer("valueMatrix3", null);
    137                 value = multiData;
    138                 break;
    139             case Matrix4:
    140                 multiData = ic.readFloatBuffer("valueMatrix4", null);
    141                 value = multiData;
    142                 break;
    143             case Vector2:
    144                 value = ic.readSavable("valueVector2", null);
    145                 break;
    146             case Vector3:
    147                 value = ic.readSavable("valueVector3", null);
    148                 break;
    149             case Vector3Array:
    150                 value = ic.readFloatBuffer("valueVector3Array", null);
    151                 break;
    152             case Vector4:
    153                 value = ic.readSavable("valueVector4", null);
    154                 break;
    155             case Vector4Array:
    156                 value = ic.readFloatBuffer("valueVector4Array", null);
    157                 break;
    158         }
    159     }
    160 
    161     @Override
    162     public String toString(){
    163         StringBuilder sb = new StringBuilder();
    164         if (name != null){
    165             sb.append("Uniform[name=");
    166             sb.append(name);
    167             if (varType != null){
    168                 sb.append(", type=");
    169                 sb.append(varType);
    170                 sb.append(", value=");
    171                 sb.append(value);
    172             }else{
    173                 sb.append(", value=<not set>");
    174             }
    175         }
    176         sb.append("]");
    177         return sb.toString();
    178     }
    179 
    180     public void setBinding(UniformBinding binding){
    181         this.binding = binding;
    182     }
    183 
    184     public UniformBinding getBinding(){
    185         return binding;
    186     }
    187 
    188     public VarType getVarType() {
    189         return varType;
    190     }
    191 
    192     public Object getValue(){
    193         return value;
    194     }
    195 
    196     public boolean isSetByCurrentMaterial() {
    197         return setByCurrentMaterial;
    198     }
    199 
    200     public void clearSetByCurrentMaterial(){
    201         setByCurrentMaterial = false;
    202     }
    203 
    204 //    public void setLastChanger(Object lastChanger){
    205 //        this.lastChanger = lastChanger;
    206 //    }
    207 //
    208 //    public Object getLastChanger(){
    209 //        return lastChanger;
    210 //    }
    211 
    212     public void clearValue(){
    213         updateNeeded = true;
    214 
    215         if (multiData != null){
    216             ZERO_BUF.clear();
    217             multiData.clear();
    218 
    219             while (multiData.remaining() > 0){
    220                 ZERO_BUF.limit( Math.min(multiData.remaining(), 16) );
    221                 multiData.put(ZERO_BUF);
    222             }
    223 
    224             multiData.clear();
    225 
    226             return;
    227         }
    228 
    229         if (varType == null)
    230             return;
    231 
    232         switch (varType){
    233             case Int:
    234                 this.value = ZERO_INT;
    235                 break;
    236             case Boolean:
    237                 this.value = Boolean.FALSE;
    238                 break;
    239             case Float:
    240                 this.value = ZERO_FLT;
    241                 break;
    242             case Vector2:
    243                 this.value = Vector2f.ZERO;
    244                 break;
    245             case Vector3:
    246                 this.value = Vector3f.ZERO;
    247                 break;
    248             case Vector4:
    249                 if (this.value instanceof ColorRGBA){
    250                     this.value = ColorRGBA.BlackNoAlpha;
    251                 }else{
    252                     this.value = Quaternion.ZERO;
    253                 }
    254                 break;
    255             default:
    256                 break; // won't happen because those are either textures
    257                        // or multidata types
    258         }
    259     }
    260 
    261     public void setValue(VarType type, Object value){
    262         if (location == -1)
    263             return;
    264 
    265         if (varType != null && varType != type)
    266             throw new IllegalArgumentException("Expected a "+varType.name()+" value!");
    267 
    268         if (value == null)
    269             throw new NullPointerException();
    270 
    271         setByCurrentMaterial = true;
    272 
    273         switch (type){
    274             case Matrix3:
    275                 Matrix3f m3 = (Matrix3f) value;
    276                 if (multiData == null)
    277                     multiData = BufferUtils.createFloatBuffer(9);
    278 
    279                 m3.fillFloatBuffer(multiData, true);
    280                 multiData.clear();
    281                 break;
    282             case Matrix4:
    283                 Matrix4f m4 = (Matrix4f) value;
    284                 if (multiData == null)
    285                     multiData = BufferUtils.createFloatBuffer(16);
    286 
    287                 m4.fillFloatBuffer(multiData, true);
    288                 multiData.clear();
    289                 break;
    290             case FloatArray:
    291                 float[] fa = (float[]) value;
    292                 if (multiData == null){
    293                     multiData = BufferUtils.createFloatBuffer(fa);
    294                 }else{
    295                     multiData = BufferUtils.ensureLargeEnough(multiData, fa.length);
    296                 }
    297 
    298                 multiData.put(fa);
    299                 multiData.clear();
    300                 break;
    301             case Vector2Array:
    302                 Vector2f[] v2a = (Vector2f[]) value;
    303                 if (multiData == null){
    304                     multiData = BufferUtils.createFloatBuffer(v2a);
    305                 } else {
    306                     multiData = BufferUtils.ensureLargeEnough(multiData, v2a.length * 2);
    307                 }
    308 
    309                 for (int i = 0; i < v2a.length; i++)
    310                     BufferUtils.setInBuffer(v2a[i], multiData, i);
    311 
    312                 multiData.clear();
    313                 break;
    314             case Vector3Array:
    315                 Vector3f[] v3a = (Vector3f[]) value;
    316                 if (multiData == null){
    317                     multiData = BufferUtils.createFloatBuffer(v3a);
    318                 } else{
    319                     multiData = BufferUtils.ensureLargeEnough(multiData, v3a.length * 3);
    320                 }
    321 
    322                 for (int i = 0; i < v3a.length; i++)
    323                     BufferUtils.setInBuffer(v3a[i], multiData, i);
    324 
    325                 multiData.clear();
    326                 break;
    327             case Vector4Array:
    328                 Quaternion[] v4a = (Quaternion[]) value;
    329                 if (multiData == null){
    330                     multiData = BufferUtils.createFloatBuffer(v4a);
    331                 } else {
    332                     multiData = BufferUtils.ensureLargeEnough(multiData, v4a.length * 4);
    333                 }
    334 
    335                 for (int i = 0; i < v4a.length; i++)
    336                     BufferUtils.setInBuffer(v4a[i], multiData, i);
    337 
    338                 multiData.clear();
    339                 break;
    340             case Matrix3Array:
    341                 Matrix3f[] m3a = (Matrix3f[]) value;
    342 
    343                 if (multiData == null)
    344                     multiData = BufferUtils.createFloatBuffer(m3a.length * 9);
    345                 else{
    346                     multiData = BufferUtils.ensureLargeEnough(multiData, m3a.length * 9);
    347                 }
    348 
    349                 for (int i = 0; i < m3a.length; i++)
    350                     m3a[i].fillFloatBuffer(multiData, true);
    351 
    352                 multiData.clear();
    353                 break;
    354             case Matrix4Array:
    355                 Matrix4f[] m4a = (Matrix4f[]) value;
    356 
    357                 if (multiData == null)
    358                     multiData = BufferUtils.createFloatBuffer(m4a.length * 16);
    359                 else{
    360                     multiData = BufferUtils.ensureLargeEnough(multiData, m4a.length * 16);
    361                 }
    362 
    363                 for (int i = 0; i < m4a.length; i++)
    364                     m4a[i].fillFloatBuffer(multiData, true);
    365 
    366                 multiData.clear();
    367                 break;
    368             // Only use check if equals optimization for primitive values
    369             case Int:
    370             case Float:
    371             case Boolean:
    372                 if (this.value != null && this.value.equals(value))
    373                     return;
    374 
    375                 this.value = value;
    376                 break;
    377             default:
    378                 this.value = value;
    379                 break;
    380         }
    381 
    382         if (multiData != null)
    383             this.value = multiData;
    384 
    385         varType = type;
    386         updateNeeded = true;
    387     }
    388 
    389     public void setVector4Length(int length){
    390         if (location == -1)
    391             return;
    392 
    393         FloatBuffer fb = (FloatBuffer) value;
    394         if (fb == null || fb.capacity() < length){
    395             value = BufferUtils.createFloatBuffer(length * 4);
    396         }
    397 
    398         varType = VarType.Vector4Array;
    399         updateNeeded = true;
    400         setByCurrentMaterial = true;
    401     }
    402 
    403     public void setVector4InArray(float x, float y, float z, float w, int index){
    404         if (location == -1)
    405             return;
    406 
    407         if (varType != null && varType != VarType.Vector4Array)
    408             throw new IllegalArgumentException("Expected a "+varType.name()+" value!");
    409 
    410         FloatBuffer fb = (FloatBuffer) value;
    411         fb.position(index * 4);
    412         fb.put(x).put(y).put(z).put(w);
    413         fb.rewind();
    414         updateNeeded = true;
    415         setByCurrentMaterial = true;
    416     }
    417 
    418     public boolean isUpdateNeeded(){
    419         return updateNeeded;
    420     }
    421 
    422     public void clearUpdateNeeded(){
    423         updateNeeded = false;
    424     }
    425 
    426     public void reset(){
    427         setByCurrentMaterial = false;
    428         location = -2;
    429         updateNeeded = true;
    430     }
    431 
    432 }
    433