Java-Gaming.org    
Featured games (81)
games approved by the League of Dukes
Games in Showcase (499)
Games in Android Showcase (118)
games submitted by our members
Games in WIP (567)
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  
  LWJGL: Loading a texture, the imperative way.  (Read 929 times)
0 Members and 1 Guest are viewing this topic.
Offline tom_mai78101
« Posted 2013-12-31 12:43:50 »

Please ignore this post, if you really care about code design. This piece of code isn't really cleaned up.

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  
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import javax.imageio.ImageIO;

//I only use LWJGL, nothing more.
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL11;

public class TextureLoader {
   
   public static class TempTexture {
      public ByteBuffer buffer;
      public int width;
      public int height;
      public int id;
   }
   
   public static TempTexture test = loadTexture("/icon.png");
   
   public static TempTexture loadTexture(String filename) {
      //Just to make sure I don't hog my laptop computer's memory and stick to an old Intel's graphics card.
     if (test != null) {
         GL11.glDeleteTextures(test.id);
         test.buffer.clear();
         test.buffer = null;
         test = null;
      }
     
     
      TempTexture result = null;
      try {
         BufferedImage img = ImageIO.read(TextureLoader.class.getResource(filename));
         int[] imgData = img.getRGB(0, 0, img.getWidth(), img.getHeight(), null, 0, img.getWidth());
         result = new TempTexture();
         result.width = img.getWidth();
         result.height = img.getHeight();
         int size = Math.max(result.width, result.height);
         result.buffer = BufferUtils.createByteBuffer(size * size * 4);
         result.buffer.order(ByteOrder.nativeOrder());
         result.buffer.position(0);
         for (int y = 0; y < result.height; y++) {
            for (int x = 0; x < result.width; x++) {
               int pixel = imgData[x + y * result.width];
               //RGBA is the preferred OpenGL format for loading texture.
              //Source:      http://www.opengl.org/wiki/Common_Mistakes#Texture_upload_and_pixel_reads
             
               result.buffer.put((byte) ((pixel >> 16) & 0xFF));
               result.buffer.put((byte) ((pixel >> 8) & 0xFF));
               result.buffer.put((byte) ((pixel) & 0xFF));
               result.buffer.put((byte) ((pixel >> 24) & 0xFF));
               
               //Do note the bitwise shift signs. Please do experiment and see for yourself.              
              //Green hue
              /*result.buffer.put((byte) ((pixel << 16) & 0xFF));
               result.buffer.put((byte) ((pixel) & 0xFF));
               result.buffer.put((byte) ((pixel << 8) & 0xFF));
               result.buffer.put((byte) ((pixel << 24) & 0xFF));*/

               
               //Blue hue
              /*result.buffer.put((byte) ((pixel << 16) & 0xFF));
               result.buffer.put((byte) ((pixel << 8) & 0xFF));
               result.buffer.put((byte) ((pixel) & 0xFF));
               result.buffer.put((byte) ((pixel << 24) & 0xFF));*/

               
               //Red hue
              /*result.buffer.put((byte) ((pixel) & 0xFF));
               result.buffer.put((byte) ((pixel << 16) & 0xFF));
               result.buffer.put((byte) ((pixel << 8) & 0xFF));
               result.buffer.put((byte) ((pixel << 24) & 0xFF));*/

               
               //Blackness
              /*result.buffer.put((byte) ((pixel << 24) & 0xFF));
               result.buffer.put((byte) ((pixel << 16) & 0xFF));
               result.buffer.put((byte) ((pixel << 8) & 0xFF));
               result.buffer.put((byte) ((pixel) & 0xFF));*/

               
               //Normal
              /*result.buffer.put((byte) ((pixel >> 16) & 0xFF));
               result.buffer.put((byte) ((pixel >> 8) & 0xFF));
               result.buffer.put((byte) ((pixel) & 0xFF));
               result.buffer.put((byte) ((pixel >> 24) & 0xFF));*/

            }
         }
         result.buffer.position(0);
      }
      catch (IOException e) {
         e.printStackTrace();
      }
      return result;
   }
}


So, to load a texture in a simple program:

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  
import org.lwjgl.LWJGLException;
import org.lwjgl.input.Keyboard;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;

public class Program {
   
   public Program() {
      try {
         Display.setDisplayMode(new DisplayMode(640, 480));
         Display.create();
      }
      catch (LWJGLException e) {
         e.printStackTrace();
         Display.destroy();
         System.exit(-1);
      }
      initialize();
   }
   
   public void initialize() {
      GL11.glMatrixMode(GL11.GL_PROJECTION);
      GL11.glLoadIdentity();
      GL11.glOrtho(0, 640, 480, 0, 1, -1);
     
      GL11.glMatrixMode(GL11.GL_MODELVIEW);
      GL11.glClearColor(1f, 1f, 1f, 1f);
     
   }
   
   public void start() {
      while (!Display.isCloseRequested()) {
         GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);
         
         if (Keyboard.isKeyDown(Keyboard.KEY_A)) {
            TextureLoader.test = TextureLoader.loadTexture("/icon.png");
         }
         
         GL11.glEnable(GL11.GL_TEXTURE_2D);
         TextureLoader.test.id = GL11.glGenTextures();
         GL11.glBindTexture(GL11.GL_TEXTURE_2D, TextureLoader.test.id);
         GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
         GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
         GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, TextureLoader.test.width, TextureLoader.test.height, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, TextureLoader.test.buffer);
         GL11.glBegin(GL11.GL_QUADS);
         {
            //Matching coordinate positive/negative signs is a must, in order to create directionally specific textures.
           //Texture coordinates (s, t) ranges from -1 to 1, with -1 being the lowest (analogous to 0 on the number line).
           GL11.glTexCoord2f(1f, -1f);
            GL11.glVertex2i(200, -200);
            GL11.glTexCoord2f(1f, 1f);
            GL11.glVertex2i(200, 200);
            GL11.glTexCoord2f(-1f, 1f);
            GL11.glVertex2i(-200, 200);
            GL11.glTexCoord2f(-1f, 1f);
            GL11.glVertex2i(-200, 200);
         }
         GL11.glEnd();
         GL11.glDisable(GL11.GL_TEXTURE_2D);
         Display.update();
         Display.sync(60);
      }
      Display.destroy();
      System.exit(0);
   }
   
   public static void main(String[] arg) {
      new Program().start();
   }
}


Created this piece of code using a laptop running Windows XP with an old Intel graphics card. And yes, it did not support shaders.
Offline Troubleshoots

JGO Knight


Medals: 36
Exp: 7-9 months


Damn maths.


« Reply #1 - Posted 2013-12-31 13:37:01 »

The loading of the texture looks similar to, but even messier than this (same naming conventions etc.). Note that
result.buffer.position(0)
can be changed to
result.buffer.rewind()
. The use of a nested class is not necessary and to be honest, neither is the use of a static method to load the pixel data. The design of this as a whole is terrible IMO. You could handle the texture as an instance which would be better OOP, e.g:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
public class Texture {

   private int id;
   private int width;
   private int height;

   public Texture(String path) {
      // load the texture here...
  }

   public int getId() {
      return id;
   }

   // getters for height and width...

}

This would also reduce the number of OpenGL functions the user has to implicitly call. Making everything static is not the way to go.

Why are all OpenGL tutorials written in Brainf**k?
Offline Danny02
« Reply #2 - Posted 2013-12-31 13:52:44 »

@ Troubleshoots, it's also no good design to load the texture in the constructor.
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Troubleshoots

JGO Knight


Medals: 36
Exp: 7-9 months


Damn maths.


« Reply #3 - Posted 2013-12-31 13:54:17 »

@ Troubleshoots, it's also no good design to load the texture in the constructor.


Why not?

Why are all OpenGL tutorials written in Brainf**k?
Offline opiop65

JGO Kernel


Medals: 154
Projects: 7
Exp: 3 years


JumpButton Studios


« Reply #4 - Posted 2013-12-31 13:57:28 »

Static design is actually quite fine, and I use it in my GLUtils library, which I've used to make multiple games, so I have no idea why you think a static design is terrible. Your code should go something like this:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
public class Texture {

   public int id;
   public int width;
   public int height;
   
   private Texture(int id, int width, int height) {
      this.id = id;
      this.width = width;
      this.height = height;
   }

   public static Texture loadTexture(String name) {
      // Load the image
     BufferedImage img = //load pixels
     return new Texture(textureID, img.getWidth(), img.getHeight());
   }
   
   //other things like binding
}

I prefer it to be that way so that I don't have to manually create new texture objects and litter my code with useless object creating calls.

Quote
Looks similar to, but even messier than this.
Also, of course it looks like the one in the tutorial series, that's the standard way of loading textures. Don't try to tell someone else they're wrong until you have more experience.

Offline Troubleshoots

JGO Knight


Medals: 36
Exp: 7-9 months


Damn maths.


« Reply #5 - Posted 2013-12-31 14:01:54 »

I have no idea why you think a static design is terrible.

Java is an object orientated language. The use of statics should be avoided wherever possible.

Quote
Looks similar to, but even messier than this.
Also, of course it looks like the one in the tutorial series, that's the standard way of loading textures. Don't try to tell someone else they're wrong until you have more experience.

I was referring to the similarity of using static methods and intermediate mode. The reason I was saying that it was messier is because there is no need to use a nested class for handling the texture data. That's bad design. Also there's no standard way of loading textures. That's just the way most people do it using the Java API.

Why are all OpenGL tutorials written in Brainf**k?
Offline opiop65

JGO Kernel


Medals: 154
Projects: 7
Exp: 3 years


JumpButton Studios


« Reply #6 - Posted 2013-12-31 14:05:01 »

It's not intermediate mode, its immediate mode, first off.

Second off, you say that the use of static should be avoided, I say a good programmer should use static when he/she needs to. Building your program entirely on a static model is probably not smart, but it's also not smart to completely avoid static like its the plague. I think you need to re-evaluate your use of static and realize that you can use, just you have to be careful with it. Not to mention the fact that statically calling a method like I showed you above is actually easier than creating a new instance of Texture manually, and has the same outcome.

Quote
Also there's no standard way of loading textures. That's just the way most people do it using the Java API.
This is not true. Everywhere I've looked, this is the general way people have loaded textures in OpenGL.

Offline Troubleshoots

JGO Knight


Medals: 36
Exp: 7-9 months


Damn maths.


« Reply #7 - Posted 2013-12-31 14:13:05 »

It's not intermediate mode, its immediate mode, first off.

Second off, you say that the use of static should be avoided, I say a good programmer should use static when he/she needs to. Building your program entirely on a static model is probably not smart, but it's also not smart to completely avoid static like its the plague. I think you need to re-evaluate your use of static and realize that you can use, just you have to be careful with it. Not to mention the fact that statically calling a method like I showed you above is actually easier than creating a new instance of Texture manually, and has the same outcome.

I don't see much difference between
Texture texture = new Texture("rgirn.png")
and
Texture texture = Texture.loadTexture("rgirn.png")
. When I say you should avoid the use of statics wherever possible I mean you should avoid the use of statics wherever possible. If you had a House class there is no reason to use a static method to create a House object, thus I don't see a reason to use a static method that returns a Texture object.

Regarding loading the pixel data via the constructor; I don't see a reason why:

1  
2  
3  
4  
5  
6  
public Texture(String path) {
   // load pixel data
  width = image.getWidth();
   height = image.getHeight();
   id = glGenTextures();
}

should become:

1  
2  
3  
4  
public static Texture loadTexture(String path) {
   // load pixel data
  return new Texture(glGenTextures(), image.getWidth(), image.getHeight(), pixelData);
}


EDIT: To add to that, the only good use of something being designed in this way is using the singleton pattern. This seems to be what the OP is doing, but the OP is using it in the wrong way. The singleton pattern is used to restrict having more than one instance of a class.

Why are all OpenGL tutorials written in Brainf**k?
Offline opiop65

JGO Kernel


Medals: 154
Projects: 7
Exp: 3 years


JumpButton Studios


« Reply #8 - Posted 2013-12-31 14:38:44 »

I never said using a nested class was a good idea, and I also do not support OP's decision on using those. However, I still stand by my argument.

Offline tom_mai78101
« Reply #9 - Posted 2013-12-31 14:56:21 »

Seems like no one likes imperative Java programming. I will turn away.
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Troubleshoots

JGO Knight


Medals: 36
Exp: 7-9 months


Damn maths.


« Reply #10 - Posted 2013-12-31 15:08:06 »

Seems like no one likes imperative Java programming. I will turn away.

Object orientated programming is a form of imperative programming. What you're doing is structuring of an object orientated program. This is no more an imperative form of programming than OOP is; this is only a bad way of structuring object orientated code.

Why are all OpenGL tutorials written in Brainf**k?
Online SHC
« Reply #11 - Posted 2013-12-31 16:00:37 »


How is my article messy? Please elaborate.

Offline davedes
« Reply #12 - Posted 2013-12-31 16:29:26 »

You're all missing the easiest way to load a BufferedImage: (source)

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
int size = width * height;
if (buffer == null || buffer.capacity() < size) {
    buffer = BufferUtils.createIntBuffer(size);
}
texture.bind();
buffer.rewind();
buffer.put(pixels, 0, size);
buffer.rewind();

GL11. glTexImage2D(GL11.GL_TEXTURE_2D,
     0,
     GL11.GL_RGBA,
     width,
     height,
     0,
     GL12.GL_BGRA,
     GL12.GL_UNSIGNED_INT_8_8_8_8_REV,
     buffer);


If you're using PNG you might rather use Matthias' decoder, see here:
https://github.com/mattdesl/lwjgl-basics/wiki/Textures

Smiley


The main downside to doing the texture loading in the constructor is that it's hidden away, e.g. from a user who might want the same utility for a more advanced texture loader (say, for cube maps or texture arrays). IMHO it's not a big deal if a simple GL utility library does this -- you can't be expected to support every possible need of the user.

LibGDX also loads textures in the constructor, although it's abstracted out the image and texture loading to provide easier support for float texture and such.

Offline Troubleshoots

JGO Knight


Medals: 36
Exp: 7-9 months


Damn maths.


« Reply #13 - Posted 2013-12-31 18:41:59 »


I didn't exactly mean it that way. I meant that the way the texture is loaded, i.e from a static method and using pretty much the same naming conventions, is similar. The reason I implied that that's messy you can read above.

Why are all OpenGL tutorials written in Brainf**k?
Offline Riven
« League of Dukes »

JGO Overlord


Medals: 801
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #14 - Posted 2013-12-31 19:47:59 »

Quote
1  
2  
//Matching coordinate positive/negative signs is a must, in order to create directionally specific textures.
//Texture coordinates (s, t) ranges from -1 to 1, with -1 being the lowest (analogous to 0 on the number line)
Please read the OpenGL spec on how texcoords are normalized, how they map to texels and how repeating/clamping works Smiley


Quote
1  
2  
3  
4  
5  
6  
7  
8  
9  
public static TempTexture loadTexture(String filename) {
      //Just to make sure I don't hog my laptop computer's memory and stick to an old Intel's graphics card.
     if (test != null) {
         GL11.glDeleteTextures(test.id);
         test.buffer.clear();
         test.buffer = null;
         test = null;
      }
 
Every time you load in a new texture, you destroy the previous one... Clueless



Moved out of [shared code] due to being generally misinformed. Pointing

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Online SHC
« Reply #15 - Posted 2014-01-01 01:55:25 »

Quote
Texture coordinates (s, t) ranges from -1 to 1

I think they range from 0 to 1 and not -1 to 1.

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.

Pippogeek (39 views)
2014-09-24 16:13:29

Pippogeek (30 views)
2014-09-24 16:12:22

Pippogeek (19 views)
2014-09-24 16:12:06

Grunnt (44 views)
2014-09-23 14:38:19

radar3301 (27 views)
2014-09-21 23:33:17

BurntPizza (63 views)
2014-09-21 02:42:18

BurntPizza (32 views)
2014-09-21 01:30:30

moogie (40 views)
2014-09-21 00:26:15

UprightPath (50 views)
2014-09-20 20:14:06

BurntPizza (54 views)
2014-09-19 03:14:18
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

List of Learning Resources
by SilverTiger
2014-07-31 16:26:06

List of Learning Resources
by SilverTiger
2014-07-31 11:54:12

HotSpot Options
by dleskov
2014-07-08 01:59:08
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!