BufferUtils.java 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196
  1. /*
  2. * Copyright (c) 2009-2010 jMonkeyEngine
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are
  7. * met:
  8. *
  9. * * Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. *
  12. * * Redistributions in binary form must reproduce the above copyright
  13. * notice, this list of conditions and the following disclaimer in the
  14. * documentation and/or other materials provided with the distribution.
  15. *
  16. * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
  17. * may be used to endorse or promote products derived from this software
  18. * without specific prior written permission.
  19. *
  20. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  22. * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  23. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  24. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  25. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  26. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  27. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  28. * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  29. * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  30. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31. */
  32. package com.jme3.util;
  33. import com.jme3.math.ColorRGBA;
  34. import com.jme3.math.Quaternion;
  35. import com.jme3.math.Vector2f;
  36. import com.jme3.math.Vector3f;
  37. import java.lang.reflect.InvocationTargetException;
  38. import java.lang.reflect.Method;
  39. import java.nio.*;
  40. import java.util.ArrayList;
  41. import java.util.Collections;
  42. import java.util.Map;
  43. import java.util.WeakHashMap;
  44. import java.util.logging.Level;
  45. import java.util.logging.Logger;
  46. /**
  47. * <code>BufferUtils</code> is a helper class for generating nio buffers from
  48. * jME data classes such as Vectors and ColorRGBA.
  49. *
  50. * @author Joshua Slack
  51. * @version $Id: BufferUtils.java,v 1.16 2007/10/29 16:56:18 nca Exp $
  52. */
  53. public final class BufferUtils {
  54. private static final Map<Buffer, Object> trackingHash = Collections.synchronizedMap(new WeakHashMap<Buffer, Object>());
  55. private static final Object ref = new Object();
  56. // Note: a WeakHashMap is really bad here since the hashCode() and
  57. // equals() behavior of buffers will vary based on their contents.
  58. // As it stands, put()'ing an empty buffer will wipe out the last
  59. // empty buffer with the same size. So any tracked memory calculations
  60. // could be lying.
  61. // Besides, the hashmap behavior isn't even being used here and
  62. // yet the expense is still incurred. For example, a newly allocated
  63. // 10,000 byte buffer will iterate through the whole buffer of 0's
  64. // to calculate the hashCode and then potentially do it again to
  65. // calculate the equals()... which by the way is guaranteed for
  66. // every empty buffer of an existing size since they will always produce
  67. // the same hashCode().
  68. // It would be better to just keep a straight list of weak references
  69. // and clean out the dead every time a new buffer is allocated.
  70. // WeakHashMap is doing that anyway... so there is no extra expense
  71. // incurred.
  72. // Recommend a ConcurrentLinkedQueue of WeakReferences since it
  73. // supports the threading semantics required with little extra overhead.
  74. private static final boolean trackDirectMemory = false;
  75. /**
  76. * Creates a clone of the given buffer. The clone's capacity is
  77. * equal to the given buffer's limit.
  78. *
  79. * @param buf The buffer to clone
  80. * @return The cloned buffer
  81. */
  82. public static Buffer clone(Buffer buf) {
  83. if (buf instanceof FloatBuffer) {
  84. return clone((FloatBuffer) buf);
  85. } else if (buf instanceof ShortBuffer) {
  86. return clone((ShortBuffer) buf);
  87. } else if (buf instanceof ByteBuffer) {
  88. return clone((ByteBuffer) buf);
  89. } else if (buf instanceof IntBuffer) {
  90. return clone((IntBuffer) buf);
  91. } else if (buf instanceof DoubleBuffer) {
  92. return clone((DoubleBuffer) buf);
  93. } else {
  94. throw new UnsupportedOperationException();
  95. }
  96. }
  97. private static void onBufferAllocated(Buffer buffer){
  98. /*
  99. StackTraceElement[] stackTrace = new Throwable().getStackTrace();
  100. int initialIndex = 0;
  101. for (int i = 0; i < stackTrace.length; i++){
  102. if (!stackTrace[i].getClassName().equals(BufferUtils.class.getName())){
  103. initialIndex = i;
  104. break;
  105. }
  106. }
  107. int allocated = buffer.capacity();
  108. int size = 0;
  109. if (buffer instanceof FloatBuffer){
  110. size = 4;
  111. }else if (buffer instanceof ShortBuffer){
  112. size = 2;
  113. }else if (buffer instanceof ByteBuffer){
  114. size = 1;
  115. }else if (buffer instanceof IntBuffer){
  116. size = 4;
  117. }else if (buffer instanceof DoubleBuffer){
  118. size = 8;
  119. }
  120. allocated *= size;
  121. for (int i = initialIndex; i < stackTrace.length; i++){
  122. StackTraceElement element = stackTrace[i];
  123. if (element.getClassName().startsWith("java")){
  124. break;
  125. }
  126. try {
  127. Class clazz = Class.forName(element.getClassName());
  128. if (i == initialIndex){
  129. System.out.println(clazz.getSimpleName()+"."+element.getMethodName()+"():" + element.getLineNumber() + " allocated " + allocated);
  130. }else{
  131. System.out.println(" at " + clazz.getSimpleName()+"."+element.getMethodName()+"()");
  132. }
  133. } catch (ClassNotFoundException ex) {
  134. }
  135. }*/
  136. if (trackDirectMemory){
  137. trackingHash.put(buffer, ref);
  138. }
  139. }
  140. /**
  141. * Generate a new FloatBuffer using the given array of Vector3f objects.
  142. * The FloatBuffer will be 3 * data.length long and contain the vector data
  143. * as data[0].x, data[0].y, data[0].z, data[1].x... etc.
  144. *
  145. * @param data array of Vector3f objects to place into a new FloatBuffer
  146. */
  147. public static FloatBuffer createFloatBuffer(Vector3f... data) {
  148. if (data == null) {
  149. return null;
  150. }
  151. FloatBuffer buff = createFloatBuffer(3 * data.length);
  152. for (int x = 0; x < data.length; x++) {
  153. if (data[x] != null) {
  154. buff.put(data[x].x).put(data[x].y).put(data[x].z);
  155. } else {
  156. buff.put(0).put(0).put(0);
  157. }
  158. }
  159. buff.flip();
  160. return buff;
  161. }
  162. /**
  163. * Generate a new FloatBuffer using the given array of Quaternion objects.
  164. * The FloatBuffer will be 4 * data.length long and contain the vector data.
  165. *
  166. * @param data array of Quaternion objects to place into a new FloatBuffer
  167. */
  168. public static FloatBuffer createFloatBuffer(Quaternion... data) {
  169. if (data == null) {
  170. return null;
  171. }
  172. FloatBuffer buff = createFloatBuffer(4 * data.length);
  173. for (int x = 0; x < data.length; x++) {
  174. if (data[x] != null) {
  175. buff.put(data[x].getX()).put(data[x].getY()).put(data[x].getZ()).put(data[x].getW());
  176. } else {
  177. buff.put(0).put(0).put(0);
  178. }
  179. }
  180. buff.flip();
  181. return buff;
  182. }
  183. /**
  184. * Generate a new FloatBuffer using the given array of float primitives.
  185. * @param data array of float primitives to place into a new FloatBuffer
  186. */
  187. public static FloatBuffer createFloatBuffer(float... data) {
  188. if (data == null) {
  189. return null;
  190. }
  191. FloatBuffer buff = createFloatBuffer(data.length);
  192. buff.clear();
  193. buff.put(data);
  194. buff.flip();
  195. return buff;
  196. }
  197. /**
  198. * Create a new FloatBuffer of an appropriate size to hold the specified
  199. * number of Vector3f object data.
  200. *
  201. * @param vertices
  202. * number of vertices that need to be held by the newly created
  203. * buffer
  204. * @return the requested new FloatBuffer
  205. */
  206. public static FloatBuffer createVector3Buffer(int vertices) {
  207. FloatBuffer vBuff = createFloatBuffer(3 * vertices);
  208. return vBuff;
  209. }
  210. /**
  211. * Create a new FloatBuffer of an appropriate size to hold the specified
  212. * number of Vector3f object data only if the given buffer if not already
  213. * the right size.
  214. *
  215. * @param buf
  216. * the buffer to first check and rewind
  217. * @param vertices
  218. * number of vertices that need to be held by the newly created
  219. * buffer
  220. * @return the requested new FloatBuffer
  221. */
  222. public static FloatBuffer createVector3Buffer(FloatBuffer buf, int vertices) {
  223. if (buf != null && buf.limit() == 3 * vertices) {
  224. buf.rewind();
  225. return buf;
  226. }
  227. return createFloatBuffer(3 * vertices);
  228. }
  229. /**
  230. * Sets the data contained in the given color into the FloatBuffer at the
  231. * specified index.
  232. *
  233. * @param color
  234. * the data to insert
  235. * @param buf
  236. * the buffer to insert into
  237. * @param index
  238. * the postion to place the data; in terms of colors not floats
  239. */
  240. public static void setInBuffer(ColorRGBA color, FloatBuffer buf,
  241. int index) {
  242. buf.position(index * 4);
  243. buf.put(color.r);
  244. buf.put(color.g);
  245. buf.put(color.b);
  246. buf.put(color.a);
  247. }
  248. /**
  249. * Sets the data contained in the given quaternion into the FloatBuffer at the
  250. * specified index.
  251. *
  252. * @param quat
  253. * the {@link Quaternion} to insert
  254. * @param buf
  255. * the buffer to insert into
  256. * @param index
  257. * the postion to place the data; in terms of quaternions not floats
  258. */
  259. public static void setInBuffer(Quaternion quat, FloatBuffer buf,
  260. int index) {
  261. buf.position(index * 4);
  262. buf.put(quat.getX());
  263. buf.put(quat.getY());
  264. buf.put(quat.getZ());
  265. buf.put(quat.getW());
  266. }
  267. /**
  268. * Sets the data contained in the given Vector3F into the FloatBuffer at the
  269. * specified index.
  270. *
  271. * @param vector
  272. * the data to insert
  273. * @param buf
  274. * the buffer to insert into
  275. * @param index
  276. * the postion to place the data; in terms of vectors not floats
  277. */
  278. public static void setInBuffer(Vector3f vector, FloatBuffer buf, int index) {
  279. if (buf == null) {
  280. return;
  281. }
  282. if (vector == null) {
  283. buf.put(index * 3, 0);
  284. buf.put((index * 3) + 1, 0);
  285. buf.put((index * 3) + 2, 0);
  286. } else {
  287. buf.put(index * 3, vector.x);
  288. buf.put((index * 3) + 1, vector.y);
  289. buf.put((index * 3) + 2, vector.z);
  290. }
  291. }
  292. /**
  293. * Updates the values of the given vector from the specified buffer at the
  294. * index provided.
  295. *
  296. * @param vector
  297. * the vector to set data on
  298. * @param buf
  299. * the buffer to read from
  300. * @param index
  301. * the position (in terms of vectors, not floats) to read from
  302. * the buf
  303. */
  304. public static void populateFromBuffer(Vector3f vector, FloatBuffer buf, int index) {
  305. vector.x = buf.get(index * 3);
  306. vector.y = buf.get(index * 3 + 1);
  307. vector.z = buf.get(index * 3 + 2);
  308. }
  309. /**
  310. * Generates a Vector3f array from the given FloatBuffer.
  311. *
  312. * @param buff
  313. * the FloatBuffer to read from
  314. * @return a newly generated array of Vector3f objects
  315. */
  316. public static Vector3f[] getVector3Array(FloatBuffer buff) {
  317. buff.clear();
  318. Vector3f[] verts = new Vector3f[buff.limit() / 3];
  319. for (int x = 0; x < verts.length; x++) {
  320. Vector3f v = new Vector3f(buff.get(), buff.get(), buff.get());
  321. verts[x] = v;
  322. }
  323. return verts;
  324. }
  325. /**
  326. * Copies a Vector3f from one position in the buffer to another. The index
  327. * values are in terms of vector number (eg, vector number 0 is postions 0-2
  328. * in the FloatBuffer.)
  329. *
  330. * @param buf
  331. * the buffer to copy from/to
  332. * @param fromPos
  333. * the index of the vector to copy
  334. * @param toPos
  335. * the index to copy the vector to
  336. */
  337. public static void copyInternalVector3(FloatBuffer buf, int fromPos, int toPos) {
  338. copyInternal(buf, fromPos * 3, toPos * 3, 3);
  339. }
  340. /**
  341. * Normalize a Vector3f in-buffer.
  342. *
  343. * @param buf
  344. * the buffer to find the Vector3f within
  345. * @param index
  346. * the position (in terms of vectors, not floats) of the vector
  347. * to normalize
  348. */
  349. public static void normalizeVector3(FloatBuffer buf, int index) {
  350. TempVars vars = TempVars.get();
  351. Vector3f tempVec3 = vars.vect1;
  352. populateFromBuffer(tempVec3, buf, index);
  353. tempVec3.normalizeLocal();
  354. setInBuffer(tempVec3, buf, index);
  355. vars.release();
  356. }
  357. /**
  358. * Add to a Vector3f in-buffer.
  359. *
  360. * @param toAdd
  361. * the vector to add from
  362. * @param buf
  363. * the buffer to find the Vector3f within
  364. * @param index
  365. * the position (in terms of vectors, not floats) of the vector
  366. * to add to
  367. */
  368. public static void addInBuffer(Vector3f toAdd, FloatBuffer buf, int index) {
  369. TempVars vars = TempVars.get();
  370. Vector3f tempVec3 = vars.vect1;
  371. populateFromBuffer(tempVec3, buf, index);
  372. tempVec3.addLocal(toAdd);
  373. setInBuffer(tempVec3, buf, index);
  374. vars.release();
  375. }
  376. /**
  377. * Multiply and store a Vector3f in-buffer.
  378. *
  379. * @param toMult
  380. * the vector to multiply against
  381. * @param buf
  382. * the buffer to find the Vector3f within
  383. * @param index
  384. * the position (in terms of vectors, not floats) of the vector
  385. * to multiply
  386. */
  387. public static void multInBuffer(Vector3f toMult, FloatBuffer buf, int index) {
  388. TempVars vars = TempVars.get();
  389. Vector3f tempVec3 = vars.vect1;
  390. populateFromBuffer(tempVec3, buf, index);
  391. tempVec3.multLocal(toMult);
  392. setInBuffer(tempVec3, buf, index);
  393. vars.release();
  394. }
  395. /**
  396. * Checks to see if the given Vector3f is equals to the data stored in the
  397. * buffer at the given data index.
  398. *
  399. * @param check
  400. * the vector to check against - null will return false.
  401. * @param buf
  402. * the buffer to compare data with
  403. * @param index
  404. * the position (in terms of vectors, not floats) of the vector
  405. * in the buffer to check against
  406. * @return
  407. */
  408. public static boolean equals(Vector3f check, FloatBuffer buf, int index) {
  409. TempVars vars = TempVars.get();
  410. Vector3f tempVec3 = vars.vect1;
  411. populateFromBuffer(tempVec3, buf, index);
  412. boolean eq = tempVec3.equals(check);
  413. vars.release();
  414. return eq;
  415. }
  416. // // -- VECTOR2F METHODS -- ////
  417. /**
  418. * Generate a new FloatBuffer using the given array of Vector2f objects.
  419. * The FloatBuffer will be 2 * data.length long and contain the vector data
  420. * as data[0].x, data[0].y, data[1].x... etc.
  421. *
  422. * @param data array of Vector2f objects to place into a new FloatBuffer
  423. */
  424. public static FloatBuffer createFloatBuffer(Vector2f... data) {
  425. if (data == null) {
  426. return null;
  427. }
  428. FloatBuffer buff = createFloatBuffer(2 * data.length);
  429. for (int x = 0; x < data.length; x++) {
  430. if (data[x] != null) {
  431. buff.put(data[x].x).put(data[x].y);
  432. } else {
  433. buff.put(0).put(0);
  434. }
  435. }
  436. buff.flip();
  437. return buff;
  438. }
  439. /**
  440. * Create a new FloatBuffer of an appropriate size to hold the specified
  441. * number of Vector2f object data.
  442. *
  443. * @param vertices
  444. * number of vertices that need to be held by the newly created
  445. * buffer
  446. * @return the requested new FloatBuffer
  447. */
  448. public static FloatBuffer createVector2Buffer(int vertices) {
  449. FloatBuffer vBuff = createFloatBuffer(2 * vertices);
  450. return vBuff;
  451. }
  452. /**
  453. * Create a new FloatBuffer of an appropriate size to hold the specified
  454. * number of Vector2f object data only if the given buffer if not already
  455. * the right size.
  456. *
  457. * @param buf
  458. * the buffer to first check and rewind
  459. * @param vertices
  460. * number of vertices that need to be held by the newly created
  461. * buffer
  462. * @return the requested new FloatBuffer
  463. */
  464. public static FloatBuffer createVector2Buffer(FloatBuffer buf, int vertices) {
  465. if (buf != null && buf.limit() == 2 * vertices) {
  466. buf.rewind();
  467. return buf;
  468. }
  469. return createFloatBuffer(2 * vertices);
  470. }
  471. /**
  472. * Sets the data contained in the given Vector2F into the FloatBuffer at the
  473. * specified index.
  474. *
  475. * @param vector
  476. * the data to insert
  477. * @param buf
  478. * the buffer to insert into
  479. * @param index
  480. * the postion to place the data; in terms of vectors not floats
  481. */
  482. public static void setInBuffer(Vector2f vector, FloatBuffer buf, int index) {
  483. buf.put(index * 2, vector.x);
  484. buf.put((index * 2) + 1, vector.y);
  485. }
  486. /**
  487. * Updates the values of the given vector from the specified buffer at the
  488. * index provided.
  489. *
  490. * @param vector
  491. * the vector to set data on
  492. * @param buf
  493. * the buffer to read from
  494. * @param index
  495. * the position (in terms of vectors, not floats) to read from
  496. * the buf
  497. */
  498. public static void populateFromBuffer(Vector2f vector, FloatBuffer buf, int index) {
  499. vector.x = buf.get(index * 2);
  500. vector.y = buf.get(index * 2 + 1);
  501. }
  502. /**
  503. * Generates a Vector2f array from the given FloatBuffer.
  504. *
  505. * @param buff
  506. * the FloatBuffer to read from
  507. * @return a newly generated array of Vector2f objects
  508. */
  509. public static Vector2f[] getVector2Array(FloatBuffer buff) {
  510. buff.clear();
  511. Vector2f[] verts = new Vector2f[buff.limit() / 2];
  512. for (int x = 0; x < verts.length; x++) {
  513. Vector2f v = new Vector2f(buff.get(), buff.get());
  514. verts[x] = v;
  515. }
  516. return verts;
  517. }
  518. /**
  519. * Copies a Vector2f from one position in the buffer to another. The index
  520. * values are in terms of vector number (eg, vector number 0 is postions 0-1
  521. * in the FloatBuffer.)
  522. *
  523. * @param buf
  524. * the buffer to copy from/to
  525. * @param fromPos
  526. * the index of the vector to copy
  527. * @param toPos
  528. * the index to copy the vector to
  529. */
  530. public static void copyInternalVector2(FloatBuffer buf, int fromPos, int toPos) {
  531. copyInternal(buf, fromPos * 2, toPos * 2, 2);
  532. }
  533. /**
  534. * Normalize a Vector2f in-buffer.
  535. *
  536. * @param buf
  537. * the buffer to find the Vector2f within
  538. * @param index
  539. * the position (in terms of vectors, not floats) of the vector
  540. * to normalize
  541. */
  542. public static void normalizeVector2(FloatBuffer buf, int index) {
  543. TempVars vars = TempVars.get();
  544. Vector2f tempVec2 = vars.vect2d;
  545. populateFromBuffer(tempVec2, buf, index);
  546. tempVec2.normalizeLocal();
  547. setInBuffer(tempVec2, buf, index);
  548. vars.release();
  549. }
  550. /**
  551. * Add to a Vector2f in-buffer.
  552. *
  553. * @param toAdd
  554. * the vector to add from
  555. * @param buf
  556. * the buffer to find the Vector2f within
  557. * @param index
  558. * the position (in terms of vectors, not floats) of the vector
  559. * to add to
  560. */
  561. public static void addInBuffer(Vector2f toAdd, FloatBuffer buf, int index) {
  562. TempVars vars = TempVars.get();
  563. Vector2f tempVec2 = vars.vect2d;
  564. populateFromBuffer(tempVec2, buf, index);
  565. tempVec2.addLocal(toAdd);
  566. setInBuffer(tempVec2, buf, index);
  567. vars.release();
  568. }
  569. /**
  570. * Multiply and store a Vector2f in-buffer.
  571. *
  572. * @param toMult
  573. * the vector to multiply against
  574. * @param buf
  575. * the buffer to find the Vector2f within
  576. * @param index
  577. * the position (in terms of vectors, not floats) of the vector
  578. * to multiply
  579. */
  580. public static void multInBuffer(Vector2f toMult, FloatBuffer buf, int index) {
  581. TempVars vars = TempVars.get();
  582. Vector2f tempVec2 = vars.vect2d;
  583. populateFromBuffer(tempVec2, buf, index);
  584. tempVec2.multLocal(toMult);
  585. setInBuffer(tempVec2, buf, index);
  586. vars.release();
  587. }
  588. /**
  589. * Checks to see if the given Vector2f is equals to the data stored in the
  590. * buffer at the given data index.
  591. *
  592. * @param check
  593. * the vector to check against - null will return false.
  594. * @param buf
  595. * the buffer to compare data with
  596. * @param index
  597. * the position (in terms of vectors, not floats) of the vector
  598. * in the buffer to check against
  599. * @return
  600. */
  601. public static boolean equals(Vector2f check, FloatBuffer buf, int index) {
  602. TempVars vars = TempVars.get();
  603. Vector2f tempVec2 = vars.vect2d;
  604. populateFromBuffer(tempVec2, buf, index);
  605. boolean eq = tempVec2.equals(check);
  606. vars.release();
  607. return eq;
  608. }
  609. //// -- INT METHODS -- ////
  610. /**
  611. * Generate a new IntBuffer using the given array of ints. The IntBuffer
  612. * will be data.length long and contain the int data as data[0], data[1]...
  613. * etc.
  614. *
  615. * @param data
  616. * array of ints to place into a new IntBuffer
  617. */
  618. public static IntBuffer createIntBuffer(int... data) {
  619. if (data == null) {
  620. return null;
  621. }
  622. IntBuffer buff = createIntBuffer(data.length);
  623. buff.clear();
  624. buff.put(data);
  625. buff.flip();
  626. return buff;
  627. }
  628. /**
  629. * Create a new int[] array and populate it with the given IntBuffer's
  630. * contents.
  631. *
  632. * @param buff
  633. * the IntBuffer to read from
  634. * @return a new int array populated from the IntBuffer
  635. */
  636. public static int[] getIntArray(IntBuffer buff) {
  637. if (buff == null) {
  638. return null;
  639. }
  640. buff.clear();
  641. int[] inds = new int[buff.limit()];
  642. for (int x = 0; x < inds.length; x++) {
  643. inds[x] = buff.get();
  644. }
  645. return inds;
  646. }
  647. /**
  648. * Create a new float[] array and populate it with the given FloatBuffer's
  649. * contents.
  650. *
  651. * @param buff
  652. * the FloatBuffer to read from
  653. * @return a new float array populated from the FloatBuffer
  654. */
  655. public static float[] getFloatArray(FloatBuffer buff) {
  656. if (buff == null) {
  657. return null;
  658. }
  659. buff.clear();
  660. float[] inds = new float[buff.limit()];
  661. for (int x = 0; x < inds.length; x++) {
  662. inds[x] = buff.get();
  663. }
  664. return inds;
  665. }
  666. //// -- GENERAL DOUBLE ROUTINES -- ////
  667. /**
  668. * Create a new DoubleBuffer of the specified size.
  669. *
  670. * @param size
  671. * required number of double to store.
  672. * @return the new DoubleBuffer
  673. */
  674. public static DoubleBuffer createDoubleBuffer(int size) {
  675. DoubleBuffer buf = ByteBuffer.allocateDirect(8 * size).order(ByteOrder.nativeOrder()).asDoubleBuffer();
  676. buf.clear();
  677. onBufferAllocated(buf);
  678. return buf;
  679. }
  680. /**
  681. * Create a new DoubleBuffer of an appropriate size to hold the specified
  682. * number of doubles only if the given buffer if not already the right size.
  683. *
  684. * @param buf
  685. * the buffer to first check and rewind
  686. * @param size
  687. * number of doubles that need to be held by the newly created
  688. * buffer
  689. * @return the requested new DoubleBuffer
  690. */
  691. public static DoubleBuffer createDoubleBuffer(DoubleBuffer buf, int size) {
  692. if (buf != null && buf.limit() == size) {
  693. buf.rewind();
  694. return buf;
  695. }
  696. buf = createDoubleBuffer(size);
  697. return buf;
  698. }
  699. /**
  700. * Creates a new DoubleBuffer with the same contents as the given
  701. * DoubleBuffer. The new DoubleBuffer is seperate from the old one and
  702. * changes are not reflected across. If you want to reflect changes,
  703. * consider using Buffer.duplicate().
  704. *
  705. * @param buf
  706. * the DoubleBuffer to copy
  707. * @return the copy
  708. */
  709. public static DoubleBuffer clone(DoubleBuffer buf) {
  710. if (buf == null) {
  711. return null;
  712. }
  713. buf.rewind();
  714. DoubleBuffer copy;
  715. if (buf.isDirect()) {
  716. copy = createDoubleBuffer(buf.limit());
  717. } else {
  718. copy = DoubleBuffer.allocate(buf.limit());
  719. }
  720. copy.put(buf);
  721. return copy;
  722. }
  723. //// -- GENERAL FLOAT ROUTINES -- ////
  724. /**
  725. * Create a new FloatBuffer of the specified size.
  726. *
  727. * @param size
  728. * required number of floats to store.
  729. * @return the new FloatBuffer
  730. */
  731. public static FloatBuffer createFloatBuffer(int size) {
  732. FloatBuffer buf = ByteBuffer.allocateDirect(4 * size).order(ByteOrder.nativeOrder()).asFloatBuffer();
  733. buf.clear();
  734. onBufferAllocated(buf);
  735. return buf;
  736. }
  737. /**
  738. * Copies floats from one position in the buffer to another.
  739. *
  740. * @param buf
  741. * the buffer to copy from/to
  742. * @param fromPos
  743. * the starting point to copy from
  744. * @param toPos
  745. * the starting point to copy to
  746. * @param length
  747. * the number of floats to copy
  748. */
  749. public static void copyInternal(FloatBuffer buf, int fromPos, int toPos, int length) {
  750. float[] data = new float[length];
  751. buf.position(fromPos);
  752. buf.get(data);
  753. buf.position(toPos);
  754. buf.put(data);
  755. }
  756. /**
  757. * Creates a new FloatBuffer with the same contents as the given
  758. * FloatBuffer. The new FloatBuffer is seperate from the old one and changes
  759. * are not reflected across. If you want to reflect changes, consider using
  760. * Buffer.duplicate().
  761. *
  762. * @param buf
  763. * the FloatBuffer to copy
  764. * @return the copy
  765. */
  766. public static FloatBuffer clone(FloatBuffer buf) {
  767. if (buf == null) {
  768. return null;
  769. }
  770. buf.rewind();
  771. FloatBuffer copy;
  772. if (buf.isDirect()) {
  773. copy = createFloatBuffer(buf.limit());
  774. } else {
  775. copy = FloatBuffer.allocate(buf.limit());
  776. }
  777. copy.put(buf);
  778. return copy;
  779. }
  780. //// -- GENERAL INT ROUTINES -- ////
  781. /**
  782. * Create a new IntBuffer of the specified size.
  783. *
  784. * @param size
  785. * required number of ints to store.
  786. * @return the new IntBuffer
  787. */
  788. public static IntBuffer createIntBuffer(int size) {
  789. IntBuffer buf = ByteBuffer.allocateDirect(4 * size).order(ByteOrder.nativeOrder()).asIntBuffer();
  790. buf.clear();
  791. onBufferAllocated(buf);
  792. return buf;
  793. }
  794. /**
  795. * Create a new IntBuffer of an appropriate size to hold the specified
  796. * number of ints only if the given buffer if not already the right size.
  797. *
  798. * @param buf
  799. * the buffer to first check and rewind
  800. * @param size
  801. * number of ints that need to be held by the newly created
  802. * buffer
  803. * @return the requested new IntBuffer
  804. */
  805. public static IntBuffer createIntBuffer(IntBuffer buf, int size) {
  806. if (buf != null && buf.limit() == size) {
  807. buf.rewind();
  808. return buf;
  809. }
  810. buf = createIntBuffer(size);
  811. return buf;
  812. }
  813. /**
  814. * Creates a new IntBuffer with the same contents as the given IntBuffer.
  815. * The new IntBuffer is seperate from the old one and changes are not
  816. * reflected across. If you want to reflect changes, consider using
  817. * Buffer.duplicate().
  818. *
  819. * @param buf
  820. * the IntBuffer to copy
  821. * @return the copy
  822. */
  823. public static IntBuffer clone(IntBuffer buf) {
  824. if (buf == null) {
  825. return null;
  826. }
  827. buf.rewind();
  828. IntBuffer copy;
  829. if (buf.isDirect()) {
  830. copy = createIntBuffer(buf.limit());
  831. } else {
  832. copy = IntBuffer.allocate(buf.limit());
  833. }
  834. copy.put(buf);
  835. return copy;
  836. }
  837. //// -- GENERAL BYTE ROUTINES -- ////
  838. /**
  839. * Create a new ByteBuffer of the specified size.
  840. *
  841. * @param size
  842. * required number of ints to store.
  843. * @return the new IntBuffer
  844. */
  845. public static ByteBuffer createByteBuffer(int size) {
  846. ByteBuffer buf = ByteBuffer.allocateDirect(size).order(ByteOrder.nativeOrder());
  847. buf.clear();
  848. onBufferAllocated(buf);
  849. return buf;
  850. }
  851. /**
  852. * Create a new ByteBuffer of an appropriate size to hold the specified
  853. * number of ints only if the given buffer if not already the right size.
  854. *
  855. * @param buf
  856. * the buffer to first check and rewind
  857. * @param size
  858. * number of bytes that need to be held by the newly created
  859. * buffer
  860. * @return the requested new IntBuffer
  861. */
  862. public static ByteBuffer createByteBuffer(ByteBuffer buf, int size) {
  863. if (buf != null && buf.limit() == size) {
  864. buf.rewind();
  865. return buf;
  866. }
  867. buf = createByteBuffer(size);
  868. return buf;
  869. }
  870. public static ByteBuffer createByteBuffer(byte... data) {
  871. ByteBuffer bb = createByteBuffer(data.length);
  872. bb.put(data);
  873. bb.flip();
  874. return bb;
  875. }
  876. public static ByteBuffer createByteBuffer(String data) {
  877. byte[] bytes = data.getBytes();
  878. ByteBuffer bb = createByteBuffer(bytes.length);
  879. bb.put(bytes);
  880. bb.flip();
  881. return bb;
  882. }
  883. /**
  884. * Creates a new ByteBuffer with the same contents as the given ByteBuffer.
  885. * The new ByteBuffer is seperate from the old one and changes are not
  886. * reflected across. If you want to reflect changes, consider using
  887. * Buffer.duplicate().
  888. *
  889. * @param buf
  890. * the ByteBuffer to copy
  891. * @return the copy
  892. */
  893. public static ByteBuffer clone(ByteBuffer buf) {
  894. if (buf == null) {
  895. return null;
  896. }
  897. buf.rewind();
  898. ByteBuffer copy;
  899. if (buf.isDirect()) {
  900. copy = createByteBuffer(buf.limit());
  901. } else {
  902. copy = ByteBuffer.allocate(buf.limit());
  903. }
  904. copy.put(buf);
  905. return copy;
  906. }
  907. //// -- GENERAL SHORT ROUTINES -- ////
  908. /**
  909. * Create a new ShortBuffer of the specified size.
  910. *
  911. * @param size
  912. * required number of shorts to store.
  913. * @return the new ShortBuffer
  914. */
  915. public static ShortBuffer createShortBuffer(int size) {
  916. ShortBuffer buf = ByteBuffer.allocateDirect(2 * size).order(ByteOrder.nativeOrder()).asShortBuffer();
  917. buf.clear();
  918. onBufferAllocated(buf);
  919. return buf;
  920. }
  921. /**
  922. * Create a new ShortBuffer of an appropriate size to hold the specified
  923. * number of shorts only if the given buffer if not already the right size.
  924. *
  925. * @param buf
  926. * the buffer to first check and rewind
  927. * @param size
  928. * number of shorts that need to be held by the newly created
  929. * buffer
  930. * @return the requested new ShortBuffer
  931. */
  932. public static ShortBuffer createShortBuffer(ShortBuffer buf, int size) {
  933. if (buf != null && buf.limit() == size) {
  934. buf.rewind();
  935. return buf;
  936. }
  937. buf = createShortBuffer(size);
  938. return buf;
  939. }
  940. public static ShortBuffer createShortBuffer(short... data) {
  941. if (data == null) {
  942. return null;
  943. }
  944. ShortBuffer buff = createShortBuffer(data.length);
  945. buff.clear();
  946. buff.put(data);
  947. buff.flip();
  948. return buff;
  949. }
  950. /**
  951. * Creates a new ShortBuffer with the same contents as the given ShortBuffer.
  952. * The new ShortBuffer is seperate from the old one and changes are not
  953. * reflected across. If you want to reflect changes, consider using
  954. * Buffer.duplicate().
  955. *
  956. * @param buf
  957. * the ShortBuffer to copy
  958. * @return the copy
  959. */
  960. public static ShortBuffer clone(ShortBuffer buf) {
  961. if (buf == null) {
  962. return null;
  963. }
  964. buf.rewind();
  965. ShortBuffer copy;
  966. if (buf.isDirect()) {
  967. copy = createShortBuffer(buf.limit());
  968. } else {
  969. copy = ShortBuffer.allocate(buf.limit());
  970. }
  971. copy.put(buf);
  972. return copy;
  973. }
  974. /**
  975. * Ensures there is at least the <code>required</code> number of entries left after the current position of the
  976. * buffer. If the buffer is too small a larger one is created and the old one copied to the new buffer.
  977. * @param buffer buffer that should be checked/copied (may be null)
  978. * @param required minimum number of elements that should be remaining in the returned buffer
  979. * @return a buffer large enough to receive at least the <code>required</code> number of entries, same position as
  980. * the input buffer, not null
  981. */
  982. public static FloatBuffer ensureLargeEnough(FloatBuffer buffer, int required) {
  983. if (buffer == null || (buffer.remaining() < required)) {
  984. int position = (buffer != null ? buffer.position() : 0);
  985. FloatBuffer newVerts = createFloatBuffer(position + required);
  986. if (buffer != null) {
  987. buffer.rewind();
  988. newVerts.put(buffer);
  989. newVerts.position(position);
  990. }
  991. buffer = newVerts;
  992. }
  993. return buffer;
  994. }
  995. public static ShortBuffer ensureLargeEnough(ShortBuffer buffer, int required) {
  996. if (buffer == null || (buffer.remaining() < required)) {
  997. int position = (buffer != null ? buffer.position() : 0);
  998. ShortBuffer newVerts = createShortBuffer(position + required);
  999. if (buffer != null) {
  1000. buffer.rewind();
  1001. newVerts.put(buffer);
  1002. newVerts.position(position);
  1003. }
  1004. buffer = newVerts;
  1005. }
  1006. return buffer;
  1007. }
  1008. public static ByteBuffer ensureLargeEnough(ByteBuffer buffer, int required) {
  1009. if (buffer == null || (buffer.remaining() < required)) {
  1010. int position = (buffer != null ? buffer.position() : 0);
  1011. ByteBuffer newVerts = createByteBuffer(position + required);
  1012. if (buffer != null) {
  1013. buffer.rewind();
  1014. newVerts.put(buffer);
  1015. newVerts.position(position);
  1016. }
  1017. buffer = newVerts;
  1018. }
  1019. return buffer;
  1020. }
  1021. public static void printCurrentDirectMemory(StringBuilder store) {
  1022. long totalHeld = 0;
  1023. // make a new set to hold the keys to prevent concurrency issues.
  1024. ArrayList<Buffer> bufs = new ArrayList<Buffer>(trackingHash.keySet());
  1025. int fBufs = 0, bBufs = 0, iBufs = 0, sBufs = 0, dBufs = 0;
  1026. int fBufsM = 0, bBufsM = 0, iBufsM = 0, sBufsM = 0, dBufsM = 0;
  1027. for (Buffer b : bufs) {
  1028. if (b instanceof ByteBuffer) {
  1029. totalHeld += b.capacity();
  1030. bBufsM += b.capacity();
  1031. bBufs++;
  1032. } else if (b instanceof FloatBuffer) {
  1033. totalHeld += b.capacity() * 4;
  1034. fBufsM += b.capacity() * 4;
  1035. fBufs++;
  1036. } else if (b instanceof IntBuffer) {
  1037. totalHeld += b.capacity() * 4;
  1038. iBufsM += b.capacity() * 4;
  1039. iBufs++;
  1040. } else if (b instanceof ShortBuffer) {
  1041. totalHeld += b.capacity() * 2;
  1042. sBufsM += b.capacity() * 2;
  1043. sBufs++;
  1044. } else if (b instanceof DoubleBuffer) {
  1045. totalHeld += b.capacity() * 8;
  1046. dBufsM += b.capacity() * 8;
  1047. dBufs++;
  1048. }
  1049. }
  1050. long heapMem = Runtime.getRuntime().totalMemory()
  1051. - Runtime.getRuntime().freeMemory();
  1052. boolean printStout = store == null;
  1053. if (store == null) {
  1054. store = new StringBuilder();
  1055. }
  1056. store.append("Existing buffers: ").append(bufs.size()).append("\n");
  1057. store.append("(b: ").append(bBufs).append(" f: ").append(fBufs).append(" i: ").append(iBufs).append(" s: ").append(sBufs).append(" d: ").append(dBufs).append(")").append("\n");
  1058. store.append("Total heap memory held: ").append(heapMem / 1024).append("kb\n");
  1059. store.append("Total direct memory held: ").append(totalHeld / 1024).append("kb\n");
  1060. 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");
  1061. if (printStout) {
  1062. System.out.println(store.toString());
  1063. }
  1064. }
  1065. /**
  1066. * Direct buffers are garbage collected by using a phantom reference and a
  1067. * reference queue. Every once a while, the JVM checks the reference queue and
  1068. * cleans the direct buffers. However, as this doesn't happen
  1069. * immediately after discarding all references to a direct buffer, it's
  1070. * easy to OutOfMemoryError yourself using direct buffers. This function
  1071. * explicitly calls the Cleaner method of a direct buffer.
  1072. *
  1073. * @param toBeDestroyed
  1074. * The direct buffer that will be "cleaned". Utilizes reflection.
  1075. *
  1076. */
  1077. public static void destroyDirectBuffer(Buffer toBeDestroyed) {
  1078. if (!toBeDestroyed.isDirect()) {
  1079. return;
  1080. }
  1081. try {
  1082. Method cleanerMethod = toBeDestroyed.getClass().getMethod("cleaner");
  1083. cleanerMethod.setAccessible(true);
  1084. Object cleaner = cleanerMethod.invoke(toBeDestroyed);
  1085. if (cleaner != null) {
  1086. Method cleanMethod = cleaner.getClass().getMethod("clean");
  1087. cleanMethod.setAccessible(true);
  1088. cleanMethod.invoke(cleaner);
  1089. } else {
  1090. // Try the alternate approach of getting the viewed buffer
  1091. Method viewedBufferMethod = toBeDestroyed.getClass().getMethod("viewedBuffer");
  1092. viewedBufferMethod.setAccessible(true);
  1093. Object viewedBuffer = viewedBufferMethod.invoke(toBeDestroyed);
  1094. if (viewedBuffer != null) {
  1095. destroyDirectBuffer( (Buffer)viewedBuffer );
  1096. } else {
  1097. Logger.getLogger(BufferUtils.class.getName()).log(Level.SEVERE, "Buffer cannot be destroyed: {0}", toBeDestroyed);
  1098. }
  1099. }
  1100. } catch (IllegalAccessException ex) {
  1101. Logger.getLogger(BufferUtils.class.getName()).log(Level.SEVERE, "{0}", ex);
  1102. } catch (IllegalArgumentException ex) {
  1103. Logger.getLogger(BufferUtils.class.getName()).log(Level.SEVERE, "{0}", ex);
  1104. } catch (InvocationTargetException ex) {
  1105. Logger.getLogger(BufferUtils.class.getName()).log(Level.SEVERE, "{0}", ex);
  1106. } catch (NoSuchMethodException ex) {
  1107. Logger.getLogger(BufferUtils.class.getName()).log(Level.SEVERE, "{0}", ex);
  1108. } catch (SecurityException ex) {
  1109. Logger.getLogger(BufferUtils.class.getName()).log(Level.SEVERE, "{0}", ex);
  1110. }
  1111. }
  1112. }