Show Posts
|
|
Pages: [1] 2 3 ... 15
|
|
1
|
Game Development / Shared Code / Re: zShapes - Resolution Independent Curve Rendering
|
on: 2010-05-30 18:38:28
|
Yeah, if I get this working I will probably start re-writing it. I'm getting farther, but now I seem to be having trouble with compiling a fragment shader: Caused by: java.lang.RuntimeException: Failed to compile fragment shader: curve.fsh 0(17) : error C7506: OpenGL does not define the global type half4 0(17) : error C7557: OpenGL does not allow Cg-style semantics 0(17) : error C7530: OpenGL requires main to return void 0(21) : error C7506: OpenGL does not define the global type half3 0(22) : error C7506: OpenGL does not define the global type half I'm really surprised there isn't an SVG / vector font API for OpenGL already in common use. I would think this would be a really popular feature.
|
|
|
|
|
2
|
Game Development / Shared Code / Re: zShapes - Resolution Independent Curve Rendering
|
on: 2010-05-30 17:47:26
|
I created a font map and loaded it like: 1 2
| fontMap = new FontMap(".../test.zfm"); font = new Font(fontMap, 32.0f); |
Then to render it I used: 1
| font.render("Hello World!", false, 0.0f); |
I get no errors but nothing is displaying on the screen...is there something else I need to do to make this function?
|
|
|
|
|
6
|
Java Game APIs & Engines / JOGL Development / JOGL2 Using GLWindow
|
on: 2009-09-30 20:17:14
|
I have the following code that does display, but when I put the mouse cursor over the window it shows a busy cursor and I have no ability to interact with it: 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
| package test;
import javax.media.opengl.GL; import javax.media.opengl.GLAutoDrawable; import javax.media.opengl.GLEventListener;
import com.sun.javafx.newt.opengl.GLWindow; import com.sun.opengl.util.Animator;
public class TestJOGL2 implements GLEventListener { private GLWindow window; public TestJOGL2() { window = GLWindow.create(); window.setTitle("Testing"); window.setSize(800, 600); window.addGLEventListener(this); Animator a = new Animator(window); a.setRunAsFastAsPossible(false); a.start(); window.setAutoDrawableClient(true); window.setVisible(true); } public static void main(String[] args) throws Exception { new TestJOGL2(); }
public void display(GLAutoDrawable d) { d.getGL().getGL2().glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); }
public void dispose(GLAutoDrawable arg0) { }
public void init(GLAutoDrawable arg0) { }
public void reshape(GLAutoDrawable arg0, int arg1, int arg2, int arg3, int arg4) { } } |
I'm sure there's something simple I'm missing here, but since there seems to be a great lack of information on JOGL2 I'm at a loss to figuring out what it is.
|
|
|
|
|
7
|
Java Game APIs & Engines / JOGL Development / Textures in GL_VERSION_1_1
|
on: 2009-09-19 17:45:06
|
|
I'm trying to write a GL 1.1 compatible texture renderer and I keep getting GL_INVALID_ENUM for this call: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 128, 128, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, null)
I'm betting it's the GL_UNSIGNED_INT_8_8_8_8_REV that is causing the problem (based on the GL spec), but what is a good format to change to?
|
|
|
|
|
11
|
Java Game APIs & Engines / JOGL Development / JOGL 2 - OpenMax?
|
on: 2009-08-27 19:08:10
|
|
I've been looking a little at JOGL 2 and noticed some references to OpenMax. My question is, what level of support exists in JOGL 2 for OpenMax and can that be leveraged in JOGL on the Desktop to play video?
|
|
|
|
|
12
|
Java Game APIs & Engines / JOGL Development / Re: TextureRenderer == Black Magic
|
on: 2009-08-18 19:57:31
|
Well, after removing my foot from my mouth yet again I realized that I was calling "gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);" not "gl.glBlendFunc(GL.GL_ONE, GL.GL_ONE_MINUS_SRC_ALPHA);" It's just so easy to glaze over code that looks like it's the same.  Well, anyway, now I have to multiply my r, g, and b to set the alpha, but it works and it looks great, so I'm happy. Thanks Riven for your help.  Though I feel like an idiot for it taking so long and so many posts to figure out the problem, now that I have I hope someone else might avoid the same stupid problem. 
|
|
|
|
|
13
|
Java Game APIs & Engines / JOGL Development / Re: TextureRenderer == Black Magic
|
on: 2009-08-18 18:57:20
|
Wow, I finally solved it! I really don't understand why this would make a difference, but I was trying any random change I could make to see if there was a change and I stumbled upon it. If I call: gl.glBlendFunc(GL.GL_ONE, GL.GL_ONE_MINUS_SRC_ALPHA); Right before I bind the texture it looks exactly as it should. I haven't been doing this because I set the blend function during initialization and thought that was sufficient. Apparently it is not...can someone explain to me why I need to set this before drawing each time instead of being able to just set it once?
|
|
|
|
|
14
|
Java Game APIs & Engines / JOGL Development / TextureRenderer == Black Magic
|
on: 2009-08-18 18:45:35
|
Yes, it's me again...and yes, it's the same exact problem I still haven't been able to solve. I have a concise example showing exactly the problem I'm having and a side-by-side comparison to TextureRenderer that looks exactly as I'd like my texture to appear. I've walked through the TextureRenderer, Texture, and TextureData classes line-by-line and still cannot find what it's doing that makes this massive difference in appearance:  The first line of text is mine and the second line is TextureRenderer. Here's my source code: 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
| package test;
import java.awt.Color; import java.awt.Font; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.image.BufferedImage;
import javax.imageio.ImageIO; import javax.media.opengl.GL;
import com.sun.opengl.util.j2d.TextureRenderer;
public class TestShape2 extends TestBasic { private Shape shape1; private Shape shape2; private TextureRenderer renderer; public void initialize(GL gl) { super.initialize(gl); try { shape1 = new Shape(gl); { BufferedImage image = ImageIO.read(getClass().getClassLoader().getResource("resource/crate.png")); BufferedImage crate = new BufferedImage(256, 256, BufferedImage.TYPE_INT_ARGB_PRE); { Graphics2D g = crate.createGraphics(); g.setColor(new Color(1.0f, 0.0f, 0.0f, 1.0f)); g.fillRect(0, 0, 256, 256); g.drawImage(image, 0, 0, null); g.dispose(); } shape1.updateTexture(gl, crate); } shape2 = new Shape(gl); { BufferedImage text = new BufferedImage(256, 256, BufferedImage.TYPE_INT_ARGB_PRE); { Graphics2D g = text.createGraphics(); g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); Font f = new Font("Arial", Font.BOLD, 24); g.setFont(f); g.drawString("Testing", 50.0f, 50.0f); g.dispose(); } shape2.updateTexture(gl, text); } renderer = new TextureRenderer(256, 256, true, true); { Graphics2D g = renderer.createGraphics(); g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); Font f = new Font("Arial", Font.BOLD, 24); g.setFont(f); g.drawString("Testing", 50.0f, 50.0f); g.dispose(); renderer.markDirty(0, 0, 256, 256); } } catch(Throwable t) { t.printStackTrace(); } } public void draw(GL gl) { gl.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); gl.glTranslatef(-50.0f, -50.0f, -500.0f); shape1.draw(gl, 256.0f, 256.0f); shape2.draw(gl, 256.0f, 256.0f); renderer.begin3DRendering(); { renderer.draw3DRect(0.0f, -50.0f, 0.0f, 0, 0, 256, 256, 1.0f); renderer.end3DRendering(); } } public static void main(String[] args) throws Exception { new TestShape2(); } } |
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 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
| package test;
import java.awt.Color; import java.io.InputStream; import java.net.URL;
import javax.media.opengl.DebugGL; import javax.media.opengl.GL; import javax.media.opengl.GLAutoDrawable; import javax.media.opengl.GLCanvas; import javax.media.opengl.GLCapabilities; import javax.media.opengl.GLEventListener; import javax.media.opengl.glu.GLU; import javax.swing.JFrame;
import com.sun.opengl.util.Animator; import com.sun.opengl.util.GLUT;
public abstract class TestBasic implements GLEventListener { protected GLU glu; protected GLUT glut; protected GLCanvas canvas; protected Animator animator; public TestBasic() { glu = new GLU(); glut = new GLUT(); JFrame frame = new JFrame(getClass().getSimpleName()); { frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(800, 600); frame.setBackground(Color.WHITE);
GLCapabilities caps = new GLCapabilities(); { } canvas = new GLCanvas(caps); { canvas.addGLEventListener(this); animator = new Animator(canvas);
frame.add(canvas); }
frame.setVisible(true); } animator.start(); } public void init(GLAutoDrawable drawable) { GL gl = new DebugGL(drawable.getGL()); gl.setSwapInterval(1); gl.glShadeModel(GL.GL_SMOOTH); gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); gl.glClearDepth(1.0f); gl.glEnable(GL.GL_LINE_SMOOTH); gl.glEnable(GL.GL_BLEND); gl.glEnable(GL.GL_POLYGON_SMOOTH); gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA); gl.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST); gl.glHint(GL.GL_LINE_SMOOTH_HINT, GL.GL_NICEST); gl.glHint(GL.GL_POLYGON_SMOOTH_HINT, GL.GL_NICEST); gl.glEnable(GL.GL_TEXTURE_2D); initialize(gl); } public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged) { }
public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { GL gl = drawable.getGL(); if (height <= 0) { height = 1; } float h = (float) width / (float) height; gl.glViewport(0, 0, width, height); gl.glMatrixMode(GL.GL_PROJECTION); gl.glLoadIdentity(); glu.gluPerspective(45.0f, h, 1.0, 20000.0); gl.glMatrixMode(GL.GL_MODELVIEW); gl.glLoadIdentity(); } public void display(GLAutoDrawable drawable) { GL gl = new DebugGL(drawable.getGL()); gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); gl.glLoadIdentity(); gl.glTranslatef(0.0f, 0.0f, -5.0f); draw(gl); } public void initialize(GL gl) { } public abstract void draw(GL gl);
public static final String getShaderSource(String resourceName) { try { URL url = TestBasic.class.getClassLoader().getResource("resource/" + resourceName); InputStream is = url.openStream(); if (is == null) return null; StringBuffer buffer = new StringBuffer(); int i; while ((i = is.read()) != -1) { buffer.append((char)i); } return buffer.toString(); } catch(Throwable t) { throw new RuntimeException(t); } } } |
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
| package test;
import java.awt.image.BufferedImage; import java.awt.image.DataBuffer; import java.awt.image.DataBufferInt; import java.awt.image.SampleModel; import java.awt.image.SinglePixelPackedSampleModel; import java.nio.Buffer; import java.nio.IntBuffer;
import javax.media.opengl.GL;
public class Shape { private int textureId; public Shape(GL gl) { int[] tmp = new int[1]; gl.glGenTextures(1, tmp, 0); textureId = tmp[0]; } public final void updateTexture(GL gl, BufferedImage image) { SampleModel sm = image.getRaster().getSampleModel(); int scanlineStride = ((SinglePixelPackedSampleModel)sm).getScanlineStride(); int internalFormat = GL.GL_RGBA; int pixelFormat = GL.GL_BGRA; int pixelType = GL.GL_UNSIGNED_INT_8_8_8_8_REV; int alignment = 1; DataBuffer data = image.getRaster().getDataBuffer(); Buffer buffer = IntBuffer.wrap(((DataBufferInt)data).getData()); gl.glBindTexture(GL.GL_TEXTURE_2D, textureId); gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_GENERATE_MIPMAP, GL.GL_TRUE); gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, internalFormat, image.getWidth(), image.getHeight(), 0, pixelFormat, pixelType, null); int[] align = new int[1]; int[] rowLength = new int[1]; int[] skipRows = new int[1]; int[] skipPixels = new int[1]; gl.glGetIntegerv(GL.GL_UNPACK_ALIGNMENT, align, 0); gl.glGetIntegerv(GL.GL_UNPACK_ROW_LENGTH, rowLength, 0); gl.glGetIntegerv(GL.GL_UNPACK_SKIP_ROWS, skipRows, 0); gl.glGetIntegerv(GL.GL_UNPACK_SKIP_PIXELS, skipPixels, 0); gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, alignment); gl.glPixelStorei(GL.GL_UNPACK_ROW_LENGTH, scanlineStride); gl.glPixelStorei(GL.GL_UNPACK_SKIP_ROWS, 0); gl.glPixelStorei(GL.GL_UNPACK_SKIP_PIXELS, 0); gl.glTexSubImage2D(GL.GL_TEXTURE_2D, 0, 0, 0, image.getWidth(), image.getHeight(), pixelFormat, pixelType, buffer); gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, align[0]); gl.glPixelStorei(GL.GL_UNPACK_ROW_LENGTH, rowLength[0]); gl.glPixelStorei(GL.GL_UNPACK_SKIP_ROWS, skipRows[0]); gl.glPixelStorei(GL.GL_UNPACK_SKIP_PIXELS, skipPixels[0]); } public final void draw(GL gl, float width, float height) { gl.glBindTexture(GL.GL_TEXTURE_2D, textureId); gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR_MIPMAP_LINEAR); gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR); gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, GL.GL_CLAMP_TO_EDGE); gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, GL.GL_CLAMP_TO_EDGE); gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, GL.GL_MODULATE); gl.glBegin(GL.GL_QUADS); { gl.glTexCoord2f(0.0f, 1.0f); gl.glVertex3f(0.0f, 0.0f, 0.0f); gl.glTexCoord2f(1.0f, 1.0f); gl.glVertex3f(width, 0.0f, 0.0f); gl.glTexCoord2f(1.0f, 0.0f); gl.glVertex3f(width, height, 0.0f); gl.glTexCoord2f(0.0f, 0.0f); gl.glVertex3f(0.0f, height, 0.0f); gl.glEnd(); } } } |
|
|
|
|
|
17
|
Java Game APIs & Engines / JOGL Development / Re: Mipmapping Frustrations
|
on: 2009-08-10 03:02:27
|
I get about the same result whether I use HIGH or AUTO...HIGH seems slightly better, but nothing compares to what TextureRenderer generates. I was going to start reading about GL_TEXTURE_FILTER_CONTROL, but looking through TextureRenderer it does not appear to be used there at all, so I just assumed that's not the solution. I'm really at a loss at this point, I can switch between TextureRenderer and my code and get this drastic difference and I've debugged through line-by-line comparing what TextureRenderer is doing and I can't find the difference. I don't suppose the person that wrote TextureRenderer hangs out in here ever? 
|
|
|
|
|
19
|
Java Game APIs & Engines / JOGL Development / Re: Mipmapping Frustrations
|
on: 2009-08-09 22:05:32
|
Maybe a silly question... but:
why are you mipmapping? the text is not scaled, and if it is, it shouldn't be - just render is a bit smaller
I'm creating a UI system that can be rendered once and as the screen resizes it scales. As well this is being displayed in standard projection so eventually I would like the UI to display in a full 3D context so mipmapping is ultimately necessary no matter what. I've been tempted to just have it regenerate the textures as the size changes, but that only solves the immediate problem, not the long-term one. It's obvious that TextureRenderer is able to accomplish what I want, it's just a matter of figuring out how it does it. I guess that's where I need to go now and dig line-by-line until I figure out what it's doing differently I was just hoping someone here might be able to point out what I'm missing.
|
|
|
|
|
21
|
Java Game APIs & Engines / JOGL Development / Re: Mipmapping Frustrations
|
on: 2009-08-09 20:25:29
|
Riven, after reading that and applying what it suggested I still don't seem to be getting the crisp appearance I'd like. Perhaps someone will see something I'm missing in my code? 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 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
| package org.jseamless.gl;
import java.awt.Graphics2D; import java.awt.Image; import java.awt.RenderingHints; import java.awt.image.BufferedImage; import java.awt.image.SampleModel; import java.awt.image.SinglePixelPackedSampleModel; import java.awt.image.WritableRaster; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.IntBuffer;
import javax.media.opengl.GL;
import org.jseamless.Component;
public class GLTexture { private int textureId; private boolean recreate; private int width; private int height; public GLTexture(GL gl) { int[] id = new int[] {textureId}; gl.glGenTextures(1, id, 0); textureId = id[0]; } public void update(GL gl, BufferedImage image, int x, int y, int width, int height, int mipmap, Component component) { if (image.getType() != BufferedImage.TYPE_INT_ARGB_PRE) { throw new RuntimeException("Unhandled BufferedImage format. Use TYPE_INT_ARGB_PRE. Type: " + image.getType()); } if ((this.width != width) || (this.height != height)) { recreate = true; } int imageFormat = GL.GL_RGBA; int textureFormat = GL.GL_BGRA; int type = GL.GL_UNSIGNED_INT_8_8_8_8_REV; gl.glBindTexture(GL.GL_TEXTURE_2D, textureId); gl.glDisable(GL.GL_LIGHTING); gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR); gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, mipmap != Shape.MIPMAP_OFF ? GL.GL_LINEAR_MIPMAP_LINEAR : GL.GL_LINEAR); gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, GL.GL_CLAMP_TO_EDGE); gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, GL.GL_CLAMP_TO_EDGE); if (mipmap == Shape.MIPMAP_AUTO) { gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_GENERATE_MIPMAP, GL.GL_TRUE); } gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 1); gl.glPixelStorei(GL.GL_UNPACK_SKIP_ROWS, 0); gl.glPixelStorei(GL.GL_UNPACK_SKIP_PIXELS, 0); int mipmaps = (int)Math.floor(Math.log(Math.max(width, height)) / Math.log(2)) + 1; if (recreate) { gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, imageFormat, width, height, 0, textureFormat, type, null); } updateSubImage(gl, image, x, y, width, height, 0, imageFormat, textureFormat, type); if (mipmap == Shape.MIPMAP_HIGH) { ReusableGraphic rg1 = ReusableGraphic.get("mipmap1"); ReusableGraphic rg2 = ReusableGraphic.get("mipmap2"); int w = width; int h = height; boolean inverse = false; BufferedImage img = image; int pw = width; int ph = height; for (int i = 1; i < mipmaps; i++) { w = Math.max(1, w / 2); h = Math.max(1, h / 2); if (w == 0) { w = 1; } else if (h == 0) { h = 1; } ReusableGraphic rg = inverse ? rg2 : rg1; Graphics2D g = rg.request(w, h); try { component.rendering.setHints(g, component); g.drawImage(img, 0, 0, w, h, x, y, pw, ph, null); g.dispose(); if (recreate) { gl.glTexImage2D(GL.GL_TEXTURE_2D, i, imageFormat, w,h, 0, textureFormat, type, null); } updateSubImage(gl, rg.getImage(), x, y, w, h, i, imageFormat, textureFormat, type); } finally { img = rg.getImage(); inverse = !inverse; rg.release(); pw = w; ph = h; } } } this.width = width; this.height = height; recreate = false; } private void updateSubImage(GL gl, BufferedImage image, int x, int y, int width, int height, int level, int imageFormat, int textureFormat, int type) { int[] data = new int[width]; WritableRaster raster = image.getRaster(); ByteBuffer buffer = ByteBuffer.allocateDirect((width * height) * 4); buffer.order(ByteOrder.nativeOrder()); IntBuffer pixels = buffer.asIntBuffer(); for (int i = 0; i < height; i++) { raster.getDataElements(x, y + i, width, 1, data); pixels.put(data); } pixels.flip(); gl.glTexSubImage2D(GL.GL_TEXTURE_2D, level, 0, 0, width, height, textureFormat, type, pixels); } public void draw(GL gl, int textureCoordinatesId) { gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, GL.GL_MODULATE); gl.glBindTexture(GL.GL_TEXTURE_2D, textureId); gl.glEnableClientState(GL.GL_TEXTURE_COORD_ARRAY); gl.glBindBufferARB(GL.GL_ARRAY_BUFFER_ARB, textureCoordinatesId); gl.glTexCoordPointer(2, GL.GL_FLOAT, 0, 0); } public void dispose(GL gl) { gl.glDeleteTextures(1, new int[] {textureId}, 0); } } |
|
|
|
|
|
23
|
Java Game APIs & Engines / JOGL Development / Re: Mipmapping Frustrations
|
on: 2009-08-04 15:41:53
|
|
Thanks for the information Riven, it did seem to make it look a lot better, but the performance drop was more than considerable, it was devastating. I think that link you gave me should help with performance though.
Thanks again for helping get on the right track.
|
|
|
|
|
25
|
Java Game APIs & Engines / JOGL Development / Mipmapping Frustrations
|
on: 2009-08-02 17:18:27
|
I have spent the past few weeks working to understand and implement my own alternative to TextureRenderer and though I think I'm nearly done, I'm struggling with mipmapping still. If I use GL_GENERATE_MIPMAP the quality in a zoomed out state for text is not crisp, so I endeavored to write my own mipmap generator to use BufferedImage scaling with bicubic interpolation to give a better appearance, but even with this it does not appear crisp:  The relevant source code follows. I don't know what else I can do to make the appearance better: 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
| public void update(GL gl, BufferedImage image, int x, int y, int width, int height, int mipmap, Component component) { if (image.getType() != BufferedImage.TYPE_INT_ARGB_PRE) { throw new RuntimeException("Unhandled BufferedImage format. Use TYPE_INT_ARGB_PRE. Type: " + image.getType()); } if ((this.width != width) || (this.height != height)) { recreate = true; } int imageFormat = GL.GL_RGBA; int textureFormat = GL.GL_BGRA; int type = GL.GL_UNSIGNED_INT_8_8_8_8_REV; gl.glBindTexture(GL.GL_TEXTURE_2D, textureId); gl.glDisable(GL.GL_LIGHTING); gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR); gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, mipmap != Shape.MIPMAP_OFF ? GL.GL_LINEAR_MIPMAP_LINEAR : GL.GL_LINEAR); gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, GL.GL_CLAMP_TO_EDGE); gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, GL.GL_CLAMP_TO_EDGE); if (mipmap == Shape.MIPMAP_AUTO) { gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_GENERATE_MIPMAP, GL.GL_TRUE); } gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 1); int mipmaps = (int)Math.floor(Math.log(Math.max(width, height)) / Math.log(2)) + 1; if (recreate) { gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, imageFormat, width, height, 0, textureFormat, type, null); } updateSubImage(gl, image, x, y, width, height, 0, imageFormat, textureFormat, type); if (mipmap == Shape.MIPMAP_HIGH) { ReusableGraphic rg = ReusableGraphic.get("mipmap"); int w = width; int h = height; for (int i = 1; i < mipmaps; i++) { w = Math.max(1, w / 2); h = Math.max(1, h / 2); if (w == 0) { w = 1; } else if (h == 0) { h = 1; } Graphics2D g = rg.request(w, h); try { component.rendering.setHints(g, component); g.drawImage(image, 0, 0, w, h, x, y, width, height, null); g.dispose(); if (recreate) { gl.glTexImage2D(GL.GL_TEXTURE_2D, i, imageFormat, w,h, 0, textureFormat, type, null); } updateSubImage(gl, rg.getImage(), x, y, w, h, i, imageFormat, textureFormat, type); } finally { rg.release(); } } } this.width = width; this.height = height; recreate = false; } private void updateSubImage(GL gl, BufferedImage image, int x, int y, int width, int height, int level, int imageFormat, int textureFormat, int type) { int[] data = new int[width]; WritableRaster raster = image.getRaster(); ByteBuffer buffer = ByteBuffer.allocateDirect((width * height) * 4); buffer.order(ByteOrder.nativeOrder()); IntBuffer pixels = buffer.asIntBuffer(); for (int i = 0; i < height; i++) { raster.getDataElements(x, y + i, width, 1, data); pixels.put(data); } pixels.flip(); gl.glTexSubImage2D(GL.GL_TEXTURE_2D, level, 0, 0, width, height, textureFormat, type, pixels); } |
|
|
|
|
|
26
|
Java Game APIs & Engines / JOGL Development / Re: Generating Mipmap Problems
|
on: 2009-07-21 21:16:56
|
I'm going to revise this significantly now that I finally have something that works.  This seems to appear on the screen exactly as it should...is there anything else I need to do in order to properly support NPOT textures? Now the only hurdle I have left is PBOs.
|
|
|
|
|
27
|
Java Game APIs & Engines / JOGL Development / Re: Generating Mipmap Problems
|
on: 2009-07-21 20:00:48
|
Hey, changing it fixed the problem. I swapped out for the alpha mode I know is supported and everything works correctly now. Thanks guys. Just in case anyone is interested, here is the final source code: 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 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
| package test;
import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.awt.image.DataBufferByte; import java.awt.image.DataBufferInt; import java.io.File; import java.nio.ByteBuffer; import java.nio.FloatBuffer; import java.nio.IntBuffer;
import javax.imageio.ImageIO; import javax.media.opengl.GL;
import com.sun.opengl.util.BufferUtil;
public class TestMipmapping extends TestBasic { private int[] vertexes; private int[] textures; private int[] textureVbo; private int programId; private int vertexShaderId; private int fragmentShaderId; private FloatBuffer textureCoordinates; public void initialize(GL gl) { super.initialize(gl); BufferedImage image = null; try { image = ImageIO.read(getClass().getClassLoader().getResource("resource/testing.png")); BufferedImage tmp = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB_PRE); Graphics2D g = tmp.createGraphics(); g.drawImage(image, 0, 0, null); g.dispose(); image = tmp; } catch(Throwable t) { t.printStackTrace(); } FloatBuffer buffer = BufferUtil.newFloatBuffer(12); { buffer.put(0.0f); buffer.put(0.0f); buffer.put(0.0f); buffer.put(image.getWidth()); buffer.put(0.0f); buffer.put(0.0f); buffer.put(image.getWidth()); buffer.put(image.getHeight()); buffer.put(0.0f); buffer.put(0.0f); buffer.put(image.getHeight()); buffer.put(0.0f); buffer.rewind(); } vertexes = new int[1]; gl.glGenBuffersARB(1, vertexes, 0); gl.glBindBufferARB(GL.GL_ARRAY_BUFFER_ARB, vertexes[0]); gl.glBufferDataARB(GL.GL_ARRAY_BUFFER_ARB, buffer.capacity() * 4, buffer, GL.GL_STATIC_DRAW_ARB); textureCoordinates = BufferUtil.newFloatBuffer(8); { textureCoordinates.put(0.0f); textureCoordinates.put(1.0f); textureCoordinates.put(1.0f); textureCoordinates.put(1.0f); textureCoordinates.put(1.0f); textureCoordinates.put(0.0f); textureCoordinates.put(0.0f); textureCoordinates.put(0.0f); textureCoordinates.rewind(); } textureVbo = new int[1]; gl.glGenBuffersARB(1, textureVbo, 0); gl.glBindBufferARB(GL.GL_ARRAY_BUFFER_ARB, textureVbo[0]); gl.glBufferDataARB(GL.GL_ARRAY_BUFFER_ARB, textureCoordinates.capacity() * 4, textureCoordinates, GL.GL_STATIC_DRAW_ARB); textures = new int[1]; gl.glGenTextures(1, textures, 0); gl.glBindTexture(GL.GL_TEXTURE_2D, textures[0]); try { DataBufferInt dbb = (DataBufferInt)image.getRaster().getDataBuffer(); int[] data = dbb.getData(); IntBuffer pixels = BufferUtil.newIntBuffer(data.length); pixels.put(data); pixels.flip(); int mode = 3; gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR); gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, mode == 1 ? GL.GL_LINEAR : GL.GL_LINEAR_MIPMAP_LINEAR); if (mode == 2) { gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_GENERATE_MIPMAP, GL.GL_TRUE); } gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 1); gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGBA, image.getWidth(), image.getHeight(), 0, GL.GL_BGRA, GL.GL_UNSIGNED_INT_8_8_8_8_REV, pixels); if (mode == 3) { int mipmaps = (int)Math.floor(Math.log(Math.max(image.getWidth(), image.getHeight())) / Math.log(2)) + 1; int w = image.getWidth(); int h = image.getHeight(); for (int i = 1; i < mipmaps; i++) { w = Math.max(1, w / 2); h = Math.max(1, h / 2); if (w == 0) { w = 1; } else if (h == 0) { h = 1; } System.out.println(w + "x" + h + " - " + i); BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB_PRE); Graphics2D g = bi.createGraphics(); g.drawImage(image, 0, 0, w, h, null); g.dispose(); DataBufferInt dbb2 = (DataBufferInt)bi.getRaster().getDataBuffer(); int[] data2 = dbb2.getData(); IntBuffer pixels2 = BufferUtil.newIntBuffer(data2.length); pixels2.put(data2); pixels2.flip(); gl.glTexImage2D(GL.GL_TEXTURE_2D, i, GL.GL_RGBA, bi.getWidth(), bi.getHeight(), 0, GL.GL_BGRA, GL.GL_UNSIGNED_INT_8_8_8_8_REV, pixels2); } System.out.println("Positions Created: " + mipmaps); } } catch(Throwable t) { t.printStackTrace(); } programId = gl.glCreateProgramObjectARB(); vertexShaderId = gl.glCreateShaderObjectARB(GL.GL_VERTEX_SHADER_ARB); String source = getShaderSource("texture_coordinates.vert"); gl.glShaderSourceARB(vertexShaderId, 1, new String[] {source}, new int[] {source.length()}, 0); gl.glCompileShaderARB(vertexShaderId); int[] result = new int[1]; gl.glGetShaderiv(vertexShaderId, GL.GL_COMPILE_STATUS, result, 0); if (result[0] != GL.GL_TRUE) { throw new RuntimeException("Compile of GLSL Shader failed!"); } gl.glAttachObjectARB(programId, vertexShaderId); fragmentShaderId = gl.glCreateShaderObjectARB(GL.GL_FRAGMENT_SHADER_ARB); source = getShaderSource("texture_coordinates.frag"); gl.glShaderSourceARB(fragmentShaderId, 1, new String[] {source}, new int[] {source.length()}, 0); gl.glCompileShaderARB(fragmentShaderId); result = new int[1]; gl.glGetShaderiv(fragmentShaderId, GL.GL_COMPILE_STATUS, result, 0); if (result[0] != GL.GL_TRUE) { throw new RuntimeException("Compile of GLSL Shader failed!"); } gl.glAttachObjectARB(programId, fragmentShaderId); gl.glLinkProgramARB(programId); gl.glGetProgramiv(programId, GL.GL_LINK_STATUS, result, 0); if (result[0] != GL.GL_TRUE) { throw new RuntimeException("Linking of GLSL Shader failed!"); } gl.glValidateProgramARB(programId); gl.glGetObjectParameterivARB(programId, GL.GL_OBJECT_INFO_LOG_LENGTH_ARB, result, 0); int length = result[0]; if (length > 0) { byte[] log = new byte[length]; gl.glGetInfoLogARB(programId, log.length, new int[length], 0, log, 0); System.out.println("Log Result: " + new String(log) + " (" + length + ")"); } gl.glUseProgramObjectARB(programId); int myTexture = gl.glGetUniformLocationARB(programId, "myTexture"); gl.glUniform1iARB(myTexture, 0); } public void draw(GL gl) { gl.glTranslatef(-400.0f, 0.0f, -800.0f); gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, GL.GL_MODULATE); gl.glBindTexture(GL.GL_TEXTURE_2D, textures[0]);
gl.glEnableClientState(GL.GL_TEXTURE_COORD_ARRAY); gl.glBindBufferARB(GL.GL_ARRAY_BUFFER_ARB, textureVbo[0]); gl.glTexCoordPointer(2, GL.GL_FLOAT, 0, 0);
gl.glEnableClientState(GL.GL_VERTEX_ARRAY); { gl.glBindBufferARB(GL.GL_ARRAY_BUFFER_ARB, vertexes[0]); gl.glVertexPointer(3, GL.GL_FLOAT, 0, 0); gl.glDrawArrays(GL.GL_QUADS, 0, 4); } gl.glDisableClientState(GL.GL_VERTEX_ARRAY); } public static void main(String[] args) throws Exception { new TestMipmapping(); } } |
|
|
|
|
|
30
|
Java Game APIs & Engines / JOGL Development / Re: Generating Mipmap Problems
|
on: 2009-07-21 14:42:13
|
Hm...
correct => Yellow = (255,255,0), Red = (255,0,0) incorrect => Aqua = (0,255,255), Blue = (0,0,255)
So the Red and Blue channel are swapped.
That makes sense, but I'm at a loss as to how to fix it. I tried switching to GL_BGR but that stops anything from appearing. I'm matching my mipmapping exactly to my original 0 call so I don't understand why the mipmaps would be incorrect? Here is the current code: 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 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
| package test;
import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.awt.image.DataBufferByte; import java.io.File; import java.nio.ByteBuffer; import java.nio.FloatBuffer;
import javax.imageio.ImageIO; import javax.media.opengl.GL;
import com.sun.opengl.util.BufferUtil;
public class TestMipmapping extends TestBasic { private int[] vertexes; private int[] textures; private int[] textureVbo; private int programId; private int vertexShaderId; private int fragmentShaderId; private FloatBuffer textureCoordinates; public void initialize(GL gl) { super.initialize(gl); BufferedImage image = null; try { image = ImageIO.read(getClass().getClassLoader().getResource("resource/testing.png")); } catch(Throwable t) { t.printStackTrace(); } FloatBuffer buffer = BufferUtil.newFloatBuffer(12); { buffer.put(0.0f); buffer.put(0.0f); buffer.put(0.0f); buffer.put(image.getWidth()); buffer.put(0.0f); buffer.put(0.0f); buffer.put(image.getWidth()); buffer.put(image.getHeight()); buffer.put(0.0f); buffer.put(0.0f); buffer.put(image.getHeight()); buffer.put(0.0f); buffer.rewind(); } vertexes = new int[1]; gl.glGenBuffersARB(1, vertexes, 0); gl.glBindBufferARB(GL.GL_ARRAY_BUFFER_ARB, vertexes[0]); gl.glBufferDataARB(GL.GL_ARRAY_BUFFER_ARB, buffer.capacity() * 4, buffer, GL.GL_STATIC_DRAW_ARB); textureCoordinates = BufferUtil.newFloatBuffer(8); { textureCoordinates.put(0.0f); textureCoordinates.put(1.0f); textureCoordinates.put(1.0f); textureCoordinates.put(1.0f); textureCoordinates.put(1.0f); textureCoordinates.put(0.0f); textureCoordinates.put(0.0f); textureCoordinates.put(0.0f); textureCoordinates.rewind(); } textureVbo = new int[1]; gl.glGenBuffersARB(1, textureVbo, 0); gl.glBindBufferARB(GL.GL_ARRAY_BUFFER_ARB, textureVbo[0]); gl.glBufferDataARB(GL.GL_ARRAY_BUFFER_ARB, textureCoordinates.capacity() * 4, textureCoordinates, GL.GL_STATIC_DRAW_ARB); textures = new int[1]; gl.glGenTextures(1, textures, 0); gl.glBindTexture(GL.GL_TEXTURE_2D, textures[0]); try { DataBufferByte dbb = (DataBufferByte)image.getRaster().getDataBuffer(); byte[] data = dbb.getData(); ByteBuffer pixels = BufferUtil.newByteBuffer(data.length); pixels.put(data); pixels.flip(); int mode = 3; gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR); gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, mode == 1 ? GL.GL_LINEAR : GL.GL_LINEAR_MIPMAP_LINEAR); if (mode == 2) { gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_GENERATE_MIPMAP, GL.GL_TRUE); } gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 1); gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGB, image.getWidth(), image.getHeight(), 0, GL.GL_RGB, GL.GL_UNSIGNED_BYTE, pixels); if (mode == 3) { int mipmaps = (int)Math.floor(Math.log(Math.max(image.getWidth(), image.getHeight())) / Math.log(2)) + 1; int w = image.getWidth(); int h = image.getHeight(); for (int i = 1; i < mipmaps; i++) { w = Math.max(1, w / 2); h = Math.max(1, h / 2); if (w == 0) { w = 1; } else if (h == 0) { h = 1; } System.out.println(w + "x" + h + " - " + i); BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_3BYTE_BGR); Graphics2D g = bi.createGraphics(); g.drawImage(image, 0, 0, w, h, null); g.dispose(); DataBufferByte dbb2 = (DataBufferByte)bi.getRaster().getDataBuffer(); byte[] data2 = dbb2.getData(); ByteBuffer pixels2 = BufferUtil.newByteBuffer(data2.length); pixels2.put(data2); pixels2.flip(); gl.glTexImage2D(GL.GL_TEXTURE_2D, i, GL.GL_RGB, bi.getWidth(), bi.getHeight(), 0, GL.GL_RGB, GL.GL_UNSIGNED_BYTE, pixels2); } System.out.println("Positions Created: " + mipmaps); } } catch(Throwable t) { t.printStackTrace(); } programId = gl.glCreateProgramObjectARB(); vertexShaderId = gl.glCreateShaderObjectARB(GL.GL_VERTEX_SHADER_ARB); String source = getShaderSource("texture_coordinates.vert"); gl.glShaderSourceARB(vertexShaderId, 1, new String[] {source}, new int[] {source.length()}, 0); gl.glCompileShaderARB(vertexShaderId); int[] result = new int[1]; gl.glGetShaderiv(vertexShaderId, GL.GL_COMPILE_STATUS, result, 0); if (result[0] != GL.GL_TRUE) { throw new RuntimeException("Compile of GLSL Shader failed!"); } gl.glAttachObjectARB(programId, vertexShaderId); fragmentShaderId = gl.glCreateShaderObjectARB(GL.GL_FRAGMENT_SHADER_ARB); source = getShaderSource("texture_coordinates.frag"); gl.glShaderSourceARB(fragmentShaderId, 1, new String[] {source}, new int[] {source.length()}, 0); gl.glCompileShaderARB(fragmentShaderId); result = new int[1]; gl.glGetShaderiv(fragmentShaderId, GL.GL_COMPILE_STATUS, result, 0); if (result[0] != GL.GL_TRUE) { throw new RuntimeException("Compile of GLSL Shader failed!"); } gl.glAttachObjectARB(programId, fragmentShaderId); gl.glLinkProgramARB(programId); gl.glGetProgramiv(programId, GL.GL_LINK_STATUS, result, 0); if (result[0] != GL.GL_TRUE) { throw new RuntimeException("Linking of GLSL Shader failed!"); } gl.glValidateProgramARB(programId); gl.glGetObjectParameterivARB(programId, GL.GL_OBJECT_INFO_LOG_LENGTH_ARB, result, 0); int length = result[0]; if (length > 0) { byte[] log = new byte[length]; gl.glGetInfoLogARB(programId, log.length, new int[length], 0, log, 0); System.out.println("Log Result: " + new String(log) + " (" + length + ")"); } gl.glUseProgramObjectARB(programId); int myTexture = gl.glGetUniformLocationARB(programId, "myTexture"); gl.glUniform1iARB(myTexture, 0); } public void draw(GL gl) { gl.glTranslatef(-400.0f, 0.0f, -800.0f); gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, GL.GL_MODULATE); gl.glBindTexture(GL.GL_TEXTURE_2D, textures[0]);
gl.glEnableClientState(GL.GL_TEXTURE_COORD_ARRAY); gl.glBindBufferARB(GL.GL_ARRAY_BUFFER_ARB, textureVbo[0]); gl.glTexCoordPointer(2, GL.GL_FLOAT, 0, 0);
gl.glEnableClientState(GL.GL_VERTEX_ARRAY); { gl.glBindBufferARB(GL.GL_ARRAY_BUFFER_ARB, vertexes[0]); gl.glVertexPointer(3, GL.GL_FLOAT, 0, 0); gl.glDrawArrays(GL.GL_QUADS, 0, 4); } gl.glDisableClientState(GL.GL_VERTEX_ARRAY); } public static void main(String[] args) throws Exception { new TestMipmapping(); } } |
|
|
|
|
|