Java-Gaming.org Hi !
Featured games (83)
games approved by the League of Dukes
Games in Showcase (539)
Games in Android Showcase (132)
games submitted by our members
Games in WIP (603)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Painless way of loading textures  (Read 3300 times)
0 Members and 1 Guest are viewing this topic.
Offline Mads

JGO Ninja


Medals: 26
Projects: 3
Exp: 6 years


One for all!


« Posted 2012-02-26 22:07:06 »

Is there a really painless way of loading textures, that just works without a lot of decisions and kicking about.

So far, I've looked at org.newdawn.slick.opengl.TextureLoader, and that seems very complicated. The class pretty much relies on org.newdawn.slick.opengl.InternalTextureLoader which in turn relies on a lot more Slick specific classes, and eventually I don't feel I have the same customizability as without.

Then, I've looked at org.newdawn.spaceinvaders.lwjgl.TextureLoader, and that requires me to make decisions about things I don't understand, such as magnification filters and different pixel-formats.

While I understand how to use these classes, I don't really want to, because I don't understand how they work.

How do you guys handle this? How does textures in OpenGL even work?

Offline Riven
« League of Dukes »

« JGO Overlord »


Medals: 842
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #1 - Posted 2012-02-26 22:17:08 »

The best way to learn is to dive in the raw API, not some highlevel library.

There are many tutorials that explain OpenGL texture loading in an easy to follow manner. Yes, there will be a mention of magnification filters, but it's not like that needs more than 3 lines of text to explain the gist of it. It's all pretty simple, don't let the abstraction layers of libraries fool you.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social
Offline Mads

JGO Ninja


Medals: 26
Projects: 3
Exp: 6 years


One for all!


« Reply #2 - Posted 2012-02-26 22:46:28 »

The best way to learn is to dive in the raw API, not some highlevel library.

There are many tutorials that explain OpenGL texture loading in an easy to follow manner. Yes, there will be a mention of magnification filters, but it's not like that needs more than 3 lines of text to explain the gist of it. It's all pretty simple, don't let the abstraction layers of libraries fool you.

Seemed like a great idea. Then I went here http://www.opengl.org/sdk/docs/man/, and I have no clue how to use any of the texture related methods.
Afterwards I head over here, http://www.opengl.org/sdk/docs/tutorials/, where even less helpful articles are dying.

Where is the good basic documentation that shows you how to use these things, at a basic level?

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline davedes
« Reply #3 - Posted 2012-02-27 08:32:44 »

Matthias Mann wrote a very good texture loading library. However, if you want to learn OpenGL and understand exactly what's going on, like Riven said, you should dive into OpenGL more directly.

Texture creation looks like this:
  • Decode your texture into a readable format (e.g. RGBA)
  • Generate an ID with glGenTextures
  • Bind the texture, set up any filtering/wrap modes with glTexParameteri
  • Upload the texture data from step one using glTexImage2D

It's not very painful compared to many other aspects of OpenGL, but for somebody who is used to Java2D it may seem very long-winded.

Here's some code from my own library, utilizing Matthias' PNGDecoder. It also corrects NPOT images if necessary.
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95  
   //there are other targets, but this is what you'll generally be using
   private final int TEXTURE_TARGET = GL11.GL_TEXTURE_2D;
   //we can set this to true to ensure that ALL textures are created with POT sizes
   private final boolean FORCE_POWER_OF_TWO = true;

   private int imageWidth, imageHeight;
   private int texWidth, texHeight;
   private float normalizedWidth=1f, normalizedHeight=1f;
   private int texture;

   public void initTexture() throws IOException {
      ContextCapabilities caps = GLContext.getCapabilities();
      ByteBuffer buf = null;
      int numComponents;

      //Decode the image using Matthias Mann's PNGDecoder
      try {
         URL url = TextureTest.class.getClassLoader().getResource("res/1.png");
         InputStream in = url.openStream();
         PNGDecoder decoder = new PNGDecoder(in);
         imageWidth = texWidth = decoder.getWidth();
         imageHeight = texHeight = decoder.getHeight();
         if (imageWidth==0||imageHeight==0)
            throw new IOException("image is zero sized");

         //this is the format we will tell PNGDecoder to decode to
         PNGDecoder.Format format = PNGDecoder.Format.RGBA;

         //"num components" is how many color components exist in this format
         //GL_RGBA - 4 components (red, green, blue, alpha)
         //GL_RGB - 3 components, no alpha
         numComponents = format.getNumComponents();

         try {
            //we create a ByteBuffer to hold our array of pixels (i.e. image)
            buf = BufferUtils.createByteBuffer(imageWidth * imageHeight * numComponents);
            decoder.decode(buf, imageWidth*numComponents, format);
         } finally {
            try { in.close(); }
            catch (IOException e) {}
         }
         buf.flip();
      } catch (IOException e) {
         throw new RuntimeException("error decoding the image");
      }

      //whether NPOT textures size is supported
      boolean npotSupported = caps.GL_ARB_texture_non_power_of_two;

      //on some systems NPOT might not be supported, also we may want to force POT for efficiency
      boolean usePOT = !npotSupported || FORCE_POWER_OF_TWO;
      if (usePOT) {
         texWidth = toPowerOfTwo(imageWidth);
         texHeight = toPowerOfTwo(imageHeight);
      }

      //get an ID handle for the OpenGL texture
      texture = GL11.glGenTextures();

      //bind it
      GL11.glBindTexture(TEXTURE_TARGET, texture);

      //to be safe, reset our unpack values
      GL11.glPixelStorei(GL11.GL_UNPACK_ROW_LENGTH, 0);
      GL11.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 1);

      //no mipmapping; just regular LINEAR filtering
      GL11.glTexParameteri(TEXTURE_TARGET, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
      GL11.glTexParameteri(TEXTURE_TARGET, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);

      //this is the "internal format" of the texture; could also be RGB, LUMINANCE or RED, for example
      int internalFormat = GL11.GL_RGBA;
      //this is the "data format", i.e. how the ByteBuffer is organized (we told PNGDecoder to use RGBA)
      int dataFmt = GL11.GL_RGBA;
      int dataType = GL11.GL_UNSIGNED_BYTE;

      //if we need to correct the texture to a power-of-two size...
      if (texWidth!=imageWidth || texHeight!=imageHeight) {
         //OpenGL allows you to pass a "null" ByteBuffer, however it seems unreliable on my system
         //here's a workaround:
         ByteBuffer emptyData = BufferUtils.createByteBuffer(texWidth * texHeight * numComponents);

         //the full texture
         GL11.glTexImage2D(TEXTURE_TARGET, 0, internalFormat, texWidth, texHeight, 0, dataFmt, dataType, emptyData);

         //now upload the non-power-of-two image using the decoded PNG data
         GL11.glTexSubImage2D(TEXTURE_TARGET, 0, 0, 0, imageWidth, imageHeight, dataFmt, dataType, buf);

         //and we adjust the texcoord values to match the new ratio
         normalizedWidth = imageWidth / (float)texWidth;
         normalizedHeight = imageHeight / (float)texHeight;
      } else { //the image is POT or NPOT is supported... no worries
         GL11.glTexImage2D(TEXTURE_TARGET, 0, internalFormat, texWidth, texHeight, 0, dataFmt, dataType, buf);
      }
   }


Then your textures should be ready to go. If you want to render them as 2D sprites in ortho view, the code might look like this:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
      float x = 50, y = 50;

      GL11.glEnable(TEXTURE_TARGET);
      GL11.glBindTexture(TEXTURE_TARGET, texture);
      GL11.glBegin(GL11.GL_QUADS);
         GL11.glTexCoord2f(0f, 0f); //TOP LEFT
         GL11.glVertex2f(x, y);
         GL11.glTexCoord2f(0f, normalizedHeight); //BOTTOM LEFT
         GL11.glVertex2f(x, y+imageHeight);
         GL11.glTexCoord2f(normalizedWidth, normalizedHeight); //BOTTOM RIGHT
         GL11.glVertex2f(x+imageWidth, y+imageHeight);
         GL11.glTexCoord2f(normalizedWidth, 0f); //TOP RIGHT
         GL11.glVertex2f(x+imageWidth, y);
      GL11.glEnd();

Offline Nate

« JGO Bitwise Duke »


Medals: 158
Projects: 4
Exp: 14 years


Esoteric Software


« Reply #4 - Posted 2012-02-27 18:42:17 »

1  
Texture texture = new Texture("something.png");

That looks pretty simple. You guess the lib. :p If you want to dig into how it works, there is two parts to the problem. First is to decode the image from PNG or JPG or whatever to bytes that represent the unencoded bitmap. Second is to upload the data to the GPU. For libgdx, there is a Pixmap class that is used to load and decode the image and then Texture just binds and makes the GL call to upload the data. Texture is a bit more complex than that because it allows customizing texture loading and reloading textures if the GL context is lost. The real guts of Pixmap is actually in Gdx2DPixmap, which is a native wrapper over gdx2d, which is a tiny native lib that uses stb_image (a small lib for loading images) for image decoding and adds things like converting between GL formats and drawing lines and circles.

The native stuff is easy to read, inline with the Java source, due to Mario's super fancy "gdx-jnigen" build tool:
https://code.google.com/p/libgdx/source/browse/trunk/gdx/src/com/badlogic/gdx/graphics/g2d/Gdx2DPixmap.java#235
Crazy, but cool! Cool

Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

rwatson462 (37 views)
2014-12-15 09:26:44

Mr.CodeIt (30 views)
2014-12-14 19:50:38

BurntPizza (62 views)
2014-12-09 22:41:13

BurntPizza (99 views)
2014-12-08 04:46:31

JscottyBieshaar (59 views)
2014-12-05 12:39:02

SHC (74 views)
2014-12-03 16:27:13

CopyableCougar4 (77 views)
2014-11-29 21:32:03

toopeicgaming1999 (138 views)
2014-11-26 15:22:04

toopeicgaming1999 (127 views)
2014-11-26 15:20:36

toopeicgaming1999 (38 views)
2014-11-26 15:20:08
Resources for WIP games
by kpars
2014-12-18 10:26:14

Understanding relations between setOrigin, setScale and setPosition in libGdx
by mbabuskov
2014-10-09 22:35:00

Definite guide to supporting multiple device resolutions on Android (2014)
by mbabuskov
2014-10-02 22:36:02

List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!