• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
write(JmeExporter ex)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
read(JmeImporter im)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
toString()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 
setBinding(UniformBinding binding)180     public void setBinding(UniformBinding binding){
181         this.binding = binding;
182     }
183 
getBinding()184     public UniformBinding getBinding(){
185         return binding;
186     }
187 
getVarType()188     public VarType getVarType() {
189         return varType;
190     }
191 
getValue()192     public Object getValue(){
193         return value;
194     }
195 
isSetByCurrentMaterial()196     public boolean isSetByCurrentMaterial() {
197         return setByCurrentMaterial;
198     }
199 
clearSetByCurrentMaterial()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 
clearValue()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 
setValue(VarType type, Object value)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 
setVector4Length(int length)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 
setVector4InArray(float x, float y, float z, float w, int index)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 
isUpdateNeeded()418     public boolean isUpdateNeeded(){
419         return updateNeeded;
420     }
421 
clearUpdateNeeded()422     public void clearUpdateNeeded(){
423         updateNeeded = false;
424     }
425 
reset()426     public void reset(){
427         setByCurrentMaterial = false;
428         location = -2;
429         updateNeeded = true;
430     }
431 
432 }
433