Main repository of MikuMikuStudio
Revision | ca902c804a84b6a58b3726b8eff0726c06dc1317 (tree) |
---|---|
Time | 2013-03-21 02:53:50 |
Author | remy.bouquet@gmail.com <remy.bouquet@gmai...> |
Commiter | remy.bouquet@gmail.com |
Added support for int arrays uniforms. thanks to abies.
git-svn-id: http://jmonkeyengine.googlecode.com/svn/trunk@10495 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
@@ -643,6 +643,7 @@ public class OGLESShaderRenderer implements Renderer { | ||
643 | 643 | |
644 | 644 | uniform.clearUpdateNeeded(); |
645 | 645 | FloatBuffer fb; |
646 | + IntBuffer ib; | |
646 | 647 | switch (uniform.getVarType()) { |
647 | 648 | case Float: |
648 | 649 | Float f = (Float) uniform.getValue(); |
@@ -683,6 +684,10 @@ public class OGLESShaderRenderer implements Renderer { | ||
683 | 684 | assert fb.remaining() == 16; |
684 | 685 | GLES20.glUniformMatrix4fv(loc, 1, false, fb); |
685 | 686 | break; |
687 | + case IntArray: | |
688 | + ib = (IntBuffer) uniform.getValue(); | |
689 | + GLES20.glUniform1iv(loc, ib.limit(), ib); | |
690 | + break; | |
686 | 691 | case FloatArray: |
687 | 692 | fb = (FloatBuffer) uniform.getValue(); |
688 | 693 | GLES20.glUniform1fv(loc, fb.limit(), fb); |
@@ -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 | +} |
@@ -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 | +} |
@@ -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 | +} |
@@ -877,6 +877,7 @@ public class JoglRenderer implements Renderer { | ||
877 | 877 | |
878 | 878 | uniform.clearUpdateNeeded(); |
879 | 879 | FloatBuffer fb; |
880 | + IntBuffer ib; | |
880 | 881 | GL gl = GLContext.getCurrentGL(); |
881 | 882 | switch (uniform.getVarType()) { |
882 | 883 | case Float: |
@@ -918,6 +919,10 @@ public class JoglRenderer implements Renderer { | ||
918 | 919 | assert fb.remaining() == 16; |
919 | 920 | gl.getGL2ES2().glUniformMatrix4fv(loc, 1, false, fb); |
920 | 921 | break; |
922 | + case IntArray: | |
923 | + ib = (IntBuffer) uniform.getValue(); | |
924 | + gl.getGL2ES2().glUniform1iv(loc, ib.remaining(), ib); | |
925 | + break; | |
921 | 926 | case FloatArray: |
922 | 927 | fb = (FloatBuffer) uniform.getValue(); |
923 | 928 | gl.getGL2ES2().glUniform1fv(loc, fb.remaining(), fb); |
@@ -823,6 +823,7 @@ public class LwjglRenderer implements Renderer { | ||
823 | 823 | |
824 | 824 | uniform.clearUpdateNeeded(); |
825 | 825 | FloatBuffer fb; |
826 | + IntBuffer ib; | |
826 | 827 | switch (uniform.getVarType()) { |
827 | 828 | case Float: |
828 | 829 | Float f = (Float) uniform.getValue(); |
@@ -863,6 +864,10 @@ public class LwjglRenderer implements Renderer { | ||
863 | 864 | assert fb.remaining() == 16; |
864 | 865 | glUniformMatrix4(loc, false, fb); |
865 | 866 | break; |
867 | + case IntArray: | |
868 | + ib = (IntBuffer) uniform.getValue(); | |
869 | + glUniform1(loc, ib); | |
870 | + break; | |
866 | 871 | case FloatArray: |
867 | 872 | fb = (FloatBuffer) uniform.getValue(); |
868 | 873 | glUniform1(loc, fb); |