Java, LWJGL, OpenGL 1.1, decoding BufferedImage to Bytebuffer and binding to OpenGL across classes -
i've been attempting solve problem without luck. have 4 classes, main class, object class, sprite class , image loader class.
i'm attempting load png using image loader , using method found here: http://www.java-gaming.org/topics/bufferedimage-to-lwjgl-texture/25516/msg/220280/view.html#msg220280 convert bytebuffer, , bind opengl.
the image in it's own seperate resource folder. should being drawn this: (http://i.imgur.com/j8gbu4c.png) (32x32), i'm seeing white box has dimensions of image, not actual texture.
if has idea of go fix i'd appreciate it. i'm new opengl , looking avoid using external library in order learn how actual code works. thanks.
updated!
to following, implemented suggestion provided vallentin, quad taking color of first pixel in image. i've attempted implementing image loader provided c.s here. i'm receiving error:
javax.imageio.iioexception: error reading png image data @ com.sun.imageio.plugins.png.pngimagereader.readimage(pngimagereader.java:1291) @ com.sun.imageio.plugins.png.pngimagereader.read(pngimagereader.java:1560) @ pimageloader.loadbin(pimageloader.java:60) @ monkeybars.main(monkeybars.java:35) @ sun.reflect.nativemethodaccessorimpl.invoke0(native method) @ sun.reflect.nativemethodaccessorimpl.invoke(nativemethodaccessorimpl.java:39) @ sun.reflect.delegatingmethodaccessorimpl.invoke(delegatingmethodaccessorimpl.java:25) @ java.lang.reflect.method.invoke(method.java:597) @ com.intellij.rt.execution.application.appmain.main(appmain.java:120) caused by: javax.imageio.iioexception: destination type imagereadparam not match! @ javax.imageio.imagereader.getdestination(imagereader.java:2862) @ com.sun.imageio.plugins.png.pngimagereader.readimage(pngimagereader.java:1263) ... 8 more exception in thread "main" java.lang.nullpointerexception @ pimageloader.loadpsprite(pimageloader.java:75) @ monkeybars.main(monkeybars.java:35) @ sun.reflect.nativemethodaccessorimpl.invoke0(native method) @ sun.reflect.nativemethodaccessorimpl.invoke(nativemethodaccessorimpl.java:39) @ sun.reflect.delegatingmethodaccessorimpl.invoke(delegatingmethodaccessorimpl.java:25) @ java.lang.reflect.method.invoke(method.java:597) @ com.intellij.rt.execution.application.appmain.main(appmain.java:120)
i'm using intellij 12 on windows 7, using java 6. image i'm trying load linked above. if has ideas, i'm open suggestions.
main block:
public static void main(string[] args){ system.out.println("sup!"); int width = 800 ; int height = 600; try{ display.setdisplaymode(new displaymode(width,height)); display.settitle("the playground"); display.create(); }catch (lwjglexception e){ e.printstacktrace(); display.destroy(); system.exit(1); } //initialize opengl gl11.glmatrixmode(gl11.gl_projection); gl11.glloadidentity(); gl11.glortho(0, width, height, 0f, 1f, -1f); gl11.glmatrixmode(gl11.gl_modelview); gl11.glloadidentity(); gl11.glenable(gl11.gl_texture_2d); gl11.gldisable(gl11.gl_depth_test); gl11.glenable(gl11.gl_blend); pobject mrredsquare = new pobject(300f,300f,pimageloader.loadpsprite(pimageloader.loadbin("test.png"))); while(!display.iscloserequested()){ gl11.glclear(gl11.gl_color_buffer_bit | gl11.gl_depth_buffer_bit); gl11.glblendfunc(gl11.gl_src_alpha, gl11.gl_one_minus_src_alpha); mrredsquare.drawme(); display.sync(60); display.update(); } } }
texture loader, new method.
public static bufferedimage loadbin(string filepath){ bufferedimage image; // reader imagereader ir = imageio.getimagereadersbyformatname("png").next(); // default param imagereadparam p = ir.getdefaultreadparam(); p.setdestinationtype( // define image type return if supported imagetypespecifier.createinterleaved( colorspace.getinstance(colorspace.cs_srgb), new int[] {0, 1, 2, 3}, // <-- order of color bands return bytes in desired order databuffer.type_byte, true, false) ); try{ inputstream stream = pimageloader.class.getclassloader().getresourceasstream(filepath); imageinputstream imagestream = imageio.createimageinputstream(stream); ir.setinput(imagestream); image = ir.read(0, p); }catch(exception e){ system.out.print("imageloader cannot obtain asset"); e.printstacktrace(); return null; } return image; }
older code, kept archival purposes
main:
public static void main(string[] args){ system.out.println("sup!"); try{ display.setdisplaymode(new displaymode(800,600)); display.settitle("the playground"); display.create(); }catch (lwjglexception e){ e.printstacktrace(); display.destroy(); system.exit(1); } //initialize opengl gl11.glmatrixmode(gl11.gl_projection); gl11.glloadidentity(); gl11.glortho(0, 800, 0, 600, 1, -1); gl11.glmatrixmode(gl11.gl_modelview); pobject mrredsquare = new pobject(300,300,pimageloader.loadpsprite(pimageloader.loadbi("square.png"))); while(!display.iscloserequested()){ gl11.glclear(gl11.gl_color_buffer_bit | gl11.gl_depth_buffer_bit); mrredsquare.drawme(); display.sync(60); display.update(); } }
object (draw code):
public void drawme(){ // store current model matrix gl11.glpushmatrix(); // bind appropriate texture sprite texture.bind(); // translate right location , prepare draw gl11.gltranslatef(x, y, 0); // draw quad textured match sprite gl11.glbegin(gl11.gl_quads); { gl11.gltexcoord2f(0, 0); gl11.glvertex2f(0, 0); gl11.gltexcoord2f(0, texture.getheight()); gl11.glvertex2f(0, height); gl11.gltexcoord2f(texture.getwidth(), texture.getheight()); gl11.glvertex2f(width,height); gl11.gltexcoord2f(texture.getwidth(), 0); gl11.glvertex2f(width,0); } gl11.glend(); // restore model view matrix prevent contamination gl11.glpopmatrix(); }
texture:
public class psprite { protected bytebuffer spritedata; protected bufferedimage spriteimage; protected int id; protected int width; protected int height; //--------------------------------------------------------------------------------------- //constructors: psprite(bufferedimage si, bytebuffer s, int i){ spriteimage = si; spritedata = s; id = i; width = spriteimage.getwidth(); height = spriteimage.getheight(); } //--------------------------------------------------------------------------------------- //methods: public void bind(){ gl11.glbindtexture(gl11.gl_texture_2d, id); }
imageloader:
public class pimageloader { public static bufferedimage loadbi(string filepath){ bufferedimage image; try{ inputstream input = pimageloader.class.getresourceasstream(filepath); image = imageio.read(input); }catch (exception e){ system.out.print("imageloader: cannot obtain asset."); e.printstacktrace(); return null; } return image; } public static psprite loadpsprite(bufferedimage image){ //http://www.java-gaming.org/topics/bufferedimage-to-lwjgl-texture/25516/msg/220280/view.html#msg220280 int pixels[] = new int[image.getwidth() * image.getheight()]; image.getrgb(0, 0, image.getwidth(), image.getheight(), pixels, 0, image.getwidth()); bytebuffer buffer = bufferutils.createbytebuffer(image.getwidth() * image.getheight() * 4); // <-- 4 rgba, 3 rgb for(int y = 0; y < image.getheight(); y++){ for(int x = 0; x < image.getwidth(); x++){ int pixel = pixels[y * image.getwidth() + x]; buffer.put((byte) ((pixel >> 16) & 0xff)); // red component buffer.put((byte) ((pixel >> 8) & 0xff)); // green component buffer.put((byte) (pixel & 0xff)); // blue component buffer.put((byte) ((pixel >> 24) & 0xff)); // alpha component. rgba } } buffer.flip(); int textureid = glgentextures(); //generate texture id glbindtexture(gl_texture_2d, textureid); // setup wrap mode gltexparameteri(gl_texture_2d, gl_texture_wrap_s, gl12.gl_clamp_to_edge); gltexparameteri(gl_texture_2d, gl_texture_wrap_t, gl12.gl_clamp_to_edge); //setup texture scaling filtering gltexparameteri(gl_texture_2d, gl_texture_min_filter, gl_linear); gltexparameteri(gl_texture_2d, gl_texture_mag_filter, gl_linear); //send texel data opengl glteximage2d(gl_texture_2d, 0, gl_rgba8, image.getwidth(), image.getheight(), 0, gl_rgba, gl_unsigned_byte, buffer); return new psprite(image, buffer, textureid); } }
there lot of problems code. important issues have found are:
1) problems of yours, start fact not using 32-bit image (i.e. rgba) using 24-bit image (i.e. rgb).
so code have used specifying image type wrong. should use following:
p.setdestinationtype( // define image type return if supported imagetypespecifier.createinterleaved( colorspace.getinstance(colorspace.cs_srgb), new int[] {0, 1, 2}, // <-- expecting 3 color bands since image rgb databuffer.type_byte, false, //<-- alpha, image doesn't have false) );
2) per comments instrunctions of image converting process, supposed use bytebuffer
of size width * height * 3
. in general true. seems lwjgl not let (it forces rectangular dimensions?) should leave value 4
, modify alpha like:
buffer.put((byte) 0xff); // alpha 1.0 i.e. opaque
this should load image correctly. please note additional problem in original code (other forgetting use glenable(gl_texture_2d)
) not setting blend function (btw can set once not need set in every frame). if have used 32-bit texture transparent areas appear black.
3) third problem when giving texture coordinates use gltexcoord2f(texture.getwidth(), texture.getheight());
wrong because texture coordinates can range [0, 1]
. way work, if had setup texture parameters gl_texture_wrap_s
, gl_texture_wrap_t
both use gl_repeat
(the default). setting gl_clamp_to_edge
. if give texture values greater 1
final image have color of image border.
so should modify code below:
gl11.glbegin(gl11.gl_quads); { gl11.gltexcoord2f(0, 0); // <-- gl11.glvertex2f(0, 0); gl11.gltexcoord2f(0, 1); // <-- gl11.glvertex2f(0, height); gl11.gltexcoord2f(1, 1); // <-- gl11.glvertex2f(width, height); gl11.gltexcoord2f(1, 0); // <-- gl11.glvertex2f(width,0); }
my advice when experimenting textures, use large simple image can see what's happenning (correct alpha, upside-down etc) e.g. red rectangle inner blue rectangle or that, able identify problem texture other "it not work".
i hope helps
Comments
Post a Comment