• R/O
  • HTTP
  • SSH
  • HTTPS

Commit

Tags
No Tags

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

Main repository of MikuMikuStudio


Commit MetaInfo

Revisionca902c804a84b6a58b3726b8eff0726c06dc1317 (tree)
Time2013-03-21 02:53:50
Authorremy.bouquet@gmail.com <remy.bouquet@gmai...>
Commiterremy.bouquet@gmail.com

Log Message

Added support for int arrays uniforms. thanks to abies.

git-svn-id: http://jmonkeyengine.googlecode.com/svn/trunk@10495 75d07b2b-3a1a-0410-a2c5-0572b91ccdca

Change Summary

Incremental Difference

--- a/engine/src/android/com/jme3/renderer/android/OGLESShaderRenderer.java
+++ b/engine/src/android/com/jme3/renderer/android/OGLESShaderRenderer.java
@@ -643,6 +643,7 @@ public class OGLESShaderRenderer implements Renderer {
643643
644644 uniform.clearUpdateNeeded();
645645 FloatBuffer fb;
646+ IntBuffer ib;
646647 switch (uniform.getVarType()) {
647648 case Float:
648649 Float f = (Float) uniform.getValue();
@@ -683,6 +684,10 @@ public class OGLESShaderRenderer implements Renderer {
683684 assert fb.remaining() == 16;
684685 GLES20.glUniformMatrix4fv(loc, 1, false, fb);
685686 break;
687+ case IntArray:
688+ ib = (IntBuffer) uniform.getValue();
689+ GLES20.glUniform1iv(loc, ib.limit(), ib);
690+ break;
686691 case FloatArray:
687692 fb = (FloatBuffer) uniform.getValue();
688693 GLES20.glUniform1fv(loc, fb.limit(), fb);
--- a/engine/src/core/com/jme3/shader/Uniform.java
+++ b/engine/src/core/com/jme3/shader/Uniform.java
@@ -1,340 +1,350 @@
1-/*
2- * Copyright (c) 2009-2012 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-package com.jme3.shader;
33-
34-import com.jme3.math.*;
35-import com.jme3.util.BufferUtils;
36-import java.nio.FloatBuffer;
37-
38-public class Uniform extends ShaderVariable {
39-
40- private static final Integer ZERO_INT = Integer.valueOf(0);
41- private static final Float ZERO_FLT = Float.valueOf(0);
42- private static final FloatBuffer ZERO_BUF = BufferUtils.createFloatBuffer(4*4);
43-
44- /**
45- * Currently set value of the uniform.
46- */
47- protected Object value = null;
48-
49- /**
50- * For arrays or matrices, efficient format
51- * that can be sent to GL faster.
52- */
53- protected FloatBuffer multiData = null;
54-
55- /**
56- * Type of uniform
57- */
58- protected VarType varType;
59-
60- /**
61- * Binding to a renderer value, or null if user-defined uniform
62- */
63- protected UniformBinding binding;
64-
65- /**
66- * Used to track which uniforms to clear to avoid
67- * values leaking from other materials that use that shader.
68- */
69- protected boolean setByCurrentMaterial = false;
70-
71- @Override
72- public String toString(){
73- StringBuilder sb = new StringBuilder();
74- sb.append("Uniform[name=");
75- sb.append(name);
76- if (varType != null){
77- sb.append(", type=");
78- sb.append(varType);
79- sb.append(", value=");
80- sb.append(value);
81- }else{
82- sb.append(", value=<not set>");
83- }
84- sb.append("]");
85- return sb.toString();
86- }
87-
88- public void setBinding(UniformBinding binding){
89- this.binding = binding;
90- }
91-
92- public UniformBinding getBinding(){
93- return binding;
94- }
95-
96- public VarType getVarType() {
97- return varType;
98- }
99-
100- public Object getValue(){
101- return value;
102- }
103-
104- public boolean isSetByCurrentMaterial() {
105- return setByCurrentMaterial;
106- }
107-
108- public void clearSetByCurrentMaterial(){
109- setByCurrentMaterial = false;
110- }
111-
112- private static void setVector4(Vector4f vec, Object value) {
113- if (value instanceof ColorRGBA) {
114- ColorRGBA color = (ColorRGBA) value;
115- vec.set(color.r, color.g, color.b, color.a);
116- } else if (value instanceof Quaternion) {
117- Quaternion quat = (Quaternion) value;
118- vec.set(quat.getX(), quat.getY(), quat.getZ(), quat.getW());
119- } else if (value instanceof Vector4f) {
120- Vector4f vec4 = (Vector4f) value;
121- vec.set(vec4);
122- } else{
123- throw new IllegalArgumentException();
124- }
125- }
126-
127- public void clearValue(){
128- updateNeeded = true;
129-
130- if (multiData != null){
131- ZERO_BUF.clear();
132- multiData.clear();
133-
134- while (multiData.remaining() > 0){
135- ZERO_BUF.limit( Math.min(multiData.remaining(), 16) );
136- multiData.put(ZERO_BUF);
137- }
138-
139- multiData.clear();
140-
141- return;
142- }
143-
144- if (varType == null) {
145- return;
146- }
147-
148- switch (varType){
149- case Int:
150- this.value = ZERO_INT;
151- break;
152- case Boolean:
153- this.value = Boolean.FALSE;
154- break;
155- case Float:
156- this.value = ZERO_FLT;
157- break;
158- case Vector2:
159- this.value = Vector2f.ZERO;
160- break;
161- case Vector3:
162- this.value = Vector3f.ZERO;
163- break;
164- case Vector4:
165- this.value = Vector4f.ZERO;
166- break;
167- default:
168- // won't happen because those are either textures
169- // or multidata types
170- }
171- }
172-
173- public void setValue(VarType type, Object value){
174- if (location == LOC_NOT_DEFINED) {
175- return;
176- }
177-
178- if (varType != null && varType != type) {
179- throw new IllegalArgumentException("Expected a " + varType.name() + " value!");
180- }
181-
182- if (value == null) {
183- throw new NullPointerException();
184- }
185-
186- setByCurrentMaterial = true;
187-
188- switch (type){
189- case Matrix3:
190- Matrix3f m3 = (Matrix3f) value;
191- if (multiData == null) {
192- multiData = BufferUtils.createFloatBuffer(9);
193- }
194- m3.fillFloatBuffer(multiData, true);
195- multiData.clear();
196- break;
197- case Matrix4:
198- Matrix4f m4 = (Matrix4f) value;
199- if (multiData == null) {
200- multiData = BufferUtils.createFloatBuffer(16);
201- }
202- m4.fillFloatBuffer(multiData, true);
203- multiData.clear();
204- break;
205- case FloatArray:
206- float[] fa = (float[]) value;
207- if (multiData == null) {
208- multiData = BufferUtils.createFloatBuffer(fa);
209- } else {
210- multiData = BufferUtils.ensureLargeEnough(multiData, fa.length);
211- }
212- multiData.put(fa);
213- multiData.clear();
214- break;
215- case Vector2Array:
216- Vector2f[] v2a = (Vector2f[]) value;
217- if (multiData == null) {
218- multiData = BufferUtils.createFloatBuffer(v2a);
219- } else {
220- multiData = BufferUtils.ensureLargeEnough(multiData, v2a.length * 2);
221- }
222- for (int i = 0; i < v2a.length; i++) {
223- BufferUtils.setInBuffer(v2a[i], multiData, i);
224- }
225- multiData.clear();
226- break;
227- case Vector3Array:
228- Vector3f[] v3a = (Vector3f[]) value;
229- if (multiData == null) {
230- multiData = BufferUtils.createFloatBuffer(v3a);
231- } else {
232- multiData = BufferUtils.ensureLargeEnough(multiData, v3a.length * 3);
233- }
234- for (int i = 0; i < v3a.length; i++) {
235- BufferUtils.setInBuffer(v3a[i], multiData, i);
236- }
237- multiData.clear();
238- break;
239- case Vector4Array:
240- Vector4f[] v4a = (Vector4f[]) value;
241- if (multiData == null) {
242- multiData = BufferUtils.createFloatBuffer(v4a);
243- } else {
244- multiData = BufferUtils.ensureLargeEnough(multiData, v4a.length * 4);
245- }
246- for (int i = 0; i < v4a.length; i++) {
247- BufferUtils.setInBuffer(v4a[i], multiData, i);
248- }
249- multiData.clear();
250- break;
251- case Matrix3Array:
252- Matrix3f[] m3a = (Matrix3f[]) value;
253- if (multiData == null) {
254- multiData = BufferUtils.createFloatBuffer(m3a.length * 9);
255- } else {
256- multiData = BufferUtils.ensureLargeEnough(multiData, m3a.length * 9);
257- }
258- for (int i = 0; i < m3a.length; i++) {
259- m3a[i].fillFloatBuffer(multiData, true);
260- }
261- multiData.clear();
262- break;
263- case Matrix4Array:
264- Matrix4f[] m4a = (Matrix4f[]) value;
265- if (multiData == null) {
266- multiData = BufferUtils.createFloatBuffer(m4a.length * 16);
267- } else {
268- multiData = BufferUtils.ensureLargeEnough(multiData, m4a.length * 16);
269- }
270- for (int i = 0; i < m4a.length; i++) {
271- m4a[i].fillFloatBuffer(multiData, true);
272- }
273- multiData.clear();
274- break;
275- // Only use check if equals optimization for primitive values
276- case Int:
277- case Float:
278- case Boolean:
279- if (this.value != null && this.value.equals(value)) {
280- return;
281- }
282- this.value = value;
283- break;
284- default:
285- this.value = value;
286- break;
287- }
288-
289- if (multiData != null) {
290- this.value = multiData;
291- }
292-
293- varType = type;
294- updateNeeded = true;
295- }
296-
297- public void setVector4Length(int length){
298- if (location == -1)
299- return;
300-
301- FloatBuffer fb = (FloatBuffer) value;
302- if (fb == null || fb.capacity() < length) {
303- value = BufferUtils.createFloatBuffer(length * 4);
304- }
305-
306- varType = VarType.Vector4Array;
307- updateNeeded = true;
308- setByCurrentMaterial = true;
309- }
310-
311- public void setVector4InArray(float x, float y, float z, float w, int index){
312- if (location == -1)
313- return;
314-
315- if (varType != null && varType != VarType.Vector4Array)
316- throw new IllegalArgumentException("Expected a "+varType.name()+" value!");
317-
318- FloatBuffer fb = (FloatBuffer) value;
319- fb.position(index * 4);
320- fb.put(x).put(y).put(z).put(w);
321- fb.rewind();
322- updateNeeded = true;
323- setByCurrentMaterial = true;
324- }
325-
326- public boolean isUpdateNeeded(){
327- return updateNeeded;
328- }
329-
330- public void clearUpdateNeeded(){
331- updateNeeded = false;
332- }
333-
334- public void reset(){
335- setByCurrentMaterial = false;
336- location = -2;
337- updateNeeded = true;
338- }
339-
340-}
1+/*
2+ * Copyright (c) 2009-2012 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+package com.jme3.shader;
33+
34+import com.jme3.math.*;
35+import com.jme3.util.BufferUtils;
36+import java.nio.FloatBuffer;
37+import java.nio.IntBuffer;
38+
39+public class Uniform extends ShaderVariable {
40+
41+ private static final Integer ZERO_INT = Integer.valueOf(0);
42+ private static final Float ZERO_FLT = Float.valueOf(0);
43+ private static final FloatBuffer ZERO_BUF = BufferUtils.createFloatBuffer(4*4);
44+
45+ /**
46+ * Currently set value of the uniform.
47+ */
48+ protected Object value = null;
49+
50+ /**
51+ * For arrays or matrices, efficient format
52+ * that can be sent to GL faster.
53+ */
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+ /**
67+ * Used to track which uniforms to clear to avoid
68+ * values leaking from other materials that use that shader.
69+ */
70+ protected boolean setByCurrentMaterial = false;
71+
72+ @Override
73+ public String toString(){
74+ StringBuilder sb = new StringBuilder();
75+ sb.append("Uniform[name=");
76+ sb.append(name);
77+ if (varType != null){
78+ sb.append(", type=");
79+ sb.append(varType);
80+ sb.append(", value=");
81+ sb.append(value);
82+ }else{
83+ sb.append(", value=<not set>");
84+ }
85+ sb.append("]");
86+ return sb.toString();
87+ }
88+
89+ public void setBinding(UniformBinding binding){
90+ this.binding = binding;
91+ }
92+
93+ public UniformBinding getBinding(){
94+ return binding;
95+ }
96+
97+ public VarType getVarType() {
98+ return varType;
99+ }
100+
101+ public Object getValue(){
102+ return value;
103+ }
104+
105+ public boolean isSetByCurrentMaterial() {
106+ return setByCurrentMaterial;
107+ }
108+
109+ public void clearSetByCurrentMaterial(){
110+ setByCurrentMaterial = false;
111+ }
112+
113+ private static void setVector4(Vector4f vec, Object value) {
114+ if (value instanceof ColorRGBA) {
115+ ColorRGBA color = (ColorRGBA) value;
116+ vec.set(color.r, color.g, color.b, color.a);
117+ } else if (value instanceof Quaternion) {
118+ Quaternion quat = (Quaternion) value;
119+ vec.set(quat.getX(), quat.getY(), quat.getZ(), quat.getW());
120+ } else if (value instanceof Vector4f) {
121+ Vector4f vec4 = (Vector4f) value;
122+ vec.set(vec4);
123+ } else{
124+ throw new IllegalArgumentException();
125+ }
126+ }
127+
128+ public void clearValue(){
129+ updateNeeded = true;
130+
131+ if (multiData != null){
132+ multiData.clear();
133+
134+ while (multiData.remaining() > 0){
135+ ZERO_BUF.clear();
136+ ZERO_BUF.limit( Math.min(multiData.remaining(), 16) );
137+ multiData.put(ZERO_BUF);
138+ }
139+
140+ multiData.clear();
141+
142+ return;
143+ }
144+
145+ if (varType == null) {
146+ return;
147+ }
148+
149+ switch (varType){
150+ case Int:
151+ this.value = ZERO_INT;
152+ break;
153+ case Boolean:
154+ this.value = Boolean.FALSE;
155+ break;
156+ case Float:
157+ this.value = ZERO_FLT;
158+ break;
159+ case Vector2:
160+ this.value = Vector2f.ZERO;
161+ break;
162+ case Vector3:
163+ this.value = Vector3f.ZERO;
164+ break;
165+ case Vector4:
166+ this.value = Vector4f.ZERO;
167+ break;
168+ default:
169+ // won't happen because those are either textures
170+ // or multidata types
171+ }
172+ }
173+
174+ public void setValue(VarType type, Object value){
175+ if (location == LOC_NOT_DEFINED) {
176+ return;
177+ }
178+
179+ if (varType != null && varType != type) {
180+ throw new IllegalArgumentException("Expected a " + varType.name() + " value!");
181+ }
182+
183+ if (value == null) {
184+ throw new NullPointerException();
185+ }
186+
187+ setByCurrentMaterial = true;
188+
189+ switch (type){
190+ case Matrix3:
191+ Matrix3f m3 = (Matrix3f) value;
192+ if (multiData == null) {
193+ multiData = BufferUtils.createFloatBuffer(9);
194+ }
195+ m3.fillFloatBuffer(multiData, true);
196+ multiData.clear();
197+ break;
198+ case Matrix4:
199+ Matrix4f m4 = (Matrix4f) value;
200+ if (multiData == null) {
201+ multiData = BufferUtils.createFloatBuffer(16);
202+ }
203+ m4.fillFloatBuffer(multiData, true);
204+ multiData.clear();
205+ break;
206+ case IntArray:
207+ int[] ia = (int[]) value;
208+ if (this.value == null) {
209+ this.value = BufferUtils.createIntBuffer(ia);
210+ } else {
211+ this.value = BufferUtils.ensureLargeEnough((IntBuffer)this.value, ia.length);
212+ }
213+ ((IntBuffer)this.value).clear();
214+ break;
215+ case FloatArray:
216+ float[] fa = (float[]) value;
217+ if (multiData == null) {
218+ multiData = BufferUtils.createFloatBuffer(fa);
219+ } else {
220+ multiData = BufferUtils.ensureLargeEnough(multiData, fa.length);
221+ }
222+ multiData.put(fa);
223+ multiData.clear();
224+ break;
225+ case Vector2Array:
226+ Vector2f[] v2a = (Vector2f[]) value;
227+ if (multiData == null) {
228+ multiData = BufferUtils.createFloatBuffer(v2a);
229+ } else {
230+ multiData = BufferUtils.ensureLargeEnough(multiData, v2a.length * 2);
231+ }
232+ for (int i = 0; i < v2a.length; i++) {
233+ BufferUtils.setInBuffer(v2a[i], multiData, i);
234+ }
235+ multiData.clear();
236+ break;
237+ case Vector3Array:
238+ Vector3f[] v3a = (Vector3f[]) value;
239+ if (multiData == null) {
240+ multiData = BufferUtils.createFloatBuffer(v3a);
241+ } else {
242+ multiData = BufferUtils.ensureLargeEnough(multiData, v3a.length * 3);
243+ }
244+ for (int i = 0; i < v3a.length; i++) {
245+ BufferUtils.setInBuffer(v3a[i], multiData, i);
246+ }
247+ multiData.clear();
248+ break;
249+ case Vector4Array:
250+ Vector4f[] v4a = (Vector4f[]) value;
251+ if (multiData == null) {
252+ multiData = BufferUtils.createFloatBuffer(v4a);
253+ } else {
254+ multiData = BufferUtils.ensureLargeEnough(multiData, v4a.length * 4);
255+ }
256+ for (int i = 0; i < v4a.length; i++) {
257+ BufferUtils.setInBuffer(v4a[i], multiData, i);
258+ }
259+ multiData.clear();
260+ break;
261+ case Matrix3Array:
262+ Matrix3f[] m3a = (Matrix3f[]) value;
263+ if (multiData == null) {
264+ multiData = BufferUtils.createFloatBuffer(m3a.length * 9);
265+ } else {
266+ multiData = BufferUtils.ensureLargeEnough(multiData, m3a.length * 9);
267+ }
268+ for (int i = 0; i < m3a.length; i++) {
269+ m3a[i].fillFloatBuffer(multiData, true);
270+ }
271+ multiData.clear();
272+ break;
273+ case Matrix4Array:
274+ Matrix4f[] m4a = (Matrix4f[]) value;
275+ if (multiData == null) {
276+ multiData = BufferUtils.createFloatBuffer(m4a.length * 16);
277+ } else {
278+ multiData = BufferUtils.ensureLargeEnough(multiData, m4a.length * 16);
279+ }
280+ for (int i = 0; i < m4a.length; i++) {
281+ m4a[i].fillFloatBuffer(multiData, true);
282+ }
283+ multiData.clear();
284+ break;
285+ // Only use check if equals optimization for primitive values
286+ case Int:
287+ case Float:
288+ case Boolean:
289+ if (this.value != null && this.value.equals(value)) {
290+ return;
291+ }
292+ this.value = value;
293+ break;
294+ default:
295+ this.value = value;
296+ break;
297+ }
298+
299+ if (multiData != null) {
300+ this.value = multiData;
301+ }
302+
303+ varType = type;
304+ updateNeeded = true;
305+ }
306+
307+ public void setVector4Length(int length){
308+ if (location == -1)
309+ return;
310+
311+ FloatBuffer fb = (FloatBuffer) value;
312+ if (fb == null || fb.capacity() < length) {
313+ value = BufferUtils.createFloatBuffer(length * 4);
314+ }
315+
316+ varType = VarType.Vector4Array;
317+ updateNeeded = true;
318+ setByCurrentMaterial = true;
319+ }
320+
321+ public void setVector4InArray(float x, float y, float z, float w, int index){
322+ if (location == -1)
323+ return;
324+
325+ if (varType != null && varType != VarType.Vector4Array)
326+ throw new IllegalArgumentException("Expected a "+varType.name()+" value!");
327+
328+ FloatBuffer fb = (FloatBuffer) value;
329+ fb.position(index * 4);
330+ fb.put(x).put(y).put(z).put(w);
331+ fb.rewind();
332+ updateNeeded = true;
333+ setByCurrentMaterial = true;
334+ }
335+
336+ public boolean isUpdateNeeded(){
337+ return updateNeeded;
338+ }
339+
340+ public void clearUpdateNeeded(){
341+ updateNeeded = false;
342+ }
343+
344+ public void reset(){
345+ setByCurrentMaterial = false;
346+ location = -2;
347+ updateNeeded = true;
348+ }
349+
350+}
--- a/engine/src/core/com/jme3/shader/VarType.java
+++ b/engine/src/core/com/jme3/shader/VarType.java
@@ -1,88 +1,89 @@
1-/*
2- * Copyright (c) 2009-2012 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-package com.jme3.shader;
33-
34-public enum VarType {
35-
36- Float("float"),
37- Vector2("vec2"),
38- Vector3("vec3"),
39- Vector4("vec4"),
40-
41- FloatArray(true,false,"float[]"),
42- Vector2Array(true,false,"vec2[]"),
43- Vector3Array(true,false,"vec3[]"),
44- Vector4Array(true,false,"vec4[]"),
45-
46- Boolean("bool"),
47-
48- Matrix3(true,false,"mat3"),
49- Matrix4(true,false,"mat4"),
50-
51- Matrix3Array(true,false,"mat3[]"),
52- Matrix4Array(true,false,"mat4[]"),
53-
54- TextureBuffer(false,true,"sampler1D|sampler1DShadow"),
55- Texture2D(false,true,"sampler2D|sampler2DShadow"),
56- Texture3D(false,true,"sampler3D"),
57- TextureArray(false,true,"sampler2DArray"),
58- TextureCubeMap(false,true,"samplerCube"),
59- Int("int");
60-
61- private boolean usesMultiData = false;
62- private boolean textureType = false;
63- private String glslType;
64-
65-
66- VarType(String glslType){
67- this.glslType = glslType;
68- }
69-
70- VarType(boolean multiData, boolean textureType,String glslType){
71- usesMultiData = multiData;
72- this.textureType = textureType;
73- this.glslType = glslType;
74- }
75-
76- public boolean isTextureType() {
77- return textureType;
78- }
79-
80- public boolean usesMultiData() {
81- return usesMultiData;
82- }
83-
84- public String getGlslType() {
85- return glslType;
86- }
87-
88-}
1+/*
2+ * Copyright (c) 2009-2012 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+package com.jme3.shader;
33+
34+public enum VarType {
35+
36+ Float("float"),
37+ Vector2("vec2"),
38+ Vector3("vec3"),
39+ Vector4("vec4"),
40+
41+ IntArray(true,false,"int[]"),
42+ FloatArray(true,false,"float[]"),
43+ Vector2Array(true,false,"vec2[]"),
44+ Vector3Array(true,false,"vec3[]"),
45+ Vector4Array(true,false,"vec4[]"),
46+
47+ Boolean("bool"),
48+
49+ Matrix3(true,false,"mat3"),
50+ Matrix4(true,false,"mat4"),
51+
52+ Matrix3Array(true,false,"mat3[]"),
53+ Matrix4Array(true,false,"mat4[]"),
54+
55+ TextureBuffer(false,true,"sampler1D|sampler1DShadow"),
56+ Texture2D(false,true,"sampler2D|sampler2DShadow"),
57+ Texture3D(false,true,"sampler3D"),
58+ TextureArray(false,true,"sampler2DArray"),
59+ TextureCubeMap(false,true,"samplerCube"),
60+ Int("int");
61+
62+ private boolean usesMultiData = false;
63+ private boolean textureType = false;
64+ private String glslType;
65+
66+
67+ VarType(String glslType){
68+ this.glslType = glslType;
69+ }
70+
71+ VarType(boolean multiData, boolean textureType,String glslType){
72+ usesMultiData = multiData;
73+ this.textureType = textureType;
74+ this.glslType = glslType;
75+ }
76+
77+ public boolean isTextureType() {
78+ return textureType;
79+ }
80+
81+ public boolean usesMultiData() {
82+ return usesMultiData;
83+ }
84+
85+ public String getGlslType() {
86+ return glslType;
87+ }
88+
89+}
--- a/engine/src/core/com/jme3/util/BufferUtils.java
+++ b/engine/src/core/com/jme3/util/BufferUtils.java
@@ -1,1363 +1,1381 @@
1-/*
2- * Copyright (c) 2009-2012 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-package com.jme3.util;
33-
34-import com.jme3.math.ColorRGBA;
35-import com.jme3.math.Quaternion;
36-import com.jme3.math.Vector2f;
37-import com.jme3.math.Vector3f;
38-import com.jme3.math.Vector4f;
39-import java.lang.ref.PhantomReference;
40-import java.lang.ref.Reference;
41-import java.lang.ref.ReferenceQueue;
42-import java.lang.reflect.InvocationTargetException;
43-import java.lang.reflect.Method;
44-import java.nio.Buffer;
45-import java.nio.ByteBuffer;
46-import java.nio.ByteOrder;
47-import java.nio.DoubleBuffer;
48-import java.nio.FloatBuffer;
49-import java.nio.IntBuffer;
50-import java.nio.LongBuffer;
51-import java.nio.ShortBuffer;
52-import java.util.concurrent.ConcurrentHashMap;
53-import java.util.concurrent.atomic.AtomicBoolean;
54-import java.util.logging.Level;
55-import java.util.logging.Logger;
56-
57-/**
58- * <code>BufferUtils</code> is a helper class for generating nio buffers from
59- * jME data classes such as Vectors and ColorRGBA.
60- *
61- * @author Joshua Slack
62- * @version $Id: BufferUtils.java,v 1.16 2007/10/29 16:56:18 nca Exp $
63- */
64-public final class BufferUtils {
65-
66- private static boolean trackDirectMemory = false;
67- private static ReferenceQueue<Buffer> removeCollected = new ReferenceQueue<Buffer>();
68- private static ConcurrentHashMap<BufferInfo, BufferInfo> trackedBuffers = new ConcurrentHashMap<BufferInfo, BufferInfo>();
69- static ClearReferences cleanupthread;
70-
71- /**
72- * Set it to true if you want to enable direct memory tracking for debugging purpose.
73- * Default is false.
74- * To print direct memory usage use BufferUtils.printCurrentDirectMemory(StringBuilder store);
75- * @param enabled
76- */
77- public static void setTrackDirectMemoryEnabled(boolean enabled) {
78- trackDirectMemory = enabled;
79- }
80-
81- /**
82- * Creates a clone of the given buffer. The clone's capacity is
83- * equal to the given buffer's limit.
84- *
85- * @param buf The buffer to clone
86- * @return The cloned buffer
87- */
88- public static Buffer clone(Buffer buf) {
89- if (buf instanceof FloatBuffer) {
90- return clone((FloatBuffer) buf);
91- } else if (buf instanceof ShortBuffer) {
92- return clone((ShortBuffer) buf);
93- } else if (buf instanceof ByteBuffer) {
94- return clone((ByteBuffer) buf);
95- } else if (buf instanceof IntBuffer) {
96- return clone((IntBuffer) buf);
97- } else if (buf instanceof DoubleBuffer) {
98- return clone((DoubleBuffer) buf);
99- } else {
100- throw new UnsupportedOperationException();
101- }
102- }
103-
104- private static void onBufferAllocated(Buffer buffer) {
105- /**
106- * StackTraceElement[] stackTrace = new Throwable().getStackTrace(); int
107- * initialIndex = 0;
108- *
109- * for (int i = 0; i < stackTrace.length; i++){ if
110- * (!stackTrace[i].getClassName().equals(BufferUtils.class.getName())){
111- * initialIndex = i; break; } }
112- *
113- * int allocated = buffer.capacity(); int size = 0;
114- *
115- * if (buffer instanceof FloatBuffer){ size = 4; }else if (buffer
116- * instanceof ShortBuffer){ size = 2; }else if (buffer instanceof
117- * ByteBuffer){ size = 1; }else if (buffer instanceof IntBuffer){ size =
118- * 4; }else if (buffer instanceof DoubleBuffer){ size = 8; }
119- *
120- * allocated *= size;
121- *
122- * for (int i = initialIndex; i < stackTrace.length; i++){
123- * StackTraceElement element = stackTrace[i]; if
124- * (element.getClassName().startsWith("java")){ break; }
125- *
126- * try { Class clazz = Class.forName(element.getClassName()); if (i ==
127- * initialIndex){
128- * System.out.println(clazz.getSimpleName()+"."+element.getMethodName
129- * ()+"():" + element.getLineNumber() + " allocated " + allocated);
130- * }else{ System.out.println(" at " +
131- * clazz.getSimpleName()+"."+element.getMethodName()+"()"); } } catch
132- * (ClassNotFoundException ex) { } }
133- */
134- if (BufferUtils.trackDirectMemory) {
135-
136- if (BufferUtils.cleanupthread == null) {
137- BufferUtils.cleanupthread = new ClearReferences();
138- BufferUtils.cleanupthread.start();
139- }
140- if (buffer instanceof ByteBuffer) {
141- BufferInfo info = new BufferInfo(ByteBuffer.class, buffer.capacity(), buffer, BufferUtils.removeCollected);
142- BufferUtils.trackedBuffers.put(info, info);
143- } else if (buffer instanceof FloatBuffer) {
144- BufferInfo info = new BufferInfo(FloatBuffer.class, buffer.capacity() * 4, buffer, BufferUtils.removeCollected);
145- BufferUtils.trackedBuffers.put(info, info);
146- } else if (buffer instanceof IntBuffer) {
147- BufferInfo info = new BufferInfo(IntBuffer.class, buffer.capacity() * 4, buffer, BufferUtils.removeCollected);
148- BufferUtils.trackedBuffers.put(info, info);
149- } else if (buffer instanceof ShortBuffer) {
150- BufferInfo info = new BufferInfo(ShortBuffer.class, buffer.capacity() * 2, buffer, BufferUtils.removeCollected);
151- BufferUtils.trackedBuffers.put(info, info);
152- } else if (buffer instanceof DoubleBuffer) {
153- BufferInfo info = new BufferInfo(DoubleBuffer.class, buffer.capacity() * 8, buffer, BufferUtils.removeCollected);
154- BufferUtils.trackedBuffers.put(info, info);
155- }
156-
157- }
158- }
159-
160- /**
161- * Generate a new FloatBuffer using the given array of Vector3f objects.
162- * The FloatBuffer will be 3 * data.length long and contain the vector data
163- * as data[0].x, data[0].y, data[0].z, data[1].x... etc.
164- *
165- * @param data array of Vector3f objects to place into a new FloatBuffer
166- */
167- public static FloatBuffer createFloatBuffer(Vector3f... data) {
168- if (data == null) {
169- return null;
170- }
171- FloatBuffer buff = createFloatBuffer(3 * data.length);
172- for (Vector3f element : data) {
173- if (element != null) {
174- buff.put(element.x).put(element.y).put(element.z);
175- } else {
176- buff.put(0).put(0).put(0);
177- }
178- }
179- buff.flip();
180- return buff;
181- }
182-
183- /**
184- * Generate a new FloatBuffer using the given array of Quaternion objects.
185- * The FloatBuffer will be 4 * data.length long and contain the vector data.
186- *
187- * @param data array of Quaternion objects to place into a new FloatBuffer
188- */
189- public static FloatBuffer createFloatBuffer(Quaternion... data) {
190- if (data == null) {
191- return null;
192- }
193- FloatBuffer buff = createFloatBuffer(4 * data.length);
194- for (Quaternion element : data) {
195- if (element != null) {
196- buff.put(element.getX()).put(element.getY()).put(element.getZ()).put(element.getW());
197- } else {
198- buff.put(0).put(0).put(0).put(0);
199- }
200- }
201- buff.flip();
202- return buff;
203- }
204-
205- /**
206- * Generate a new FloatBuffer using the given array of Vector4 objects.
207- * The FloatBuffer will be 4 * data.length long and contain the vector data.
208- *
209- * @param data array of Vector4 objects to place into a new FloatBuffer
210- */
211- public static FloatBuffer createFloatBuffer(Vector4f... data) {
212- if (data == null) {
213- return null;
214- }
215- FloatBuffer buff = createFloatBuffer(4 * data.length);
216- for (int x = 0; x < data.length; x++) {
217- if (data[x] != null) {
218- buff.put(data[x].getX()).put(data[x].getY()).put(data[x].getZ()).put(data[x].getW());
219- } else {
220- buff.put(0).put(0).put(0).put(0);
221- }
222- }
223- buff.flip();
224- return buff;
225- }
226-
227- /**
228- * Generate a new FloatBuffer using the given array of float primitives.
229- * @param data array of float primitives to place into a new FloatBuffer
230- */
231- public static FloatBuffer createFloatBuffer(float... data) {
232- if (data == null) {
233- return null;
234- }
235- FloatBuffer buff = createFloatBuffer(data.length);
236- buff.clear();
237- buff.put(data);
238- buff.flip();
239- return buff;
240- }
241-
242- /**
243- * Create a new FloatBuffer of an appropriate size to hold the specified
244- * number of Vector3f object data.
245- *
246- * @param vertices
247- * number of vertices that need to be held by the newly created
248- * buffer
249- * @return the requested new FloatBuffer
250- */
251- public static FloatBuffer createVector3Buffer(int vertices) {
252- FloatBuffer vBuff = createFloatBuffer(3 * vertices);
253- return vBuff;
254- }
255-
256- /**
257- * Create a new FloatBuffer of an appropriate size to hold the specified
258- * number of Vector3f object data only if the given buffer if not already
259- * the right size.
260- *
261- * @param buf
262- * the buffer to first check and rewind
263- * @param vertices
264- * number of vertices that need to be held by the newly created
265- * buffer
266- * @return the requested new FloatBuffer
267- */
268- public static FloatBuffer createVector3Buffer(FloatBuffer buf, int vertices) {
269- if (buf != null && buf.limit() == 3 * vertices) {
270- buf.rewind();
271- return buf;
272- }
273-
274- return createFloatBuffer(3 * vertices);
275- }
276-
277- /**
278- * Sets the data contained in the given color into the FloatBuffer at the
279- * specified index.
280- *
281- * @param color
282- * the data to insert
283- * @param buf
284- * the buffer to insert into
285- * @param index
286- * the postion to place the data; in terms of colors not floats
287- */
288- public static void setInBuffer(ColorRGBA color, FloatBuffer buf,
289- int index) {
290- buf.position(index * 4);
291- buf.put(color.r);
292- buf.put(color.g);
293- buf.put(color.b);
294- buf.put(color.a);
295- }
296-
297- /**
298- * Sets the data contained in the given quaternion into the FloatBuffer at the
299- * specified index.
300- *
301- * @param quat
302- * the {@link Quaternion} to insert
303- * @param buf
304- * the buffer to insert into
305- * @param index
306- * the postion to place the data; in terms of quaternions not floats
307- */
308- public static void setInBuffer(Quaternion quat, FloatBuffer buf,
309- int index) {
310- buf.position(index * 4);
311- buf.put(quat.getX());
312- buf.put(quat.getY());
313- buf.put(quat.getZ());
314- buf.put(quat.getW());
315- }
316-
317- /**
318- * Sets the data contained in the given vector4 into the FloatBuffer at the
319- * specified index.
320- *
321- * @param vec
322- * the {@link Vector4f} to insert
323- * @param buf
324- * the buffer to insert into
325- * @param index
326- * the postion to place the data; in terms of vector4 not floats
327- */
328- public static void setInBuffer(Vector4f vec, FloatBuffer buf,
329- int index) {
330- buf.position(index * 4);
331- buf.put(vec.getX());
332- buf.put(vec.getY());
333- buf.put(vec.getZ());
334- buf.put(vec.getW());
335- }
336-
337- /**
338- * Sets the data contained in the given Vector3F into the FloatBuffer at the
339- * specified index.
340- *
341- * @param vector
342- * the data to insert
343- * @param buf
344- * the buffer to insert into
345- * @param index
346- * the postion to place the data; in terms of vectors not floats
347- */
348- public static void setInBuffer(Vector3f vector, FloatBuffer buf, int index) {
349- if (buf == null) {
350- return;
351- }
352- if (vector == null) {
353- buf.put(index * 3, 0);
354- buf.put((index * 3) + 1, 0);
355- buf.put((index * 3) + 2, 0);
356- } else {
357- buf.put(index * 3, vector.x);
358- buf.put((index * 3) + 1, vector.y);
359- buf.put((index * 3) + 2, vector.z);
360- }
361- }
362-
363- /**
364- * Updates the values of the given vector from the specified buffer at the
365- * index provided.
366- *
367- * @param vector
368- * the vector to set data on
369- * @param buf
370- * the buffer to read from
371- * @param index
372- * the position (in terms of vectors, not floats) to read from
373- * the buf
374- */
375- public static void populateFromBuffer(Vector3f vector, FloatBuffer buf, int index) {
376- vector.x = buf.get(index * 3);
377- vector.y = buf.get(index * 3 + 1);
378- vector.z = buf.get(index * 3 + 2);
379- }
380-
381- /**
382- * Generates a Vector3f array from the given FloatBuffer.
383- *
384- * @param buff
385- * the FloatBuffer to read from
386- * @return a newly generated array of Vector3f objects
387- */
388- public static Vector3f[] getVector3Array(FloatBuffer buff) {
389- buff.clear();
390- Vector3f[] verts = new Vector3f[buff.limit() / 3];
391- for (int x = 0; x < verts.length; x++) {
392- Vector3f v = new Vector3f(buff.get(), buff.get(), buff.get());
393- verts[x] = v;
394- }
395- return verts;
396- }
397-
398- /**
399- * Copies a Vector3f from one position in the buffer to another. The index
400- * values are in terms of vector number (eg, vector number 0 is postions 0-2
401- * in the FloatBuffer.)
402- *
403- * @param buf
404- * the buffer to copy from/to
405- * @param fromPos
406- * the index of the vector to copy
407- * @param toPos
408- * the index to copy the vector to
409- */
410- public static void copyInternalVector3(FloatBuffer buf, int fromPos, int toPos) {
411- copyInternal(buf, fromPos * 3, toPos * 3, 3);
412- }
413-
414- /**
415- * Normalize a Vector3f in-buffer.
416- *
417- * @param buf
418- * the buffer to find the Vector3f within
419- * @param index
420- * the position (in terms of vectors, not floats) of the vector
421- * to normalize
422- */
423- public static void normalizeVector3(FloatBuffer buf, int index) {
424- TempVars vars = TempVars.get();
425- Vector3f tempVec3 = vars.vect1;
426- populateFromBuffer(tempVec3, buf, index);
427- tempVec3.normalizeLocal();
428- setInBuffer(tempVec3, buf, index);
429- vars.release();
430- }
431-
432- /**
433- * Add to a Vector3f in-buffer.
434- *
435- * @param toAdd
436- * the vector to add from
437- * @param buf
438- * the buffer to find the Vector3f within
439- * @param index
440- * the position (in terms of vectors, not floats) of the vector
441- * to add to
442- */
443- public static void addInBuffer(Vector3f toAdd, FloatBuffer buf, int index) {
444- TempVars vars = TempVars.get();
445- Vector3f tempVec3 = vars.vect1;
446- populateFromBuffer(tempVec3, buf, index);
447- tempVec3.addLocal(toAdd);
448- setInBuffer(tempVec3, buf, index);
449- vars.release();
450- }
451-
452- /**
453- * Multiply and store a Vector3f in-buffer.
454- *
455- * @param toMult
456- * the vector to multiply against
457- * @param buf
458- * the buffer to find the Vector3f within
459- * @param index
460- * the position (in terms of vectors, not floats) of the vector
461- * to multiply
462- */
463- public static void multInBuffer(Vector3f toMult, FloatBuffer buf, int index) {
464- TempVars vars = TempVars.get();
465- Vector3f tempVec3 = vars.vect1;
466- populateFromBuffer(tempVec3, buf, index);
467- tempVec3.multLocal(toMult);
468- setInBuffer(tempVec3, buf, index);
469- vars.release();
470- }
471-
472- /**
473- * Checks to see if the given Vector3f is equals to the data stored in the
474- * buffer at the given data index.
475- *
476- * @param check
477- * the vector to check against - null will return false.
478- * @param buf
479- * the buffer to compare data with
480- * @param index
481- * the position (in terms of vectors, not floats) of the vector
482- * in the buffer to check against
483- * @return true if the data is equivalent, otherwise false.
484- */
485- public static boolean equals(Vector3f check, FloatBuffer buf, int index) {
486- TempVars vars = TempVars.get();
487- Vector3f tempVec3 = vars.vect1;
488- populateFromBuffer(tempVec3, buf, index);
489- boolean eq = tempVec3.equals(check);
490- vars.release();
491- return eq;
492- }
493-
494- // // -- VECTOR2F METHODS -- ////
495- /**
496- * Generate a new FloatBuffer using the given array of Vector2f objects.
497- * The FloatBuffer will be 2 * data.length long and contain the vector data
498- * as data[0].x, data[0].y, data[1].x... etc.
499- *
500- * @param data array of Vector2f objects to place into a new FloatBuffer
501- */
502- public static FloatBuffer createFloatBuffer(Vector2f... data) {
503- if (data == null) {
504- return null;
505- }
506- FloatBuffer buff = createFloatBuffer(2 * data.length);
507- for (Vector2f element : data) {
508- if (element != null) {
509- buff.put(element.x).put(element.y);
510- } else {
511- buff.put(0).put(0);
512- }
513- }
514- buff.flip();
515- return buff;
516- }
517-
518- /**
519- * Create a new FloatBuffer of an appropriate size to hold the specified
520- * number of Vector2f object data.
521- *
522- * @param vertices
523- * number of vertices that need to be held by the newly created
524- * buffer
525- * @return the requested new FloatBuffer
526- */
527- public static FloatBuffer createVector2Buffer(int vertices) {
528- FloatBuffer vBuff = createFloatBuffer(2 * vertices);
529- return vBuff;
530- }
531-
532- /**
533- * Create a new FloatBuffer of an appropriate size to hold the specified
534- * number of Vector2f object data only if the given buffer if not already
535- * the right size.
536- *
537- * @param buf
538- * the buffer to first check and rewind
539- * @param vertices
540- * number of vertices that need to be held by the newly created
541- * buffer
542- * @return the requested new FloatBuffer
543- */
544- public static FloatBuffer createVector2Buffer(FloatBuffer buf, int vertices) {
545- if (buf != null && buf.limit() == 2 * vertices) {
546- buf.rewind();
547- return buf;
548- }
549-
550- return createFloatBuffer(2 * vertices);
551- }
552-
553- /**
554- * Sets the data contained in the given Vector2F into the FloatBuffer at the
555- * specified index.
556- *
557- * @param vector
558- * the data to insert
559- * @param buf
560- * the buffer to insert into
561- * @param index
562- * the postion to place the data; in terms of vectors not floats
563- */
564- public static void setInBuffer(Vector2f vector, FloatBuffer buf, int index) {
565- buf.put(index * 2, vector.x);
566- buf.put((index * 2) + 1, vector.y);
567- }
568-
569- /**
570- * Updates the values of the given vector from the specified buffer at the
571- * index provided.
572- *
573- * @param vector
574- * the vector to set data on
575- * @param buf
576- * the buffer to read from
577- * @param index
578- * the position (in terms of vectors, not floats) to read from
579- * the buf
580- */
581- public static void populateFromBuffer(Vector2f vector, FloatBuffer buf, int index) {
582- vector.x = buf.get(index * 2);
583- vector.y = buf.get(index * 2 + 1);
584- }
585-
586- /**
587- * Generates a Vector2f array from the given FloatBuffer.
588- *
589- * @param buff
590- * the FloatBuffer to read from
591- * @return a newly generated array of Vector2f objects
592- */
593- public static Vector2f[] getVector2Array(FloatBuffer buff) {
594- buff.clear();
595- Vector2f[] verts = new Vector2f[buff.limit() / 2];
596- for (int x = 0; x < verts.length; x++) {
597- Vector2f v = new Vector2f(buff.get(), buff.get());
598- verts[x] = v;
599- }
600- return verts;
601- }
602-
603- /**
604- * Copies a Vector2f from one position in the buffer to another. The index
605- * values are in terms of vector number (eg, vector number 0 is postions 0-1
606- * in the FloatBuffer.)
607- *
608- * @param buf
609- * the buffer to copy from/to
610- * @param fromPos
611- * the index of the vector to copy
612- * @param toPos
613- * the index to copy the vector to
614- */
615- public static void copyInternalVector2(FloatBuffer buf, int fromPos, int toPos) {
616- copyInternal(buf, fromPos * 2, toPos * 2, 2);
617- }
618-
619- /**
620- * Normalize a Vector2f in-buffer.
621- *
622- * @param buf
623- * the buffer to find the Vector2f within
624- * @param index
625- * the position (in terms of vectors, not floats) of the vector
626- * to normalize
627- */
628- public static void normalizeVector2(FloatBuffer buf, int index) {
629- TempVars vars = TempVars.get();
630- Vector2f tempVec2 = vars.vect2d;
631- populateFromBuffer(tempVec2, buf, index);
632- tempVec2.normalizeLocal();
633- setInBuffer(tempVec2, buf, index);
634- vars.release();
635- }
636-
637- /**
638- * Add to a Vector2f in-buffer.
639- *
640- * @param toAdd
641- * the vector to add from
642- * @param buf
643- * the buffer to find the Vector2f within
644- * @param index
645- * the position (in terms of vectors, not floats) of the vector
646- * to add to
647- */
648- public static void addInBuffer(Vector2f toAdd, FloatBuffer buf, int index) {
649- TempVars vars = TempVars.get();
650- Vector2f tempVec2 = vars.vect2d;
651- populateFromBuffer(tempVec2, buf, index);
652- tempVec2.addLocal(toAdd);
653- setInBuffer(tempVec2, buf, index);
654- vars.release();
655- }
656-
657- /**
658- * Multiply and store a Vector2f in-buffer.
659- *
660- * @param toMult
661- * the vector to multiply against
662- * @param buf
663- * the buffer to find the Vector2f within
664- * @param index
665- * the position (in terms of vectors, not floats) of the vector
666- * to multiply
667- */
668- public static void multInBuffer(Vector2f toMult, FloatBuffer buf, int index) {
669- TempVars vars = TempVars.get();
670- Vector2f tempVec2 = vars.vect2d;
671- populateFromBuffer(tempVec2, buf, index);
672- tempVec2.multLocal(toMult);
673- setInBuffer(tempVec2, buf, index);
674- vars.release();
675- }
676-
677- /**
678- * Checks to see if the given Vector2f is equals to the data stored in the
679- * buffer at the given data index.
680- *
681- * @param check
682- * the vector to check against - null will return false.
683- * @param buf
684- * the buffer to compare data with
685- * @param index
686- * the position (in terms of vectors, not floats) of the vector
687- * in the buffer to check against
688- * @return true if the data is equivalent, otherwise false.
689- */
690- public static boolean equals(Vector2f check, FloatBuffer buf, int index) {
691- TempVars vars = TempVars.get();
692- Vector2f tempVec2 = vars.vect2d;
693- populateFromBuffer(tempVec2, buf, index);
694- boolean eq = tempVec2.equals(check);
695- vars.release();
696- return eq;
697- }
698-
699- //// -- INT METHODS -- ////
700- /**
701- * Generate a new IntBuffer using the given array of ints. The IntBuffer
702- * will be data.length long and contain the int data as data[0], data[1]...
703- * etc.
704- *
705- * @param data
706- * array of ints to place into a new IntBuffer
707- */
708- public static IntBuffer createIntBuffer(int... data) {
709- if (data == null) {
710- return null;
711- }
712- IntBuffer buff = createIntBuffer(data.length);
713- buff.clear();
714- buff.put(data);
715- buff.flip();
716- return buff;
717- }
718-
719- /**
720- * Create a new int[] array and populate it with the given IntBuffer's
721- * contents.
722- *
723- * @param buff
724- * the IntBuffer to read from
725- * @return a new int array populated from the IntBuffer
726- */
727- public static int[] getIntArray(IntBuffer buff) {
728- if (buff == null) {
729- return null;
730- }
731- buff.clear();
732- int[] inds = new int[buff.limit()];
733- for (int x = 0; x < inds.length; x++) {
734- inds[x] = buff.get();
735- }
736- return inds;
737- }
738-
739- /**
740- * Create a new float[] array and populate it with the given FloatBuffer's
741- * contents.
742- *
743- * @param buff
744- * the FloatBuffer to read from
745- * @return a new float array populated from the FloatBuffer
746- */
747- public static float[] getFloatArray(FloatBuffer buff) {
748- if (buff == null) {
749- return null;
750- }
751- buff.clear();
752- float[] inds = new float[buff.limit()];
753- for (int x = 0; x < inds.length; x++) {
754- inds[x] = buff.get();
755- }
756- return inds;
757- }
758-
759- //// -- GENERAL DOUBLE ROUTINES -- ////
760- /**
761- * Create a new DoubleBuffer of the specified size.
762- *
763- * @param size
764- * required number of double to store.
765- * @return the new DoubleBuffer
766- */
767- public static DoubleBuffer createDoubleBuffer(int size) {
768- DoubleBuffer buf = ByteBuffer.allocateDirect(8 * size).order(ByteOrder.nativeOrder()).asDoubleBuffer();
769- buf.clear();
770- onBufferAllocated(buf);
771- return buf;
772- }
773-
774- /**
775- * Create a new DoubleBuffer of an appropriate size to hold the specified
776- * number of doubles only if the given buffer if not already the right size.
777- *
778- * @param buf
779- * the buffer to first check and rewind
780- * @param size
781- * number of doubles that need to be held by the newly created
782- * buffer
783- * @return the requested new DoubleBuffer
784- */
785- public static DoubleBuffer createDoubleBuffer(DoubleBuffer buf, int size) {
786- if (buf != null && buf.limit() == size) {
787- buf.rewind();
788- return buf;
789- }
790-
791- buf = createDoubleBuffer(size);
792- return buf;
793- }
794-
795- /**
796- * Creates a new DoubleBuffer with the same contents as the given
797- * DoubleBuffer. The new DoubleBuffer is seperate from the old one and
798- * changes are not reflected across. If you want to reflect changes,
799- * consider using Buffer.duplicate().
800- *
801- * @param buf
802- * the DoubleBuffer to copy
803- * @return the copy
804- */
805- public static DoubleBuffer clone(DoubleBuffer buf) {
806- if (buf == null) {
807- return null;
808- }
809- buf.rewind();
810-
811- DoubleBuffer copy;
812- if (isDirect(buf)) {
813- copy = createDoubleBuffer(buf.limit());
814- } else {
815- copy = DoubleBuffer.allocate(buf.limit());
816- }
817- copy.put(buf);
818-
819- return copy;
820- }
821-
822- //// -- GENERAL FLOAT ROUTINES -- ////
823- /**
824- * Create a new FloatBuffer of the specified size.
825- *
826- * @param size
827- * required number of floats to store.
828- * @return the new FloatBuffer
829- */
830- public static FloatBuffer createFloatBuffer(int size) {
831- FloatBuffer buf = ByteBuffer.allocateDirect(4 * size).order(ByteOrder.nativeOrder()).asFloatBuffer();
832- buf.clear();
833- onBufferAllocated(buf);
834- return buf;
835- }
836-
837- /**
838- * Copies floats from one position in the buffer to another.
839- *
840- * @param buf
841- * the buffer to copy from/to
842- * @param fromPos
843- * the starting point to copy from
844- * @param toPos
845- * the starting point to copy to
846- * @param length
847- * the number of floats to copy
848- */
849- public static void copyInternal(FloatBuffer buf, int fromPos, int toPos, int length) {
850- float[] data = new float[length];
851- buf.position(fromPos);
852- buf.get(data);
853- buf.position(toPos);
854- buf.put(data);
855- }
856-
857- /**
858- * Creates a new FloatBuffer with the same contents as the given
859- * FloatBuffer. The new FloatBuffer is seperate from the old one and changes
860- * are not reflected across. If you want to reflect changes, consider using
861- * Buffer.duplicate().
862- *
863- * @param buf
864- * the FloatBuffer to copy
865- * @return the copy
866- */
867- public static FloatBuffer clone(FloatBuffer buf) {
868- if (buf == null) {
869- return null;
870- }
871- buf.rewind();
872-
873- FloatBuffer copy;
874- if (isDirect(buf)) {
875- copy = createFloatBuffer(buf.limit());
876- } else {
877- copy = FloatBuffer.allocate(buf.limit());
878- }
879- copy.put(buf);
880-
881- return copy;
882- }
883-
884- //// -- GENERAL INT ROUTINES -- ////
885- /**
886- * Create a new IntBuffer of the specified size.
887- *
888- * @param size
889- * required number of ints to store.
890- * @return the new IntBuffer
891- */
892- public static IntBuffer createIntBuffer(int size) {
893- IntBuffer buf = ByteBuffer.allocateDirect(4 * size).order(ByteOrder.nativeOrder()).asIntBuffer();
894- buf.clear();
895- onBufferAllocated(buf);
896- return buf;
897- }
898-
899- /**
900- * Create a new IntBuffer of an appropriate size to hold the specified
901- * number of ints only if the given buffer if not already the right size.
902- *
903- * @param buf
904- * the buffer to first check and rewind
905- * @param size
906- * number of ints that need to be held by the newly created
907- * buffer
908- * @return the requested new IntBuffer
909- */
910- public static IntBuffer createIntBuffer(IntBuffer buf, int size) {
911- if (buf != null && buf.limit() == size) {
912- buf.rewind();
913- return buf;
914- }
915-
916- buf = createIntBuffer(size);
917- return buf;
918- }
919-
920- /**
921- * Creates a new IntBuffer with the same contents as the given IntBuffer.
922- * The new IntBuffer is seperate from the old one and changes are not
923- * reflected across. If you want to reflect changes, consider using
924- * Buffer.duplicate().
925- *
926- * @param buf
927- * the IntBuffer to copy
928- * @return the copy
929- */
930- public static IntBuffer clone(IntBuffer buf) {
931- if (buf == null) {
932- return null;
933- }
934- buf.rewind();
935-
936- IntBuffer copy;
937- if (isDirect(buf)) {
938- copy = createIntBuffer(buf.limit());
939- } else {
940- copy = IntBuffer.allocate(buf.limit());
941- }
942- copy.put(buf);
943-
944- return copy;
945- }
946-
947- //// -- GENERAL BYTE ROUTINES -- ////
948- /**
949- * Create a new ByteBuffer of the specified size.
950- *
951- * @param size
952- * required number of ints to store.
953- * @return the new IntBuffer
954- */
955- public static ByteBuffer createByteBuffer(int size) {
956- ByteBuffer buf = ByteBuffer.allocateDirect(size).order(ByteOrder.nativeOrder());
957- buf.clear();
958- onBufferAllocated(buf);
959- return buf;
960- }
961-
962- /**
963- * Create a new ByteBuffer of an appropriate size to hold the specified
964- * number of ints only if the given buffer if not already the right size.
965- *
966- * @param buf
967- * the buffer to first check and rewind
968- * @param size
969- * number of bytes that need to be held by the newly created
970- * buffer
971- * @return the requested new IntBuffer
972- */
973- public static ByteBuffer createByteBuffer(ByteBuffer buf, int size) {
974- if (buf != null && buf.limit() == size) {
975- buf.rewind();
976- return buf;
977- }
978-
979- buf = createByteBuffer(size);
980- return buf;
981- }
982-
983- public static ByteBuffer createByteBuffer(byte... data) {
984- ByteBuffer bb = createByteBuffer(data.length);
985- bb.put(data);
986- bb.flip();
987- return bb;
988- }
989-
990- public static ByteBuffer createByteBuffer(String data) {
991- byte[] bytes = data.getBytes();
992- ByteBuffer bb = createByteBuffer(bytes.length);
993- bb.put(bytes);
994- bb.flip();
995- return bb;
996- }
997-
998- /**
999- * Creates a new ByteBuffer with the same contents as the given ByteBuffer.
1000- * The new ByteBuffer is seperate from the old one and changes are not
1001- * reflected across. If you want to reflect changes, consider using
1002- * Buffer.duplicate().
1003- *
1004- * @param buf
1005- * the ByteBuffer to copy
1006- * @return the copy
1007- */
1008- public static ByteBuffer clone(ByteBuffer buf) {
1009- if (buf == null) {
1010- return null;
1011- }
1012- buf.rewind();
1013-
1014- ByteBuffer copy;
1015- if (isDirect(buf)) {
1016- copy = createByteBuffer(buf.limit());
1017- } else {
1018- copy = ByteBuffer.allocate(buf.limit());
1019- }
1020- copy.put(buf);
1021-
1022- return copy;
1023- }
1024-
1025- //// -- GENERAL SHORT ROUTINES -- ////
1026- /**
1027- * Create a new ShortBuffer of the specified size.
1028- *
1029- * @param size
1030- * required number of shorts to store.
1031- * @return the new ShortBuffer
1032- */
1033- public static ShortBuffer createShortBuffer(int size) {
1034- ShortBuffer buf = ByteBuffer.allocateDirect(2 * size).order(ByteOrder.nativeOrder()).asShortBuffer();
1035- buf.clear();
1036- onBufferAllocated(buf);
1037- return buf;
1038- }
1039-
1040- /**
1041- * Create a new ShortBuffer of an appropriate size to hold the specified
1042- * number of shorts only if the given buffer if not already the right size.
1043- *
1044- * @param buf
1045- * the buffer to first check and rewind
1046- * @param size
1047- * number of shorts that need to be held by the newly created
1048- * buffer
1049- * @return the requested new ShortBuffer
1050- */
1051- public static ShortBuffer createShortBuffer(ShortBuffer buf, int size) {
1052- if (buf != null && buf.limit() == size) {
1053- buf.rewind();
1054- return buf;
1055- }
1056-
1057- buf = createShortBuffer(size);
1058- return buf;
1059- }
1060-
1061- public static ShortBuffer createShortBuffer(short... data) {
1062- if (data == null) {
1063- return null;
1064- }
1065- ShortBuffer buff = createShortBuffer(data.length);
1066- buff.clear();
1067- buff.put(data);
1068- buff.flip();
1069- return buff;
1070- }
1071-
1072- /**
1073- * Creates a new ShortBuffer with the same contents as the given ShortBuffer.
1074- * The new ShortBuffer is seperate from the old one and changes are not
1075- * reflected across. If you want to reflect changes, consider using
1076- * Buffer.duplicate().
1077- *
1078- * @param buf
1079- * the ShortBuffer to copy
1080- * @return the copy
1081- */
1082- public static ShortBuffer clone(ShortBuffer buf) {
1083- if (buf == null) {
1084- return null;
1085- }
1086- buf.rewind();
1087-
1088- ShortBuffer copy;
1089- if (isDirect(buf)) {
1090- copy = createShortBuffer(buf.limit());
1091- } else {
1092- copy = ShortBuffer.allocate(buf.limit());
1093- }
1094- copy.put(buf);
1095-
1096- return copy;
1097- }
1098-
1099- /**
1100- * Ensures there is at least the <code>required</code> number of entries left after the current position of the
1101- * buffer. If the buffer is too small a larger one is created and the old one copied to the new buffer.
1102- * @param buffer buffer that should be checked/copied (may be null)
1103- * @param required minimum number of elements that should be remaining in the returned buffer
1104- * @return a buffer large enough to receive at least the <code>required</code> number of entries, same position as
1105- * the input buffer, not null
1106- */
1107- public static FloatBuffer ensureLargeEnough(FloatBuffer buffer, int required) {
1108- if (buffer != null) {
1109- buffer.limit(buffer.capacity());
1110- }
1111- if (buffer == null || (buffer.remaining() < required)) {
1112- int position = (buffer != null ? buffer.position() : 0);
1113- FloatBuffer newVerts = createFloatBuffer(position + required);
1114- if (buffer != null) {
1115- buffer.flip();
1116- newVerts.put(buffer);
1117- newVerts.position(position);
1118- }
1119- buffer = newVerts;
1120- }
1121- return buffer;
1122- }
1123-
1124- public static ShortBuffer ensureLargeEnough(ShortBuffer buffer, int required) {
1125- if (buffer != null) {
1126- buffer.limit(buffer.capacity());
1127- }
1128- if (buffer == null || (buffer.remaining() < required)) {
1129- int position = (buffer != null ? buffer.position() : 0);
1130- ShortBuffer newVerts = createShortBuffer(position + required);
1131- if (buffer != null) {
1132- buffer.flip();
1133- newVerts.put(buffer);
1134- newVerts.position(position);
1135- }
1136- buffer = newVerts;
1137- }
1138- return buffer;
1139- }
1140-
1141- public static ByteBuffer ensureLargeEnough(ByteBuffer buffer, int required) {
1142- if (buffer != null) {
1143- buffer.limit(buffer.capacity());
1144- }
1145- if (buffer == null || (buffer.remaining() < required)) {
1146- int position = (buffer != null ? buffer.position() : 0);
1147- ByteBuffer newVerts = createByteBuffer(position + required);
1148- if (buffer != null) {
1149- buffer.flip();
1150- newVerts.put(buffer);
1151- newVerts.position(position);
1152- }
1153- buffer = newVerts;
1154- }
1155- return buffer;
1156- }
1157-
1158- public static void printCurrentDirectMemory(StringBuilder store) {
1159- long totalHeld = 0;
1160- long heapMem = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
1161-
1162- boolean printStout = store == null;
1163- if (store == null) {
1164- store = new StringBuilder();
1165- }
1166- if (trackDirectMemory) {
1167- // make a new set to hold the keys to prevent concurrency issues.
1168- int fBufs = 0, bBufs = 0, iBufs = 0, sBufs = 0, dBufs = 0;
1169- int fBufsM = 0, bBufsM = 0, iBufsM = 0, sBufsM = 0, dBufsM = 0;
1170- for (BufferInfo b : BufferUtils.trackedBuffers.values()) {
1171- if (b.type == ByteBuffer.class) {
1172- totalHeld += b.size;
1173- bBufsM += b.size;
1174- bBufs++;
1175- } else if (b.type == FloatBuffer.class) {
1176- totalHeld += b.size;
1177- fBufsM += b.size;
1178- fBufs++;
1179- } else if (b.type == IntBuffer.class) {
1180- totalHeld += b.size;
1181- iBufsM += b.size;
1182- iBufs++;
1183- } else if (b.type == ShortBuffer.class) {
1184- totalHeld += b.size;
1185- sBufsM += b.size;
1186- sBufs++;
1187- } else if (b.type == DoubleBuffer.class) {
1188- totalHeld += b.size;
1189- dBufsM += b.size;
1190- dBufs++;
1191- }
1192- }
1193-
1194- store.append("Existing buffers: ").append(BufferUtils.trackedBuffers.size()).append("\n");
1195- store.append("(b: ").append(bBufs).append(" f: ").append(fBufs).append(" i: ").append(iBufs).append(" s: ").append(sBufs).append(" d: ").append(dBufs).append(")").append("\n");
1196- store.append("Total heap memory held: ").append(heapMem / 1024).append("kb\n");
1197- store.append("Total direct memory held: ").append(totalHeld / 1024).append("kb\n");
1198- store.append("(b: ").append(bBufsM / 1024).append("kb f: ").append(fBufsM / 1024).append("kb i: ").append(iBufsM / 1024).append("kb s: ").append(sBufsM / 1024).append("kb d: ").append(dBufsM / 1024).append("kb)").append("\n");
1199- } else {
1200- store.append("Total heap memory held: ").append(heapMem / 1024).append("kb\n");
1201- store.append("Only heap memory available, if you want to monitor direct memory use BufferUtils.setTrackDirectMemoryEnabled(true) during initialization.").append("\n");
1202- }
1203- if (printStout) {
1204- System.out.println(store.toString());
1205- }
1206- }
1207- private static final AtomicBoolean loadedMethods = new AtomicBoolean(false);
1208- private static Method cleanerMethod = null;
1209- private static Method cleanMethod = null;
1210- private static Method viewedBufferMethod = null;
1211- private static Method freeMethod = null;
1212-
1213- private static Method loadMethod(String className, String methodName) {
1214- try {
1215- Method method = Class.forName(className).getMethod(methodName);
1216- method.setAccessible(true);
1217- return method;
1218- } catch (NoSuchMethodException ex) {
1219- return null; // the method was not found
1220- } catch (SecurityException ex) {
1221- return null; // setAccessible not allowed by security policy
1222- } catch (ClassNotFoundException ex) {
1223- return null; // the direct buffer implementation was not found
1224- }
1225- }
1226-
1227- private static void loadCleanerMethods() {
1228- // If its already true, exit, if not, set it to true.
1229- if (BufferUtils.loadedMethods.getAndSet(true)) {
1230- return;
1231- }
1232- // This could potentially be called many times if used from multiple
1233- // threads
1234- synchronized (BufferUtils.loadedMethods) {
1235- // Oracle JRE / OpenJDK
1236- cleanerMethod = loadMethod("sun.nio.ch.DirectBuffer", "cleaner");
1237- cleanMethod = loadMethod("sun.misc.Cleaner", "clean");
1238- viewedBufferMethod = loadMethod("sun.nio.ch.DirectBuffer", "viewedBuffer");
1239- if (viewedBufferMethod == null) {
1240- // They changed the name in Java 7 (???)
1241- viewedBufferMethod = loadMethod("sun.nio.ch.DirectBuffer", "attachment");
1242- }
1243-
1244- // Apache Harmony
1245- ByteBuffer bb = BufferUtils.createByteBuffer(1);
1246- Class<?> clazz = bb.getClass();
1247- try {
1248- freeMethod = clazz.getMethod("free");
1249- } catch (NoSuchMethodException ex) {
1250- } catch (SecurityException ex) {
1251- }
1252- }
1253- }
1254-
1255- /**
1256- * Direct buffers are garbage collected by using a phantom reference and a
1257- * reference queue. Every once a while, the JVM checks the reference queue and
1258- * cleans the direct buffers. However, as this doesn't happen
1259- * immediately after discarding all references to a direct buffer, it's
1260- * easy to OutOfMemoryError yourself using direct buffers. This function
1261- * explicitly calls the Cleaner method of a direct buffer.
1262- *
1263- * @param toBeDestroyed
1264- * The direct buffer that will be "cleaned". Utilizes reflection.
1265- *
1266- */
1267- public static void destroyDirectBuffer(Buffer toBeDestroyed) {
1268- if (!isDirect(toBeDestroyed)) {
1269- return;
1270- }
1271-
1272- BufferUtils.loadCleanerMethods();
1273-
1274- try {
1275- if (freeMethod != null) {
1276- freeMethod.invoke(toBeDestroyed);
1277- } else {
1278- Object cleaner = cleanerMethod.invoke(toBeDestroyed);
1279- if (cleaner != null) {
1280- cleanMethod.invoke(cleaner);
1281- } else {
1282- // Try the alternate approach of getting the viewed buffer first
1283- Object viewedBuffer = viewedBufferMethod.invoke(toBeDestroyed);
1284- if (viewedBuffer != null) {
1285- destroyDirectBuffer((Buffer) viewedBuffer);
1286- } else {
1287- Logger.getLogger(BufferUtils.class.getName()).log(Level.SEVERE, "Buffer cannot be destroyed: {0}", toBeDestroyed);
1288- }
1289- }
1290- }
1291- } catch (IllegalAccessException ex) {
1292- Logger.getLogger(BufferUtils.class.getName()).log(Level.SEVERE, "{0}", ex);
1293- } catch (IllegalArgumentException ex) {
1294- Logger.getLogger(BufferUtils.class.getName()).log(Level.SEVERE, "{0}", ex);
1295- } catch (InvocationTargetException ex) {
1296- Logger.getLogger(BufferUtils.class.getName()).log(Level.SEVERE, "{0}", ex);
1297- } catch (SecurityException ex) {
1298- Logger.getLogger(BufferUtils.class.getName()).log(Level.SEVERE, "{0}", ex);
1299- }
1300- }
1301-
1302- /*
1303- * FIXME when java 1.5 supprt is dropped - replace calls to this method with Buffer.isDirect
1304- *
1305- * Buffer.isDirect() is only java 6. Java 5 only have this method on Buffer subclasses :
1306- * FloatBuffer, IntBuffer, ShortBuffer, ByteBuffer,DoubleBuffer, LongBuffer.
1307- * CharBuffer has been excluded as we don't use it.
1308- *
1309- */
1310- private static boolean isDirect(Buffer buf) {
1311- if (buf instanceof FloatBuffer) {
1312- return ((FloatBuffer) buf).isDirect();
1313- }
1314- if (buf instanceof IntBuffer) {
1315- return ((IntBuffer) buf).isDirect();
1316- }
1317- if (buf instanceof ShortBuffer) {
1318- return ((ShortBuffer) buf).isDirect();
1319- }
1320- if (buf instanceof ByteBuffer) {
1321- return ((ByteBuffer) buf).isDirect();
1322- }
1323- if (buf instanceof DoubleBuffer) {
1324- return ((DoubleBuffer) buf).isDirect();
1325- }
1326- if (buf instanceof LongBuffer) {
1327- return ((LongBuffer) buf).isDirect();
1328- }
1329- throw new UnsupportedOperationException(" BufferUtils.isDirect was called on " + buf.getClass().getName());
1330- }
1331-
1332- private static class BufferInfo extends PhantomReference<Buffer> {
1333-
1334- private Class type;
1335- private int size;
1336-
1337- public BufferInfo(Class type, int size, Buffer referent, ReferenceQueue<? super Buffer> q) {
1338- super(referent, q);
1339- this.type = type;
1340- this.size = size;
1341- }
1342- }
1343-
1344- private static class ClearReferences extends Thread {
1345-
1346- ClearReferences() {
1347- this.setDaemon(true);
1348- }
1349-
1350- @Override
1351- public void run() {
1352- try {
1353- while (true) {
1354- Reference<? extends Buffer> toclean = BufferUtils.removeCollected.remove();
1355- BufferUtils.trackedBuffers.remove(toclean);
1356- }
1357-
1358- } catch (InterruptedException e) {
1359- e.printStackTrace();
1360- }
1361- }
1362- }
1363-}
\ No newline at end of file
1+/*
2+ * Copyright (c) 2009-2012 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+package com.jme3.util;
33+
34+import com.jme3.math.ColorRGBA;
35+import com.jme3.math.Quaternion;
36+import com.jme3.math.Vector2f;
37+import com.jme3.math.Vector3f;
38+import com.jme3.math.Vector4f;
39+import java.lang.ref.PhantomReference;
40+import java.lang.ref.Reference;
41+import java.lang.ref.ReferenceQueue;
42+import java.lang.reflect.InvocationTargetException;
43+import java.lang.reflect.Method;
44+import java.nio.Buffer;
45+import java.nio.ByteBuffer;
46+import java.nio.ByteOrder;
47+import java.nio.DoubleBuffer;
48+import java.nio.FloatBuffer;
49+import java.nio.IntBuffer;
50+import java.nio.LongBuffer;
51+import java.nio.ShortBuffer;
52+import java.util.concurrent.ConcurrentHashMap;
53+import java.util.concurrent.atomic.AtomicBoolean;
54+import java.util.logging.Level;
55+import java.util.logging.Logger;
56+
57+/**
58+ * <code>BufferUtils</code> is a helper class for generating nio buffers from
59+ * jME data classes such as Vectors and ColorRGBA.
60+ *
61+ * @author Joshua Slack
62+ * @version $Id: BufferUtils.java,v 1.16 2007/10/29 16:56:18 nca Exp $
63+ */
64+public final class BufferUtils {
65+
66+ private static boolean trackDirectMemory = false;
67+ private static ReferenceQueue<Buffer> removeCollected = new ReferenceQueue<Buffer>();
68+ private static ConcurrentHashMap<BufferInfo, BufferInfo> trackedBuffers = new ConcurrentHashMap<BufferInfo, BufferInfo>();
69+ static ClearReferences cleanupthread;
70+
71+ /**
72+ * Set it to true if you want to enable direct memory tracking for debugging purpose.
73+ * Default is false.
74+ * To print direct memory usage use BufferUtils.printCurrentDirectMemory(StringBuilder store);
75+ * @param enabled
76+ */
77+ public static void setTrackDirectMemoryEnabled(boolean enabled) {
78+ trackDirectMemory = enabled;
79+ }
80+
81+ /**
82+ * Creates a clone of the given buffer. The clone's capacity is
83+ * equal to the given buffer's limit.
84+ *
85+ * @param buf The buffer to clone
86+ * @return The cloned buffer
87+ */
88+ public static Buffer clone(Buffer buf) {
89+ if (buf instanceof FloatBuffer) {
90+ return clone((FloatBuffer) buf);
91+ } else if (buf instanceof ShortBuffer) {
92+ return clone((ShortBuffer) buf);
93+ } else if (buf instanceof ByteBuffer) {
94+ return clone((ByteBuffer) buf);
95+ } else if (buf instanceof IntBuffer) {
96+ return clone((IntBuffer) buf);
97+ } else if (buf instanceof DoubleBuffer) {
98+ return clone((DoubleBuffer) buf);
99+ } else {
100+ throw new UnsupportedOperationException();
101+ }
102+ }
103+
104+ private static void onBufferAllocated(Buffer buffer) {
105+ /**
106+ * StackTraceElement[] stackTrace = new Throwable().getStackTrace(); int
107+ * initialIndex = 0;
108+ *
109+ * for (int i = 0; i < stackTrace.length; i++){ if
110+ * (!stackTrace[i].getClassName().equals(BufferUtils.class.getName())){
111+ * initialIndex = i; break; } }
112+ *
113+ * int allocated = buffer.capacity(); int size = 0;
114+ *
115+ * if (buffer instanceof FloatBuffer){ size = 4; }else if (buffer
116+ * instanceof ShortBuffer){ size = 2; }else if (buffer instanceof
117+ * ByteBuffer){ size = 1; }else if (buffer instanceof IntBuffer){ size =
118+ * 4; }else if (buffer instanceof DoubleBuffer){ size = 8; }
119+ *
120+ * allocated *= size;
121+ *
122+ * for (int i = initialIndex; i < stackTrace.length; i++){
123+ * StackTraceElement element = stackTrace[i]; if
124+ * (element.getClassName().startsWith("java")){ break; }
125+ *
126+ * try { Class clazz = Class.forName(element.getClassName()); if (i ==
127+ * initialIndex){
128+ * System.out.println(clazz.getSimpleName()+"."+element.getMethodName
129+ * ()+"():" + element.getLineNumber() + " allocated " + allocated);
130+ * }else{ System.out.println(" at " +
131+ * clazz.getSimpleName()+"."+element.getMethodName()+"()"); } } catch
132+ * (ClassNotFoundException ex) { } }
133+ */
134+ if (BufferUtils.trackDirectMemory) {
135+
136+ if (BufferUtils.cleanupthread == null) {
137+ BufferUtils.cleanupthread = new ClearReferences();
138+ BufferUtils.cleanupthread.start();
139+ }
140+ if (buffer instanceof ByteBuffer) {
141+ BufferInfo info = new BufferInfo(ByteBuffer.class, buffer.capacity(), buffer, BufferUtils.removeCollected);
142+ BufferUtils.trackedBuffers.put(info, info);
143+ } else if (buffer instanceof FloatBuffer) {
144+ BufferInfo info = new BufferInfo(FloatBuffer.class, buffer.capacity() * 4, buffer, BufferUtils.removeCollected);
145+ BufferUtils.trackedBuffers.put(info, info);
146+ } else if (buffer instanceof IntBuffer) {
147+ BufferInfo info = new BufferInfo(IntBuffer.class, buffer.capacity() * 4, buffer, BufferUtils.removeCollected);
148+ BufferUtils.trackedBuffers.put(info, info);
149+ } else if (buffer instanceof ShortBuffer) {
150+ BufferInfo info = new BufferInfo(ShortBuffer.class, buffer.capacity() * 2, buffer, BufferUtils.removeCollected);
151+ BufferUtils.trackedBuffers.put(info, info);
152+ } else if (buffer instanceof DoubleBuffer) {
153+ BufferInfo info = new BufferInfo(DoubleBuffer.class, buffer.capacity() * 8, buffer, BufferUtils.removeCollected);
154+ BufferUtils.trackedBuffers.put(info, info);
155+ }
156+
157+ }
158+ }
159+
160+ /**
161+ * Generate a new FloatBuffer using the given array of Vector3f objects.
162+ * The FloatBuffer will be 3 * data.length long and contain the vector data
163+ * as data[0].x, data[0].y, data[0].z, data[1].x... etc.
164+ *
165+ * @param data array of Vector3f objects to place into a new FloatBuffer
166+ */
167+ public static FloatBuffer createFloatBuffer(Vector3f... data) {
168+ if (data == null) {
169+ return null;
170+ }
171+ FloatBuffer buff = createFloatBuffer(3 * data.length);
172+ for (Vector3f element : data) {
173+ if (element != null) {
174+ buff.put(element.x).put(element.y).put(element.z);
175+ } else {
176+ buff.put(0).put(0).put(0);
177+ }
178+ }
179+ buff.flip();
180+ return buff;
181+ }
182+
183+ /**
184+ * Generate a new FloatBuffer using the given array of Quaternion objects.
185+ * The FloatBuffer will be 4 * data.length long and contain the vector data.
186+ *
187+ * @param data array of Quaternion objects to place into a new FloatBuffer
188+ */
189+ public static FloatBuffer createFloatBuffer(Quaternion... data) {
190+ if (data == null) {
191+ return null;
192+ }
193+ FloatBuffer buff = createFloatBuffer(4 * data.length);
194+ for (Quaternion element : data) {
195+ if (element != null) {
196+ buff.put(element.getX()).put(element.getY()).put(element.getZ()).put(element.getW());
197+ } else {
198+ buff.put(0).put(0).put(0).put(0);
199+ }
200+ }
201+ buff.flip();
202+ return buff;
203+ }
204+
205+ /**
206+ * Generate a new FloatBuffer using the given array of Vector4 objects.
207+ * The FloatBuffer will be 4 * data.length long and contain the vector data.
208+ *
209+ * @param data array of Vector4 objects to place into a new FloatBuffer
210+ */
211+ public static FloatBuffer createFloatBuffer(Vector4f... data) {
212+ if (data == null) {
213+ return null;
214+ }
215+ FloatBuffer buff = createFloatBuffer(4 * data.length);
216+ for (int x = 0; x < data.length; x++) {
217+ if (data[x] != null) {
218+ buff.put(data[x].getX()).put(data[x].getY()).put(data[x].getZ()).put(data[x].getW());
219+ } else {
220+ buff.put(0).put(0).put(0).put(0);
221+ }
222+ }
223+ buff.flip();
224+ return buff;
225+ }
226+
227+ /**
228+ * Generate a new FloatBuffer using the given array of float primitives.
229+ * @param data array of float primitives to place into a new FloatBuffer
230+ */
231+ public static FloatBuffer createFloatBuffer(float... data) {
232+ if (data == null) {
233+ return null;
234+ }
235+ FloatBuffer buff = createFloatBuffer(data.length);
236+ buff.clear();
237+ buff.put(data);
238+ buff.flip();
239+ return buff;
240+ }
241+
242+ /**
243+ * Create a new FloatBuffer of an appropriate size to hold the specified
244+ * number of Vector3f object data.
245+ *
246+ * @param vertices
247+ * number of vertices that need to be held by the newly created
248+ * buffer
249+ * @return the requested new FloatBuffer
250+ */
251+ public static FloatBuffer createVector3Buffer(int vertices) {
252+ FloatBuffer vBuff = createFloatBuffer(3 * vertices);
253+ return vBuff;
254+ }
255+
256+ /**
257+ * Create a new FloatBuffer of an appropriate size to hold the specified
258+ * number of Vector3f object data only if the given buffer if not already
259+ * the right size.
260+ *
261+ * @param buf
262+ * the buffer to first check and rewind
263+ * @param vertices
264+ * number of vertices that need to be held by the newly created
265+ * buffer
266+ * @return the requested new FloatBuffer
267+ */
268+ public static FloatBuffer createVector3Buffer(FloatBuffer buf, int vertices) {
269+ if (buf != null && buf.limit() == 3 * vertices) {
270+ buf.rewind();
271+ return buf;
272+ }
273+
274+ return createFloatBuffer(3 * vertices);
275+ }
276+
277+ /**
278+ * Sets the data contained in the given color into the FloatBuffer at the
279+ * specified index.
280+ *
281+ * @param color
282+ * the data to insert
283+ * @param buf
284+ * the buffer to insert into
285+ * @param index
286+ * the postion to place the data; in terms of colors not floats
287+ */
288+ public static void setInBuffer(ColorRGBA color, FloatBuffer buf,
289+ int index) {
290+ buf.position(index * 4);
291+ buf.put(color.r);
292+ buf.put(color.g);
293+ buf.put(color.b);
294+ buf.put(color.a);
295+ }
296+
297+ /**
298+ * Sets the data contained in the given quaternion into the FloatBuffer at the
299+ * specified index.
300+ *
301+ * @param quat
302+ * the {@link Quaternion} to insert
303+ * @param buf
304+ * the buffer to insert into
305+ * @param index
306+ * the postion to place the data; in terms of quaternions not floats
307+ */
308+ public static void setInBuffer(Quaternion quat, FloatBuffer buf,
309+ int index) {
310+ buf.position(index * 4);
311+ buf.put(quat.getX());
312+ buf.put(quat.getY());
313+ buf.put(quat.getZ());
314+ buf.put(quat.getW());
315+ }
316+
317+ /**
318+ * Sets the data contained in the given vector4 into the FloatBuffer at the
319+ * specified index.
320+ *
321+ * @param vec
322+ * the {@link Vector4f} to insert
323+ * @param buf
324+ * the buffer to insert into
325+ * @param index
326+ * the postion to place the data; in terms of vector4 not floats
327+ */
328+ public static void setInBuffer(Vector4f vec, FloatBuffer buf,
329+ int index) {
330+ buf.position(index * 4);
331+ buf.put(vec.getX());
332+ buf.put(vec.getY());
333+ buf.put(vec.getZ());
334+ buf.put(vec.getW());
335+ }
336+
337+ /**
338+ * Sets the data contained in the given Vector3F into the FloatBuffer at the
339+ * specified index.
340+ *
341+ * @param vector
342+ * the data to insert
343+ * @param buf
344+ * the buffer to insert into
345+ * @param index
346+ * the postion to place the data; in terms of vectors not floats
347+ */
348+ public static void setInBuffer(Vector3f vector, FloatBuffer buf, int index) {
349+ if (buf == null) {
350+ return;
351+ }
352+ if (vector == null) {
353+ buf.put(index * 3, 0);
354+ buf.put((index * 3) + 1, 0);
355+ buf.put((index * 3) + 2, 0);
356+ } else {
357+ buf.put(index * 3, vector.x);
358+ buf.put((index * 3) + 1, vector.y);
359+ buf.put((index * 3) + 2, vector.z);
360+ }
361+ }
362+
363+ /**
364+ * Updates the values of the given vector from the specified buffer at the
365+ * index provided.
366+ *
367+ * @param vector
368+ * the vector to set data on
369+ * @param buf
370+ * the buffer to read from
371+ * @param index
372+ * the position (in terms of vectors, not floats) to read from
373+ * the buf
374+ */
375+ public static void populateFromBuffer(Vector3f vector, FloatBuffer buf, int index) {
376+ vector.x = buf.get(index * 3);
377+ vector.y = buf.get(index * 3 + 1);
378+ vector.z = buf.get(index * 3 + 2);
379+ }
380+
381+ /**
382+ * Generates a Vector3f array from the given FloatBuffer.
383+ *
384+ * @param buff
385+ * the FloatBuffer to read from
386+ * @return a newly generated array of Vector3f objects
387+ */
388+ public static Vector3f[] getVector3Array(FloatBuffer buff) {
389+ buff.clear();
390+ Vector3f[] verts = new Vector3f[buff.limit() / 3];
391+ for (int x = 0; x < verts.length; x++) {
392+ Vector3f v = new Vector3f(buff.get(), buff.get(), buff.get());
393+ verts[x] = v;
394+ }
395+ return verts;
396+ }
397+
398+ /**
399+ * Copies a Vector3f from one position in the buffer to another. The index
400+ * values are in terms of vector number (eg, vector number 0 is postions 0-2
401+ * in the FloatBuffer.)
402+ *
403+ * @param buf
404+ * the buffer to copy from/to
405+ * @param fromPos
406+ * the index of the vector to copy
407+ * @param toPos
408+ * the index to copy the vector to
409+ */
410+ public static void copyInternalVector3(FloatBuffer buf, int fromPos, int toPos) {
411+ copyInternal(buf, fromPos * 3, toPos * 3, 3);
412+ }
413+
414+ /**
415+ * Normalize a Vector3f in-buffer.
416+ *
417+ * @param buf
418+ * the buffer to find the Vector3f within
419+ * @param index
420+ * the position (in terms of vectors, not floats) of the vector
421+ * to normalize
422+ */
423+ public static void normalizeVector3(FloatBuffer buf, int index) {
424+ TempVars vars = TempVars.get();
425+ Vector3f tempVec3 = vars.vect1;
426+ populateFromBuffer(tempVec3, buf, index);
427+ tempVec3.normalizeLocal();
428+ setInBuffer(tempVec3, buf, index);
429+ vars.release();
430+ }
431+
432+ /**
433+ * Add to a Vector3f in-buffer.
434+ *
435+ * @param toAdd
436+ * the vector to add from
437+ * @param buf
438+ * the buffer to find the Vector3f within
439+ * @param index
440+ * the position (in terms of vectors, not floats) of the vector
441+ * to add to
442+ */
443+ public static void addInBuffer(Vector3f toAdd, FloatBuffer buf, int index) {
444+ TempVars vars = TempVars.get();
445+ Vector3f tempVec3 = vars.vect1;
446+ populateFromBuffer(tempVec3, buf, index);
447+ tempVec3.addLocal(toAdd);
448+ setInBuffer(tempVec3, buf, index);
449+ vars.release();
450+ }
451+
452+ /**
453+ * Multiply and store a Vector3f in-buffer.
454+ *
455+ * @param toMult
456+ * the vector to multiply against
457+ * @param buf
458+ * the buffer to find the Vector3f within
459+ * @param index
460+ * the position (in terms of vectors, not floats) of the vector
461+ * to multiply
462+ */
463+ public static void multInBuffer(Vector3f toMult, FloatBuffer buf, int index) {
464+ TempVars vars = TempVars.get();
465+ Vector3f tempVec3 = vars.vect1;
466+ populateFromBuffer(tempVec3, buf, index);
467+ tempVec3.multLocal(toMult);
468+ setInBuffer(tempVec3, buf, index);
469+ vars.release();
470+ }
471+
472+ /**
473+ * Checks to see if the given Vector3f is equals to the data stored in the
474+ * buffer at the given data index.
475+ *
476+ * @param check
477+ * the vector to check against - null will return false.
478+ * @param buf
479+ * the buffer to compare data with
480+ * @param index
481+ * the position (in terms of vectors, not floats) of the vector
482+ * in the buffer to check against
483+ * @return true if the data is equivalent, otherwise false.
484+ */
485+ public static boolean equals(Vector3f check, FloatBuffer buf, int index) {
486+ TempVars vars = TempVars.get();
487+ Vector3f tempVec3 = vars.vect1;
488+ populateFromBuffer(tempVec3, buf, index);
489+ boolean eq = tempVec3.equals(check);
490+ vars.release();
491+ return eq;
492+ }
493+
494+ // // -- VECTOR2F METHODS -- ////
495+ /**
496+ * Generate a new FloatBuffer using the given array of Vector2f objects.
497+ * The FloatBuffer will be 2 * data.length long and contain the vector data
498+ * as data[0].x, data[0].y, data[1].x... etc.
499+ *
500+ * @param data array of Vector2f objects to place into a new FloatBuffer
501+ */
502+ public static FloatBuffer createFloatBuffer(Vector2f... data) {
503+ if (data == null) {
504+ return null;
505+ }
506+ FloatBuffer buff = createFloatBuffer(2 * data.length);
507+ for (Vector2f element : data) {
508+ if (element != null) {
509+ buff.put(element.x).put(element.y);
510+ } else {
511+ buff.put(0).put(0);
512+ }
513+ }
514+ buff.flip();
515+ return buff;
516+ }
517+
518+ /**
519+ * Create a new FloatBuffer of an appropriate size to hold the specified
520+ * number of Vector2f object data.
521+ *
522+ * @param vertices
523+ * number of vertices that need to be held by the newly created
524+ * buffer
525+ * @return the requested new FloatBuffer
526+ */
527+ public static FloatBuffer createVector2Buffer(int vertices) {
528+ FloatBuffer vBuff = createFloatBuffer(2 * vertices);
529+ return vBuff;
530+ }
531+
532+ /**
533+ * Create a new FloatBuffer of an appropriate size to hold the specified
534+ * number of Vector2f object data only if the given buffer if not already
535+ * the right size.
536+ *
537+ * @param buf
538+ * the buffer to first check and rewind
539+ * @param vertices
540+ * number of vertices that need to be held by the newly created
541+ * buffer
542+ * @return the requested new FloatBuffer
543+ */
544+ public static FloatBuffer createVector2Buffer(FloatBuffer buf, int vertices) {
545+ if (buf != null && buf.limit() == 2 * vertices) {
546+ buf.rewind();
547+ return buf;
548+ }
549+
550+ return createFloatBuffer(2 * vertices);
551+ }
552+
553+ /**
554+ * Sets the data contained in the given Vector2F into the FloatBuffer at the
555+ * specified index.
556+ *
557+ * @param vector
558+ * the data to insert
559+ * @param buf
560+ * the buffer to insert into
561+ * @param index
562+ * the postion to place the data; in terms of vectors not floats
563+ */
564+ public static void setInBuffer(Vector2f vector, FloatBuffer buf, int index) {
565+ buf.put(index * 2, vector.x);
566+ buf.put((index * 2) + 1, vector.y);
567+ }
568+
569+ /**
570+ * Updates the values of the given vector from the specified buffer at the
571+ * index provided.
572+ *
573+ * @param vector
574+ * the vector to set data on
575+ * @param buf
576+ * the buffer to read from
577+ * @param index
578+ * the position (in terms of vectors, not floats) to read from
579+ * the buf
580+ */
581+ public static void populateFromBuffer(Vector2f vector, FloatBuffer buf, int index) {
582+ vector.x = buf.get(index * 2);
583+ vector.y = buf.get(index * 2 + 1);
584+ }
585+
586+ /**
587+ * Generates a Vector2f array from the given FloatBuffer.
588+ *
589+ * @param buff
590+ * the FloatBuffer to read from
591+ * @return a newly generated array of Vector2f objects
592+ */
593+ public static Vector2f[] getVector2Array(FloatBuffer buff) {
594+ buff.clear();
595+ Vector2f[] verts = new Vector2f[buff.limit() / 2];
596+ for (int x = 0; x < verts.length; x++) {
597+ Vector2f v = new Vector2f(buff.get(), buff.get());
598+ verts[x] = v;
599+ }
600+ return verts;
601+ }
602+
603+ /**
604+ * Copies a Vector2f from one position in the buffer to another. The index
605+ * values are in terms of vector number (eg, vector number 0 is postions 0-1
606+ * in the FloatBuffer.)
607+ *
608+ * @param buf
609+ * the buffer to copy from/to
610+ * @param fromPos
611+ * the index of the vector to copy
612+ * @param toPos
613+ * the index to copy the vector to
614+ */
615+ public static void copyInternalVector2(FloatBuffer buf, int fromPos, int toPos) {
616+ copyInternal(buf, fromPos * 2, toPos * 2, 2);
617+ }
618+
619+ /**
620+ * Normalize a Vector2f in-buffer.
621+ *
622+ * @param buf
623+ * the buffer to find the Vector2f within
624+ * @param index
625+ * the position (in terms of vectors, not floats) of the vector
626+ * to normalize
627+ */
628+ public static void normalizeVector2(FloatBuffer buf, int index) {
629+ TempVars vars = TempVars.get();
630+ Vector2f tempVec2 = vars.vect2d;
631+ populateFromBuffer(tempVec2, buf, index);
632+ tempVec2.normalizeLocal();
633+ setInBuffer(tempVec2, buf, index);
634+ vars.release();
635+ }
636+
637+ /**
638+ * Add to a Vector2f in-buffer.
639+ *
640+ * @param toAdd
641+ * the vector to add from
642+ * @param buf
643+ * the buffer to find the Vector2f within
644+ * @param index
645+ * the position (in terms of vectors, not floats) of the vector
646+ * to add to
647+ */
648+ public static void addInBuffer(Vector2f toAdd, FloatBuffer buf, int index) {
649+ TempVars vars = TempVars.get();
650+ Vector2f tempVec2 = vars.vect2d;
651+ populateFromBuffer(tempVec2, buf, index);
652+ tempVec2.addLocal(toAdd);
653+ setInBuffer(tempVec2, buf, index);
654+ vars.release();
655+ }
656+
657+ /**
658+ * Multiply and store a Vector2f in-buffer.
659+ *
660+ * @param toMult
661+ * the vector to multiply against
662+ * @param buf
663+ * the buffer to find the Vector2f within
664+ * @param index
665+ * the position (in terms of vectors, not floats) of the vector
666+ * to multiply
667+ */
668+ public static void multInBuffer(Vector2f toMult, FloatBuffer buf, int index) {
669+ TempVars vars = TempVars.get();
670+ Vector2f tempVec2 = vars.vect2d;
671+ populateFromBuffer(tempVec2, buf, index);
672+ tempVec2.multLocal(toMult);
673+ setInBuffer(tempVec2, buf, index);
674+ vars.release();
675+ }
676+
677+ /**
678+ * Checks to see if the given Vector2f is equals to the data stored in the
679+ * buffer at the given data index.
680+ *
681+ * @param check
682+ * the vector to check against - null will return false.
683+ * @param buf
684+ * the buffer to compare data with
685+ * @param index
686+ * the position (in terms of vectors, not floats) of the vector
687+ * in the buffer to check against
688+ * @return true if the data is equivalent, otherwise false.
689+ */
690+ public static boolean equals(Vector2f check, FloatBuffer buf, int index) {
691+ TempVars vars = TempVars.get();
692+ Vector2f tempVec2 = vars.vect2d;
693+ populateFromBuffer(tempVec2, buf, index);
694+ boolean eq = tempVec2.equals(check);
695+ vars.release();
696+ return eq;
697+ }
698+
699+ //// -- INT METHODS -- ////
700+ /**
701+ * Generate a new IntBuffer using the given array of ints. The IntBuffer
702+ * will be data.length long and contain the int data as data[0], data[1]...
703+ * etc.
704+ *
705+ * @param data
706+ * array of ints to place into a new IntBuffer
707+ */
708+ public static IntBuffer createIntBuffer(int... data) {
709+ if (data == null) {
710+ return null;
711+ }
712+ IntBuffer buff = createIntBuffer(data.length);
713+ buff.clear();
714+ buff.put(data);
715+ buff.flip();
716+ return buff;
717+ }
718+
719+ /**
720+ * Create a new int[] array and populate it with the given IntBuffer's
721+ * contents.
722+ *
723+ * @param buff
724+ * the IntBuffer to read from
725+ * @return a new int array populated from the IntBuffer
726+ */
727+ public static int[] getIntArray(IntBuffer buff) {
728+ if (buff == null) {
729+ return null;
730+ }
731+ buff.clear();
732+ int[] inds = new int[buff.limit()];
733+ for (int x = 0; x < inds.length; x++) {
734+ inds[x] = buff.get();
735+ }
736+ return inds;
737+ }
738+
739+ /**
740+ * Create a new float[] array and populate it with the given FloatBuffer's
741+ * contents.
742+ *
743+ * @param buff
744+ * the FloatBuffer to read from
745+ * @return a new float array populated from the FloatBuffer
746+ */
747+ public static float[] getFloatArray(FloatBuffer buff) {
748+ if (buff == null) {
749+ return null;
750+ }
751+ buff.clear();
752+ float[] inds = new float[buff.limit()];
753+ for (int x = 0; x < inds.length; x++) {
754+ inds[x] = buff.get();
755+ }
756+ return inds;
757+ }
758+
759+ //// -- GENERAL DOUBLE ROUTINES -- ////
760+ /**
761+ * Create a new DoubleBuffer of the specified size.
762+ *
763+ * @param size
764+ * required number of double to store.
765+ * @return the new DoubleBuffer
766+ */
767+ public static DoubleBuffer createDoubleBuffer(int size) {
768+ DoubleBuffer buf = ByteBuffer.allocateDirect(8 * size).order(ByteOrder.nativeOrder()).asDoubleBuffer();
769+ buf.clear();
770+ onBufferAllocated(buf);
771+ return buf;
772+ }
773+
774+ /**
775+ * Create a new DoubleBuffer of an appropriate size to hold the specified
776+ * number of doubles only if the given buffer if not already the right size.
777+ *
778+ * @param buf
779+ * the buffer to first check and rewind
780+ * @param size
781+ * number of doubles that need to be held by the newly created
782+ * buffer
783+ * @return the requested new DoubleBuffer
784+ */
785+ public static DoubleBuffer createDoubleBuffer(DoubleBuffer buf, int size) {
786+ if (buf != null && buf.limit() == size) {
787+ buf.rewind();
788+ return buf;
789+ }
790+
791+ buf = createDoubleBuffer(size);
792+ return buf;
793+ }
794+
795+ /**
796+ * Creates a new DoubleBuffer with the same contents as the given
797+ * DoubleBuffer. The new DoubleBuffer is seperate from the old one and
798+ * changes are not reflected across. If you want to reflect changes,
799+ * consider using Buffer.duplicate().
800+ *
801+ * @param buf
802+ * the DoubleBuffer to copy
803+ * @return the copy
804+ */
805+ public static DoubleBuffer clone(DoubleBuffer buf) {
806+ if (buf == null) {
807+ return null;
808+ }
809+ buf.rewind();
810+
811+ DoubleBuffer copy;
812+ if (isDirect(buf)) {
813+ copy = createDoubleBuffer(buf.limit());
814+ } else {
815+ copy = DoubleBuffer.allocate(buf.limit());
816+ }
817+ copy.put(buf);
818+
819+ return copy;
820+ }
821+
822+ //// -- GENERAL FLOAT ROUTINES -- ////
823+ /**
824+ * Create a new FloatBuffer of the specified size.
825+ *
826+ * @param size
827+ * required number of floats to store.
828+ * @return the new FloatBuffer
829+ */
830+ public static FloatBuffer createFloatBuffer(int size) {
831+ FloatBuffer buf = ByteBuffer.allocateDirect(4 * size).order(ByteOrder.nativeOrder()).asFloatBuffer();
832+ buf.clear();
833+ onBufferAllocated(buf);
834+ return buf;
835+ }
836+
837+ /**
838+ * Copies floats from one position in the buffer to another.
839+ *
840+ * @param buf
841+ * the buffer to copy from/to
842+ * @param fromPos
843+ * the starting point to copy from
844+ * @param toPos
845+ * the starting point to copy to
846+ * @param length
847+ * the number of floats to copy
848+ */
849+ public static void copyInternal(FloatBuffer buf, int fromPos, int toPos, int length) {
850+ float[] data = new float[length];
851+ buf.position(fromPos);
852+ buf.get(data);
853+ buf.position(toPos);
854+ buf.put(data);
855+ }
856+
857+ /**
858+ * Creates a new FloatBuffer with the same contents as the given
859+ * FloatBuffer. The new FloatBuffer is seperate from the old one and changes
860+ * are not reflected across. If you want to reflect changes, consider using
861+ * Buffer.duplicate().
862+ *
863+ * @param buf
864+ * the FloatBuffer to copy
865+ * @return the copy
866+ */
867+ public static FloatBuffer clone(FloatBuffer buf) {
868+ if (buf == null) {
869+ return null;
870+ }
871+ buf.rewind();
872+
873+ FloatBuffer copy;
874+ if (isDirect(buf)) {
875+ copy = createFloatBuffer(buf.limit());
876+ } else {
877+ copy = FloatBuffer.allocate(buf.limit());
878+ }
879+ copy.put(buf);
880+
881+ return copy;
882+ }
883+
884+ //// -- GENERAL INT ROUTINES -- ////
885+ /**
886+ * Create a new IntBuffer of the specified size.
887+ *
888+ * @param size
889+ * required number of ints to store.
890+ * @return the new IntBuffer
891+ */
892+ public static IntBuffer createIntBuffer(int size) {
893+ IntBuffer buf = ByteBuffer.allocateDirect(4 * size).order(ByteOrder.nativeOrder()).asIntBuffer();
894+ buf.clear();
895+ onBufferAllocated(buf);
896+ return buf;
897+ }
898+
899+ /**
900+ * Create a new IntBuffer of an appropriate size to hold the specified
901+ * number of ints only if the given buffer if not already the right size.
902+ *
903+ * @param buf
904+ * the buffer to first check and rewind
905+ * @param size
906+ * number of ints that need to be held by the newly created
907+ * buffer
908+ * @return the requested new IntBuffer
909+ */
910+ public static IntBuffer createIntBuffer(IntBuffer buf, int size) {
911+ if (buf != null && buf.limit() == size) {
912+ buf.rewind();
913+ return buf;
914+ }
915+
916+ buf = createIntBuffer(size);
917+ return buf;
918+ }
919+
920+ /**
921+ * Creates a new IntBuffer with the same contents as the given IntBuffer.
922+ * The new IntBuffer is seperate from the old one and changes are not
923+ * reflected across. If you want to reflect changes, consider using
924+ * Buffer.duplicate().
925+ *
926+ * @param buf
927+ * the IntBuffer to copy
928+ * @return the copy
929+ */
930+ public static IntBuffer clone(IntBuffer buf) {
931+ if (buf == null) {
932+ return null;
933+ }
934+ buf.rewind();
935+
936+ IntBuffer copy;
937+ if (isDirect(buf)) {
938+ copy = createIntBuffer(buf.limit());
939+ } else {
940+ copy = IntBuffer.allocate(buf.limit());
941+ }
942+ copy.put(buf);
943+
944+ return copy;
945+ }
946+
947+ //// -- GENERAL BYTE ROUTINES -- ////
948+ /**
949+ * Create a new ByteBuffer of the specified size.
950+ *
951+ * @param size
952+ * required number of ints to store.
953+ * @return the new IntBuffer
954+ */
955+ public static ByteBuffer createByteBuffer(int size) {
956+ ByteBuffer buf = ByteBuffer.allocateDirect(size).order(ByteOrder.nativeOrder());
957+ buf.clear();
958+ onBufferAllocated(buf);
959+ return buf;
960+ }
961+
962+ /**
963+ * Create a new ByteBuffer of an appropriate size to hold the specified
964+ * number of ints only if the given buffer if not already the right size.
965+ *
966+ * @param buf
967+ * the buffer to first check and rewind
968+ * @param size
969+ * number of bytes that need to be held by the newly created
970+ * buffer
971+ * @return the requested new IntBuffer
972+ */
973+ public static ByteBuffer createByteBuffer(ByteBuffer buf, int size) {
974+ if (buf != null && buf.limit() == size) {
975+ buf.rewind();
976+ return buf;
977+ }
978+
979+ buf = createByteBuffer(size);
980+ return buf;
981+ }
982+
983+ public static ByteBuffer createByteBuffer(byte... data) {
984+ ByteBuffer bb = createByteBuffer(data.length);
985+ bb.put(data);
986+ bb.flip();
987+ return bb;
988+ }
989+
990+ public static ByteBuffer createByteBuffer(String data) {
991+ byte[] bytes = data.getBytes();
992+ ByteBuffer bb = createByteBuffer(bytes.length);
993+ bb.put(bytes);
994+ bb.flip();
995+ return bb;
996+ }
997+
998+ /**
999+ * Creates a new ByteBuffer with the same contents as the given ByteBuffer.
1000+ * The new ByteBuffer is seperate from the old one and changes are not
1001+ * reflected across. If you want to reflect changes, consider using
1002+ * Buffer.duplicate().
1003+ *
1004+ * @param buf
1005+ * the ByteBuffer to copy
1006+ * @return the copy
1007+ */
1008+ public static ByteBuffer clone(ByteBuffer buf) {
1009+ if (buf == null) {
1010+ return null;
1011+ }
1012+ buf.rewind();
1013+
1014+ ByteBuffer copy;
1015+ if (isDirect(buf)) {
1016+ copy = createByteBuffer(buf.limit());
1017+ } else {
1018+ copy = ByteBuffer.allocate(buf.limit());
1019+ }
1020+ copy.put(buf);
1021+
1022+ return copy;
1023+ }
1024+
1025+ //// -- GENERAL SHORT ROUTINES -- ////
1026+ /**
1027+ * Create a new ShortBuffer of the specified size.
1028+ *
1029+ * @param size
1030+ * required number of shorts to store.
1031+ * @return the new ShortBuffer
1032+ */
1033+ public static ShortBuffer createShortBuffer(int size) {
1034+ ShortBuffer buf = ByteBuffer.allocateDirect(2 * size).order(ByteOrder.nativeOrder()).asShortBuffer();
1035+ buf.clear();
1036+ onBufferAllocated(buf);
1037+ return buf;
1038+ }
1039+
1040+ /**
1041+ * Create a new ShortBuffer of an appropriate size to hold the specified
1042+ * number of shorts only if the given buffer if not already the right size.
1043+ *
1044+ * @param buf
1045+ * the buffer to first check and rewind
1046+ * @param size
1047+ * number of shorts that need to be held by the newly created
1048+ * buffer
1049+ * @return the requested new ShortBuffer
1050+ */
1051+ public static ShortBuffer createShortBuffer(ShortBuffer buf, int size) {
1052+ if (buf != null && buf.limit() == size) {
1053+ buf.rewind();
1054+ return buf;
1055+ }
1056+
1057+ buf = createShortBuffer(size);
1058+ return buf;
1059+ }
1060+
1061+ public static ShortBuffer createShortBuffer(short... data) {
1062+ if (data == null) {
1063+ return null;
1064+ }
1065+ ShortBuffer buff = createShortBuffer(data.length);
1066+ buff.clear();
1067+ buff.put(data);
1068+ buff.flip();
1069+ return buff;
1070+ }
1071+
1072+ /**
1073+ * Creates a new ShortBuffer with the same contents as the given ShortBuffer.
1074+ * The new ShortBuffer is seperate from the old one and changes are not
1075+ * reflected across. If you want to reflect changes, consider using
1076+ * Buffer.duplicate().
1077+ *
1078+ * @param buf
1079+ * the ShortBuffer to copy
1080+ * @return the copy
1081+ */
1082+ public static ShortBuffer clone(ShortBuffer buf) {
1083+ if (buf == null) {
1084+ return null;
1085+ }
1086+ buf.rewind();
1087+
1088+ ShortBuffer copy;
1089+ if (isDirect(buf)) {
1090+ copy = createShortBuffer(buf.limit());
1091+ } else {
1092+ copy = ShortBuffer.allocate(buf.limit());
1093+ }
1094+ copy.put(buf);
1095+
1096+ return copy;
1097+ }
1098+
1099+ /**
1100+ * Ensures there is at least the <code>required</code> number of entries left after the current position of the
1101+ * buffer. If the buffer is too small a larger one is created and the old one copied to the new buffer.
1102+ * @param buffer buffer that should be checked/copied (may be null)
1103+ * @param required minimum number of elements that should be remaining in the returned buffer
1104+ * @return a buffer large enough to receive at least the <code>required</code> number of entries, same position as
1105+ * the input buffer, not null
1106+ */
1107+ public static FloatBuffer ensureLargeEnough(FloatBuffer buffer, int required) {
1108+ if (buffer != null) {
1109+ buffer.limit(buffer.capacity());
1110+ }
1111+ if (buffer == null || (buffer.remaining() < required)) {
1112+ int position = (buffer != null ? buffer.position() : 0);
1113+ FloatBuffer newVerts = createFloatBuffer(position + required);
1114+ if (buffer != null) {
1115+ buffer.flip();
1116+ newVerts.put(buffer);
1117+ newVerts.position(position);
1118+ }
1119+ buffer = newVerts;
1120+ }
1121+ return buffer;
1122+ }
1123+
1124+ public static IntBuffer ensureLargeEnough(IntBuffer buffer, int required) {
1125+ if (buffer != null) {
1126+ buffer.limit(buffer.capacity());
1127+ }
1128+ if (buffer == null || (buffer.remaining() < required)) {
1129+ int position = (buffer != null ? buffer.position() : 0);
1130+ IntBuffer newVerts = createIntBuffer(position + required);
1131+ if (buffer != null) {
1132+ buffer.flip();
1133+ newVerts.put(buffer);
1134+ newVerts.position(position);
1135+ }
1136+ buffer = newVerts;
1137+ }
1138+ return buffer;
1139+ }
1140+
1141+
1142+ public static ShortBuffer ensureLargeEnough(ShortBuffer buffer, int required) {
1143+ if (buffer != null) {
1144+ buffer.limit(buffer.capacity());
1145+ }
1146+ if (buffer == null || (buffer.remaining() < required)) {
1147+ int position = (buffer != null ? buffer.position() : 0);
1148+ ShortBuffer newVerts = createShortBuffer(position + required);
1149+ if (buffer != null) {
1150+ buffer.flip();
1151+ newVerts.put(buffer);
1152+ newVerts.position(position);
1153+ }
1154+ buffer = newVerts;
1155+ }
1156+ return buffer;
1157+ }
1158+
1159+ public static ByteBuffer ensureLargeEnough(ByteBuffer buffer, int required) {
1160+ if (buffer != null) {
1161+ buffer.limit(buffer.capacity());
1162+ }
1163+ if (buffer == null || (buffer.remaining() < required)) {
1164+ int position = (buffer != null ? buffer.position() : 0);
1165+ ByteBuffer newVerts = createByteBuffer(position + required);
1166+ if (buffer != null) {
1167+ buffer.flip();
1168+ newVerts.put(buffer);
1169+ newVerts.position(position);
1170+ }
1171+ buffer = newVerts;
1172+ }
1173+ return buffer;
1174+ }
1175+
1176+ public static void printCurrentDirectMemory(StringBuilder store) {
1177+ long totalHeld = 0;
1178+ long heapMem = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
1179+
1180+ boolean printStout = store == null;
1181+ if (store == null) {
1182+ store = new StringBuilder();
1183+ }
1184+ if (trackDirectMemory) {
1185+ // make a new set to hold the keys to prevent concurrency issues.
1186+ int fBufs = 0, bBufs = 0, iBufs = 0, sBufs = 0, dBufs = 0;
1187+ int fBufsM = 0, bBufsM = 0, iBufsM = 0, sBufsM = 0, dBufsM = 0;
1188+ for (BufferInfo b : BufferUtils.trackedBuffers.values()) {
1189+ if (b.type == ByteBuffer.class) {
1190+ totalHeld += b.size;
1191+ bBufsM += b.size;
1192+ bBufs++;
1193+ } else if (b.type == FloatBuffer.class) {
1194+ totalHeld += b.size;
1195+ fBufsM += b.size;
1196+ fBufs++;
1197+ } else if (b.type == IntBuffer.class) {
1198+ totalHeld += b.size;
1199+ iBufsM += b.size;
1200+ iBufs++;
1201+ } else if (b.type == ShortBuffer.class) {
1202+ totalHeld += b.size;
1203+ sBufsM += b.size;
1204+ sBufs++;
1205+ } else if (b.type == DoubleBuffer.class) {
1206+ totalHeld += b.size;
1207+ dBufsM += b.size;
1208+ dBufs++;
1209+ }
1210+ }
1211+
1212+ store.append("Existing buffers: ").append(BufferUtils.trackedBuffers.size()).append("\n");
1213+ store.append("(b: ").append(bBufs).append(" f: ").append(fBufs).append(" i: ").append(iBufs).append(" s: ").append(sBufs).append(" d: ").append(dBufs).append(")").append("\n");
1214+ store.append("Total heap memory held: ").append(heapMem / 1024).append("kb\n");
1215+ store.append("Total direct memory held: ").append(totalHeld / 1024).append("kb\n");
1216+ store.append("(b: ").append(bBufsM / 1024).append("kb f: ").append(fBufsM / 1024).append("kb i: ").append(iBufsM / 1024).append("kb s: ").append(sBufsM / 1024).append("kb d: ").append(dBufsM / 1024).append("kb)").append("\n");
1217+ } else {
1218+ store.append("Total heap memory held: ").append(heapMem / 1024).append("kb\n");
1219+ store.append("Only heap memory available, if you want to monitor direct memory use BufferUtils.setTrackDirectMemoryEnabled(true) during initialization.").append("\n");
1220+ }
1221+ if (printStout) {
1222+ System.out.println(store.toString());
1223+ }
1224+ }
1225+ private static final AtomicBoolean loadedMethods = new AtomicBoolean(false);
1226+ private static Method cleanerMethod = null;
1227+ private static Method cleanMethod = null;
1228+ private static Method viewedBufferMethod = null;
1229+ private static Method freeMethod = null;
1230+
1231+ private static Method loadMethod(String className, String methodName) {
1232+ try {
1233+ Method method = Class.forName(className).getMethod(methodName);
1234+ method.setAccessible(true);
1235+ return method;
1236+ } catch (NoSuchMethodException ex) {
1237+ return null; // the method was not found
1238+ } catch (SecurityException ex) {
1239+ return null; // setAccessible not allowed by security policy
1240+ } catch (ClassNotFoundException ex) {
1241+ return null; // the direct buffer implementation was not found
1242+ }
1243+ }
1244+
1245+ private static void loadCleanerMethods() {
1246+ // If its already true, exit, if not, set it to true.
1247+ if (BufferUtils.loadedMethods.getAndSet(true)) {
1248+ return;
1249+ }
1250+ // This could potentially be called many times if used from multiple
1251+ // threads
1252+ synchronized (BufferUtils.loadedMethods) {
1253+ // Oracle JRE / OpenJDK
1254+ cleanerMethod = loadMethod("sun.nio.ch.DirectBuffer", "cleaner");
1255+ cleanMethod = loadMethod("sun.misc.Cleaner", "clean");
1256+ viewedBufferMethod = loadMethod("sun.nio.ch.DirectBuffer", "viewedBuffer");
1257+ if (viewedBufferMethod == null) {
1258+ // They changed the name in Java 7 (???)
1259+ viewedBufferMethod = loadMethod("sun.nio.ch.DirectBuffer", "attachment");
1260+ }
1261+
1262+ // Apache Harmony
1263+ ByteBuffer bb = BufferUtils.createByteBuffer(1);
1264+ Class<?> clazz = bb.getClass();
1265+ try {
1266+ freeMethod = clazz.getMethod("free");
1267+ } catch (NoSuchMethodException ex) {
1268+ } catch (SecurityException ex) {
1269+ }
1270+ }
1271+ }
1272+
1273+ /**
1274+ * Direct buffers are garbage collected by using a phantom reference and a
1275+ * reference queue. Every once a while, the JVM checks the reference queue and
1276+ * cleans the direct buffers. However, as this doesn't happen
1277+ * immediately after discarding all references to a direct buffer, it's
1278+ * easy to OutOfMemoryError yourself using direct buffers. This function
1279+ * explicitly calls the Cleaner method of a direct buffer.
1280+ *
1281+ * @param toBeDestroyed
1282+ * The direct buffer that will be "cleaned". Utilizes reflection.
1283+ *
1284+ */
1285+ public static void destroyDirectBuffer(Buffer toBeDestroyed) {
1286+ if (!isDirect(toBeDestroyed)) {
1287+ return;
1288+ }
1289+
1290+ BufferUtils.loadCleanerMethods();
1291+
1292+ try {
1293+ if (freeMethod != null) {
1294+ freeMethod.invoke(toBeDestroyed);
1295+ } else {
1296+ Object cleaner = cleanerMethod.invoke(toBeDestroyed);
1297+ if (cleaner != null) {
1298+ cleanMethod.invoke(cleaner);
1299+ } else {
1300+ // Try the alternate approach of getting the viewed buffer first
1301+ Object viewedBuffer = viewedBufferMethod.invoke(toBeDestroyed);
1302+ if (viewedBuffer != null) {
1303+ destroyDirectBuffer((Buffer) viewedBuffer);
1304+ } else {
1305+ Logger.getLogger(BufferUtils.class.getName()).log(Level.SEVERE, "Buffer cannot be destroyed: {0}", toBeDestroyed);
1306+ }
1307+ }
1308+ }
1309+ } catch (IllegalAccessException ex) {
1310+ Logger.getLogger(BufferUtils.class.getName()).log(Level.SEVERE, "{0}", ex);
1311+ } catch (IllegalArgumentException ex) {
1312+ Logger.getLogger(BufferUtils.class.getName()).log(Level.SEVERE, "{0}", ex);
1313+ } catch (InvocationTargetException ex) {
1314+ Logger.getLogger(BufferUtils.class.getName()).log(Level.SEVERE, "{0}", ex);
1315+ } catch (SecurityException ex) {
1316+ Logger.getLogger(BufferUtils.class.getName()).log(Level.SEVERE, "{0}", ex);
1317+ }
1318+ }
1319+
1320+ /*
1321+ * FIXME when java 1.5 supprt is dropped - replace calls to this method with Buffer.isDirect
1322+ *
1323+ * Buffer.isDirect() is only java 6. Java 5 only have this method on Buffer subclasses :
1324+ * FloatBuffer, IntBuffer, ShortBuffer, ByteBuffer,DoubleBuffer, LongBuffer.
1325+ * CharBuffer has been excluded as we don't use it.
1326+ *
1327+ */
1328+ private static boolean isDirect(Buffer buf) {
1329+ if (buf instanceof FloatBuffer) {
1330+ return ((FloatBuffer) buf).isDirect();
1331+ }
1332+ if (buf instanceof IntBuffer) {
1333+ return ((IntBuffer) buf).isDirect();
1334+ }
1335+ if (buf instanceof ShortBuffer) {
1336+ return ((ShortBuffer) buf).isDirect();
1337+ }
1338+ if (buf instanceof ByteBuffer) {
1339+ return ((ByteBuffer) buf).isDirect();
1340+ }
1341+ if (buf instanceof DoubleBuffer) {
1342+ return ((DoubleBuffer) buf).isDirect();
1343+ }
1344+ if (buf instanceof LongBuffer) {
1345+ return ((LongBuffer) buf).isDirect();
1346+ }
1347+ throw new UnsupportedOperationException(" BufferUtils.isDirect was called on " + buf.getClass().getName());
1348+ }
1349+
1350+ private static class BufferInfo extends PhantomReference<Buffer> {
1351+
1352+ private Class type;
1353+ private int size;
1354+
1355+ public BufferInfo(Class type, int size, Buffer referent, ReferenceQueue<? super Buffer> q) {
1356+ super(referent, q);
1357+ this.type = type;
1358+ this.size = size;
1359+ }
1360+ }
1361+
1362+ private static class ClearReferences extends Thread {
1363+
1364+ ClearReferences() {
1365+ this.setDaemon(true);
1366+ }
1367+
1368+ @Override
1369+ public void run() {
1370+ try {
1371+ while (true) {
1372+ Reference<? extends Buffer> toclean = BufferUtils.removeCollected.remove();
1373+ BufferUtils.trackedBuffers.remove(toclean);
1374+ }
1375+
1376+ } catch (InterruptedException e) {
1377+ e.printStackTrace();
1378+ }
1379+ }
1380+ }
1381+}
--- a/engine/src/jogl/com/jme3/renderer/jogl/JoglRenderer.java
+++ b/engine/src/jogl/com/jme3/renderer/jogl/JoglRenderer.java
@@ -877,6 +877,7 @@ public class JoglRenderer implements Renderer {
877877
878878 uniform.clearUpdateNeeded();
879879 FloatBuffer fb;
880+ IntBuffer ib;
880881 GL gl = GLContext.getCurrentGL();
881882 switch (uniform.getVarType()) {
882883 case Float:
@@ -918,6 +919,10 @@ public class JoglRenderer implements Renderer {
918919 assert fb.remaining() == 16;
919920 gl.getGL2ES2().glUniformMatrix4fv(loc, 1, false, fb);
920921 break;
922+ case IntArray:
923+ ib = (IntBuffer) uniform.getValue();
924+ gl.getGL2ES2().glUniform1iv(loc, ib.remaining(), ib);
925+ break;
921926 case FloatArray:
922927 fb = (FloatBuffer) uniform.getValue();
923928 gl.getGL2ES2().glUniform1fv(loc, fb.remaining(), fb);
--- a/engine/src/lwjgl/com/jme3/renderer/lwjgl/LwjglRenderer.java
+++ b/engine/src/lwjgl/com/jme3/renderer/lwjgl/LwjglRenderer.java
@@ -823,6 +823,7 @@ public class LwjglRenderer implements Renderer {
823823
824824 uniform.clearUpdateNeeded();
825825 FloatBuffer fb;
826+ IntBuffer ib;
826827 switch (uniform.getVarType()) {
827828 case Float:
828829 Float f = (Float) uniform.getValue();
@@ -863,6 +864,10 @@ public class LwjglRenderer implements Renderer {
863864 assert fb.remaining() == 16;
864865 glUniformMatrix4(loc, false, fb);
865866 break;
867+ case IntArray:
868+ ib = (IntBuffer) uniform.getValue();
869+ glUniform1(loc, ib);
870+ break;
866871 case FloatArray:
867872 fb = (FloatBuffer) uniform.getValue();
868873 glUniform1(loc, fb);