title: Simple Java OpenGL Textures Manager
body: <p>I'm trying to make a simple textures manager for a 2D tile-based project.</p>
  
  <p>What I have is a class that has a hashmap of strings (texture name) and textures. If the name doesn't exist in the hashmap, it uses TextureIO.newTexture(..) to create it and store it into the hashmap.</p>
  
  <p>This is the error I get when I try to load a texture: </p>
  
  <pre><code>Exception in thread "Timer-0" javax.media.opengl.GLException: java.lang.IllegalArgumentException: Illegally formatted version identifier: "null"
      at javax.media.opengl.Threading.invokeOnOpenGLThread(Threading.java:271)
      at javax.media.opengl.GLCanvas.maybeDoSingleThreadedWorkaround(GLCanvas.java:410)
      at javax.media.opengl.GLCanvas.display(GLCanvas.java:244)
      at com.sun.opengl.util.Animator.display(Animator.java:144)
      at com.sun.opengl.util.FPSAnimator$1.run(FPSAnimator.java:95)
      at java.util.TimerThread.mainLoop(Unknown Source)
      at java.util.TimerThread.run(Unknown Source)
  Caused by: java.lang.IllegalArgumentException: Illegally formatted version identifier: "null"
      at com.sun.opengl.impl.FunctionAvailabilityCache$Version.&lt;init&gt;(FunctionAvailabilityCache.java:354)
      at com.sun.opengl.impl.FunctionAvailabilityCache.initAvailableExtensions(FunctionAvailabilityCache.java:133)
      at com.sun.opengl.impl.FunctionAvailabilityCache.isExtensionAvailable(FunctionAvailabilityCache.java:104)
      at com.sun.opengl.impl.GLContextImpl.isExtensionAvailable(GLContextImpl.java:351)
      at com.sun.opengl.impl.GLImpl.isExtensionAvailable(GLImpl.java:30493)
      at com.sun.opengl.util.texture.Texture.updateImage(Texture.java:416)
      at com.sun.opengl.util.texture.Texture.updateImage(Texture.java:381)
      at com.sun.opengl.util.texture.Texture.&lt;init&gt;(Texture.java:182)
      at com.sun.opengl.util.texture.TextureIO.newTexture(TextureIO.java:445)
      at com.sun.opengl.util.texture.TextureIO.newTexture(TextureIO.java:465)
      at dqs.manager.TextureManager.loadTexture(TextureManager.java:31)
      at dqs.world.World.draw(World.java:59)
      at dqs.scene.GameScene.display(GameScene.java:58)
      at com.sun.opengl.impl.GLDrawableHelper.display(GLDrawableHelper.java:78)
      at javax.media.opengl.GLCanvas$DisplayAction.run(GLCanvas.java:435)
      at com.sun.opengl.impl.GLDrawableHelper.invokeGL(GLDrawableHelper.java:194)
      at javax.media.opengl.GLCanvas$DisplayOnEventDispatchThreadAction.run(GLCanvas.java:452)
      at java.awt.event.InvocationEvent.dispatch(Unknown Source)
      at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
      at java.awt.EventQueue.access$000(Unknown Source)
      at java.awt.EventQueue$1.run(Unknown Source)
      at java.awt.EventQueue$1.run(Unknown Source)
      at java.security.AccessController.doPrivileged(Native Method)
      at java.security.AccessControlContext$1.doIntersectionPrivilege(Unknown Source)
      at java.awt.EventQueue.dispatchEvent(Unknown Source)
      at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
      at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
      at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
      at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
      at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
      at java.awt.EventDispatchThread.run(Unknown Source)
  Caused by: java.lang.NullPointerException
      at com.sun.opengl.impl.FunctionAvailabilityCache$Version.&lt;init&gt;(FunctionAvailabilityCache.java:309)
      ... 30 more
  Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
      at com.sun.opengl.impl.mipmap.Mipmap.closestFit(Mipmap.java:252)
      at com.sun.opengl.impl.mipmap.Mipmap.gluBuild2DMipmaps(Mipmap.java:726)
      at javax.media.opengl.glu.GLU.gluBuild2DMipmapsJava(GLU.java:1525)
      at javax.media.opengl.glu.GLU.gluBuild2DMipmaps(GLU.java:1581)
      at com.sun.opengl.util.texture.Texture.updateImage(Texture.java:523)
      at com.sun.opengl.util.texture.Texture.updateImage(Texture.java:381)
      at com.sun.opengl.util.texture.Texture.&lt;init&gt;(Texture.java:182)
      at com.sun.opengl.util.texture.TextureIO.newTexture(TextureIO.java:445)
      at com.sun.opengl.util.texture.TextureIO.newTexture(TextureIO.java:465)
      at dqs.manager.TextureManager.loadTexture(TextureManager.java:31)
      at dqs.world.World.draw(World.java:59)
      at dqs.scene.GameScene.display(GameScene.java:58)
      at com.sun.opengl.impl.GLDrawableHelper.display(GLDrawableHelper.java:78)
      at javax.media.opengl.GLCanvas$DisplayAction.run(GLCanvas.java:435)
      at com.sun.opengl.impl.GLDrawableHelper.invokeGL(GLDrawableHelper.java:194)
      at javax.media.opengl.GLCanvas.maybeDoSingleThreadedWorkaround(GLCanvas.java:412)
      at javax.media.opengl.GLCanvas.display(GLCanvas.java:244)
      at javax.media.opengl.GLCanvas.paint(GLCanvas.java:277)
      at sun.awt.RepaintArea.paintComponent(Unknown Source)
      at sun.awt.RepaintArea.paint(Unknown Source)
      at sun.awt.windows.WComponentPeer.handleEvent(Unknown Source)
      at java.awt.Component.dispatchEventImpl(Unknown Source)
      at java.awt.Component.dispatchEvent(Unknown Source)
      at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
      at java.awt.EventQueue.access$000(Unknown Source)
      at java.awt.EventQueue$1.run(Unknown Source)
      at java.awt.EventQueue$1.run(Unknown Source)
      at java.security.AccessController.doPrivileged(Native Method)
      at java.security.AccessControlContext$1.doIntersectionPrivilege(Unknown Source)
      at java.security.AccessControlContext$1.doIntersectionPrivilege(Unknown Source)
      at java.awt.EventQueue$2.run(Unknown Source)
      at java.awt.EventQueue$2.run(Unknown Source)
      at java.security.AccessController.doPrivileged(Native Method)
      at java.security.AccessControlContext$1.doIntersectionPrivilege(Unknown Source)
      at java.awt.EventQueue.dispatchEvent(Unknown Source)
      at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
      at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
      at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
      at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
      at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
      at java.awt.EventDispatchThread.run(Unknown Source)
  </code></pre>
  
  <p>The error occurs the moment I call loadTexture from within my TextureManager.</p>
  
  <p>Here is the TextureManager code:</p>
  
  <pre><code>public class TextureManager {
  
      private static HashMap&lt;String, Texture&gt; textureMap;
  
      public TextureManager() {
  
          textureMap = new HashMap&lt;String, Texture&gt;();
  
      }
  
      public static void loadTexture(String name) {
  
          if(textureMap.containsKey(name)) return;
  
          try {
  
              textureMap.put(name, TextureIO.newTexture(new File("textures/" + name + ".png"), true));
          }
          catch (GLException e) {
  
              e.printStackTrace();
          }
          catch (IOException e) {
  
              e.printStackTrace();
          }
      }
  
      public static void bindTexture(String name) {
  
          textureMap.get(name).bind();
      }
  }
  </code></pre>
  
  <p>A TextureManager object has already been created earlier in the code via:</p>
  
  <pre><code>new TextureManager();
  </code></pre>
  
  <p>This is the code that I called it using:</p>
  
  <pre><code>TextureManager.loadTexture("tree");
  </code></pre>
  
  <p>The path textures/tree.png exists too.</p>
  
  <p>I did something similar to this in an older project, but instead of using a hashmap, I hard coded a variable in the TextureManager for every texture I used (not many). I suspect It's because the thread lacks a GL context because my old TextureManager passed GL in via the constructor, but never used it in the code. The draw function that called the loadTexture function also passed in a GL variable.</p>