Jogl uv coordinates for tilesets - java

I am currently learning jogl so I can make my own 2d game. All the textures for the tiles are stored in a single large tileset.
I tried to use Texture.getSubImageTexCoords() to draw a single tile, but the result was weird:
I'm not sure exactly how to describe it, but the upper left triangle that makes up the quad is stretching in a very strange way.
I want to display just a section of the tileset.
I tried looking for something online but couldn't find anything.
here is my code:
public class TestSubImage {
private GLU glu = new GLU();
private GLCanvas mainCanvas;
private Texture texture;
private TextureCoords tc;
class Listener implements GLEventListener {
public void init(GLAutoDrawable drawable) {
// Load texture
try {
texture = TextureIO.newTexture(TestSubImage.class.getResource("/images/sheet.png"), false, null);
texture.setTexParameteri(drawable.getGL(), drawable.getGL().GL_TEXTURE_MAG_FILTER, drawable.getGL().GL_NEAREST);
tc = texture.getSubImageTexCoords(0, 16, 16, 32); // sub texture coords
} catch (IOException e) {
e.printStackTrace();
}
// Set up
drawable.getGL().glClearColor(0.3f, 0.3f, 0.3f, 0);
glu = new GLU();
glu.gluOrtho2D(0, 512, 512, 0);
}
public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
}
public void dispose(GLAutoDrawable drawable) {
}
public void display(GLAutoDrawable drawable) {
GL2 gl = drawable.getGL().getGL2();
gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
// where to draw the image
int x = 100;
int y = 100;
int width = 200;
int height = 200;
gl.glColor3f(1, 1, 1);
// Draw the image
texture.enable(gl);
texture.bind(gl);
gl.glBegin(GL2.GL_QUADS);
gl.glVertex2f(x, y);
gl.glTexCoord2f(tc.left(), tc.bottom());
gl.glVertex2f(x, y + height);
gl.glTexCoord2f(tc.right(), tc.bottom());
gl.glVertex2f(x + width, y + height);
gl.glTexCoord2f(tc.right(), tc.top());
gl.glVertex2f(x + width, y);
gl.glTexCoord2f(tc.left(), tc.top());
gl.glEnd();
texture.disable(gl);
}
}
private void run() {
// Create window
JFrame frame = new JFrame("Texture Coords Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Create profile and capabilities
final GLProfile profile = GLProfile.get(GLProfile.GL2);
GLCapabilities caps = new GLCapabilities(profile);
// Now set up the main GLCanvas
mainCanvas = new GLCanvas(caps);
mainCanvas.addGLEventListener(new Listener());
frame.getContentPane().add(mainCanvas);
frame.setSize(512, 512);
frame.setResizable(false);
frame.setVisible(true);
}
public static void main(String[] args) {
new TestSubImage().run();
}
}
The tileset is here.

glTexCoord2f sets the texcoord for the next vertex. So, you are rendering one vertex with the default texcoord (whatever that is), and then you are rendering each vertex with the previous vertex's texcoord. And the last texcoord call does nothing. (Well, it probably hangs around as the current texcoord and gets used for the first vertex on the next frame)
You need to call glTexCoord2f before glVertex2f.
P.S. It works the same for glColor3f/4f, glNormal3f, etc.

I don't use JOGL, but it looks like your
gl.glVertex2f(x, y);
gl.glTexCoord2f(tc.left(), tc.bottom());
gl.glVertex2f(x, y + height);
gl.glTexCoord2f(tc.right(), tc.bottom());
gl.glVertex2f(x + width, y + height);
gl.glTexCoord2f(tc.right(), tc.top());
gl.glVertex2f(x + width, y);
gl.glTexCoord2f(tc.left(), tc.top());
is incorrect. If we are pairing each glVertex2f with the line below it I would imagine it should look like
gl.glVertex2f(x, y);
gl.glTexCoord2f(tc.left(), tc.bottom());
gl.glVertex2f(x, y + height);
gl.glTexCoord2f(tc.left(), tc.top());
gl.glVertex2f(x + width, y + height);
gl.glTexCoord2f(tc.right(), tc.top());
gl.glVertex2f(x + width, y);
gl.glTexCoord2f(tc.right, tc.bottom());

Related

Analog clock in OpenGL 2.0 using Java

Can someone help to make a static analogue clock in OpenGL 2.0 using Java? I used Bresenham Circle to draw a circle for the clock but is there any other way to draw a circle here? Then I drew an hour, minute, and second hand but I got an error in the render part while drawing the numbers. Can someone help me here with how to fix this? The code which I tried is following:
public class MyClock implements GLEventListener {
private int windowWidth = 1000;
private int windowHeight = 900;
public void display(GLAutoDrawable drawable) {
render(drawable);
}
//render
private void render(GLAutoDrawable drawable) {
GL2 gl = drawable.getGL().getGL2();
gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT);
gl.glPointSize(5.0f);
//drawing circle
bresenhamCircle(new Point(100,100), 200, new Color(1, 0, 1), gl);
double x, y, d, delta_SE, delta_E;
x = 0;
double r = 200;
y = r;
d = 5-4*r;
setPixel(x ,y, gl);
setPixel(-x,y, gl);
setPixel(x,-y, gl);
setPixel(-x,-y, gl);
setPixel(y,x, gl);
setPixel(-y,x, gl);
setPixel(y,-x, gl);
setPixel(-y,-x, gl);
while (y>x) {
if (d >= 0) {
delta_SE = 4*(2*(x-y)+5);
d+=delta_SE; x++; y--;
}
else {
delta_E = 4*(2*x+3);
d+=delta_E; x++;
}
setPixel(x,y, gl);
setPixel(-x,y, gl);
setPixel(x,-y, gl);
setPixel(-x,-y, gl);
setPixel(y,x, gl);
setPixel(-y,x, gl);
setPixel(y,-x, gl);
setPixel(-y,-x, gl);
}
//hour hand
gl.glColor3d(0, 0, 1);
gl.glBegin(GL2.GL_LINES);
gl.glVertex2d(0, 00);
gl.glVertex2d(70, 70);
gl.glEnd();
//minute hand
gl.glColor3d(0, 0, 1);
gl.glBegin(GL2.GL_LINES);
gl.glVertex2d(0, 00);
gl.glVertex2d(150, 20);
gl.glEnd();
//seconds hand
gl.glColor3d(1, 0, 0);
gl.glBegin(GL2.GL_LINES);
gl.glVertex2d(0, 00);
gl.glVertex2d(120, -120);
gl.glEnd();
//drawing numbers
int AngleX, AngleY;
int radius;
double line;
for (int i=1;i<=12;i++) {
line = i/12*Math.PI*2;
radius=170;
AngleX=(int)((0)+(Math.sin(line)*radius));
AngleY=(int)((0)+(Math.cos(line)*radius));
gl.glColor3d(1, 1, 1);
String a= Integer.toString(i);
g.drawString(a,AngleX,AngleY);
}
}
//Bresenham Circle method
public void bresenhamCircle(Point center, double radius, Color color, GL2 gl) {
gl.glColor3d(0, 0, 1);
gl.glBegin(GL2.GL_POINTS);
gl.glVertex2d(00,200);
gl.glEnd();
}
private void setPixel(double x, double y,GL2 gl) {
gl.glColor3d(0.0, 1.0, 0.0);
gl.glBegin(GL2.GL_POINTS);
gl.glVertex2d(0,0);
gl.glVertex2d( x, y);
gl.glEnd();
}
public void dispose(GLAutoDrawable drawable) {
}
public void init(GLAutoDrawable drawable) {
GL2 gl = drawable.getGL().getGL2();
gl.glViewport(0, 0, windowWidth, windowHeight);
gl.glMatrixMode(GL2.GL_PROJECTION);
gl.glLoadIdentity();
gl.glOrtho(-windowWidth / 2, windowWidth / 2, -windowHeight / 2, windowHeight / 2, 0, 1);
gl.glClear(GL2.GL_COLOR_BUFFER_BIT);
gl.glEnable(GL2.GL_LINE_SMOOTH);
}
public void reshape(GLAutoDrawable drawable, int x, int y, int w, int h) {
GL2 gl = drawable.getGL().getGL2();
windowWidth = w;
windowHeight = h;
gl.glViewport(0, 0, w, h);
gl.glMatrixMode(GL2.GL_PROJECTION);
gl.glLoadIdentity();
gl.glOrtho(-w / 2, w / 2, -h / 2, h / 2, 0, 1);
}
}
As far as I know, there isn't a simple method built into OpenGL ES 2.0 that draws text. That means you have to either find an open-source library that you can use, or you can create your own way of rendering text. This post outlines nicely the different ways that you can render text with OpenGL.
The best way I have found based on my research and which is also stated in the above link, is to render text through images. This tutorial shows how to create a basic text engine and is what I used to get an idea of how to render custom text. The idea is to take a texture atlas (a texture atlas is one image that contains all the letters, numbers, characters that you want to be able to render) and based on what string you want to draw, the engine will crop out the necessary letters, numbers, or characters from the atlas needed for your string and combine them into a square polygon that you can then render to the screen. The tutorial that I linked is a basic text engine, but once you understand how it works, you can then modify and improve it to your needs.

Multiple cameras and ScissorStack?

I'm currently trying to make a game, and I'm still novice with using cameras, and I'm thinking that two OrthographicCameras may be necessary, but I'm not sure if that's the most efficient way, or even how to do so.
Basically, I want this to be the layout for it:
The Main Area is where the main stuff is, which is a Server Interface. The Game Level is where the actual game part is in. I am currently using a ScissorStack to cut the region, but with this demo, results make me question how to do this:
public class TestScissorStackAndCamera extends ApplicationAdapter {
private SpriteBatch batch;
private OrthographicCamera camera;
private Sprite sprite;
private int width, height;
#Override
public void create() {
Gdx.gl.glClearColor(0, 0, 0, 0);
width = Gdx.graphics.getWidth();
height = Gdx.graphics.getHeight();
batch = new SpriteBatch();
camera = new OrthographicCamera(width, height);
camera.position.set(width / 2, height / 2, 0);
camera.update();
createSprite();
}
private void createSprite() {
Pixmap map = new Pixmap(width, height, Format.RGBA8888);
map.setColor(Color.RED);
map.fillRectangle(0, 0, width, height);
map.setColor(Color.BLUE);
map.drawLine(width / 2, 0, width / 2, height);
map.drawLine(0, height / 2, width, height / 2);
Texture texture = new Texture(map);
sprite = new Sprite(texture);
}
#Override
public void render() {
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.setProjectionMatrix(camera.combined); // The Question!
batch.begin();
{
Rectangle scissors = new Rectangle();
Rectangle area = new Rectangle(10, 10, width - 20, height - 20);
ScissorStack.calculateScissors(camera, batch.getTransformMatrix(), area, scissors);
ScissorStack.pushScissors(scissors);
batch.draw(sprite, 0, 0);
batch.flush();
ScissorStack.popScissors();
}
batch.end();
}
public static void main(String[] args) {
LwjglApplicationConfiguration config = new LwjglApplicationConfiguration();
config.title = "ScissorStack & Camera Test";
config.resizable = false;
new LwjglApplication(new TestScissorStackAndCamera(), config);
}
}
Questioning batch.setProjectionMatrix(camera.combined)
I marked a line in the code with a comment, The Question!, which is what is affecting the results. If I don't have it, using the camera.translate(...) method, the image is drawn at (0, 0) but what it does is it moves what part is viewed. If I do have that line, when I use the camera.translate(...) method, the image is drawn respectively to the position of the camera.
In respect to the game that I'm currently developing, it behaves awkwardly without the projectionMatrix not being set, but when I do set it, it messes up the positioning of the rest of the game. I even added some testing features, and it's not rendering inside of the correct ScissorStack
How could I go about setting up two cameras, or what could I do to set up what I'm trying to correctly and efficiently?
With my actual game (not the mock-up) this is what it is doing. It should be rendering inside of the red lines, but it's not:
If you'd like to see my current code for my GameLevel that is handling the ScissorStack and OrthographicCamera:
public GameLevel(int x, int y, int displayWidth, int displayHeight) {
this.x = x; // x = 10
this.y = y; // y = 10
this.displayWidth = displayWidth; // displayWidth = Gdx.graphics.getWidth() - x - 10
this.displayHeight = displayHeight; // displayHeight = Gdx.graphics.getHeight() - y - 120
camera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
camera.position.set(displayWidth / 2, displayHeight / 2, 0);
// FBLAGame.batch.setProjectionMatrix(camera.combined);
camera.update();
init();
}
...
#Override
public void render() {
Rectangle area = new Rectangle(x, y, displayWidth, displayHeight);
Rectangle scissor = new Rectangle();
Matrix4 matrix = FBLAGame.batch.getTransformMatrix();
ScissorStack.calculateScissors(camera, matrix, area, scissor);
ScissorStack.pushScissors(scissor);
renderLevel();
FBLAGame.batch.flush();
ScissorStack.popScissors();
Pixmap map = new Pixmap(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), Format.RGBA8888);
map.setColor(Color.RED);
map.drawRectangle((int) area.x, (int) area.y, (int) area.width, (int) area.height);
Texture t = new Texture(map);
map.dispose();
FBLAGame.batch.draw(t, 0, 0);
}

Same texture being put on each image - JOGL

I am using JOGL to create a 2D game. In my game it has square blocks that each have a different type e.g water, grass, etc.
I have an ArrayList of the class Block. Each block instance has the type of block it is and coordinates.
My problem is that when drawing the blocks they each have the same texture instead of the type they are. I think it may be because I need to disable the texture after using it but that seems to remove the texture off of everything.
GLCanvas Class
float[] lightPos = new float[4];
private void doLighting( GL2 gl )
{
lightPos[0] =0.5f;
lightPos[1] = 0;
lightPos[2] = 1f;
lightPos[3] = 0.0001f;
gl.glEnable(GLLightingFunc.GL_LIGHTING);
gl.glEnable(GLLightingFunc.GL_LIGHT0);
gl.glEnable(GL2.GL_COLOR_MATERIAL);
float[] noAmbient ={ 0.2f, 0.2f, 0.2f, 1f }; // low ambient light
float[] spec = { 1f, 1f, 1f,1f }; // low ambient light
float[] diffuse ={ 1f, 1f, 1f, 1f };
// properties of the light
gl.glLightfv(GLLightingFunc.GL_LIGHT0, GLLightingFunc.GL_AMBIENT, noAmbient, 0);
gl.glLightfv(GLLightingFunc.GL_LIGHT0, GLLightingFunc.GL_SPECULAR, spec, 0);
gl.glLightfv(GLLightingFunc.GL_LIGHT0, GLLightingFunc.GL_DIFFUSE, diffuse, 0);
gl.glLightfv(GLLightingFunc.GL_LIGHT0, GLLightingFunc.GL_POSITION, lightPos, 0);
gl.glLightf(GL2.GL_LIGHT0, GL2.GL_SPOT_CUTOFF, 45.0f);
}
private void render(GL2 gl) {
gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer
gl.glLoadIdentity(); // Reset The Current Modelview Matrix
//Draw the blocks from the Block Array List
for(int i = 0; i < block.size(); i ++){
block.get(i).draw(gl, moveX, moveY);
}
//Draw player
gl.glColor3f(1, 1, 1);
gl.glBegin(GL2.GL_QUADS);
gl.glVertex2f(player.x,player.y);
gl.glVertex2f(player.x + player.width,player.y);
gl.glVertex2f(player.x + player.width,player.y + player.width);
gl.glVertex2f(player.x,player.y + player.width);
gl.glEnd();
}
#Override
public void display(GLAutoDrawable drawable) {
GL2 gl = drawable.getGL().getGL2();
gl.glClear(GL2.GL_DEPTH_BUFFER_BIT | GL2.GL_COLOR_BUFFER_BIT);
gl.glEnable(GL2.GL_TEXTURE_2D);
gl.glEnable(GL2.GL_BLEND);
gl.glBlendFunc(GL2.GL_ONE, GL2.GL_ONE_MINUS_SRC_ALPHA);
gl.glEnableClientState(GL2.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL2.GL_COLOR_ARRAY);
gl.glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
gl.glLoadIdentity();
doLighting(gl);
setCamera(gl,120);
render(gl);
}
#Override
public void dispose(GLAutoDrawable arg0) {
}
#Override
public void init(GLAutoDrawable drawable) {
GL2 gl = drawable.getGL().getGL2();
gl.glEnable(GL2.GL_TEXTURE_2D);
}
private void setCamera(GL2 gl,float distance) {
// Change to projection matrix.
gl.glMatrixMode(GL2.GL_PROJECTION);
gl.glLoadIdentity();
// Perspective.
gl.glOrtho(0, Frame.WIDTH, Frame.HEIGHT, 0, 0, 1);
gl.glMatrixMode(GL2.GL_MODELVIEW);
//Disable z axis
gl.glDisable(GL2.GL_DEPTH_TEST);
}
#Override
public void reshape(GLAutoDrawable arg0, int arg1, int arg2, int arg3,
int arg4) {
}
Block class draw method
public void draw(GL2 gl, int moveX, int moveY) {
if (texture == null) {
try {
texture = TextureIO.newTexture(new File(this.getClass().getClassLoader()
.getResource("com/world/images/" + type + ".png").getPath()), false);
texture.enable(gl);
texture.bind(gl);
// Poor filtering. Needed !
gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MAG_FILTER, GL2.GL_NEAREST);
gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MIN_FILTER, GL2.GL_NEAREST);
} catch (GLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
gl.glBegin(GL2.GL_QUADS);
gl.glVertex2f(x * width + moveX, y * width + moveY);
gl.glTexCoord2f(0, 0);
gl.glVertex2f(x * width + width + moveX, y * width + moveY);
gl.glTexCoord2f(1, 0);
gl.glVertex2f(x * width + width + moveX, y * width + width + moveY);
gl.glTexCoord2f(1, 1);
gl.glVertex2f(x * width + moveX, y * width + width + moveY);
gl.glTexCoord2f(0, 1);
gl.glEnd();
gl.glFlush();
}
Thank you very much for any help. Ask if I have made anything unclear.
Move the calls of gl.glTexParameteri() into the init() method of your GLEventListener, it should be called only once, it affects the whole texture target, not only a single texture and I'm not sure you need to call bind before. Load each texture matching with a block type once elsewhere, call gl.glEnable(GL2.GL_TEXTURE_2D) before drawing any textured mesh, call texture.bind(gl) (use the texture that matches with the block type) before calling glBegin() and call gl.glDisable(GL2.GL_TEXTURE_2D) after drawing the last textured mesh.
texture.enable() and texture.bind() had to be outside the if statement as they need to be called each time the textures are drawn.
public void draw(GL2 gl, int moveX, int moveY) {
if (texture == null) {
try {
texture = TextureIO.newTexture(
new File(this.getClass().getClassLoader().getResource("com/world/images/" + type + ".png").getPath()), false);
} catch (GLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
texture.enable(gl);
texture.bind(gl);
gl.glEnable(GL2.GL_TEXTURE_2D);
gl.glBegin(GL2.GL_QUADS);
gl.glVertex2f(x * width + moveX, y * width + moveY);
gl.glTexCoord2f(0, 0);
gl.glVertex2f(x * width + width + moveX, y * width + moveY);
gl.glTexCoord2f(1, 0);
gl.glVertex2f(x * width + width + moveX, y * width + width + moveY);
gl.glTexCoord2f(1, 1);
gl.glVertex2f(x * width + moveX, y * width + width + moveY);
gl.glTexCoord2f(0, 1);
gl.glEnd();
gl.glDisable(GL2.GL_TEXTURE_2D);
}

Draw opposite of shape in PApplet

Is there a way to fall an entire canvas, except for a shape. For example, this thread, but in Java's Processing PApplet.
Thank you in advanced.
By the answer in HTML 5 linked, I assume you need something like this:
PGraphics mask, filler;
int x;
void setup(){
size(400,400);
// initial bg color, the white circle...
background(255);
//init both PGraphics
mask = createGraphics(width, height);
filler = createGraphics(width, height);
// draw a circle as a mask
mask.beginDraw();
mask.background(255);
mask.noStroke();
mask.fill(0);
mask.ellipse(width/2, height/2, 200, 200);
mask.endDraw();
}
void draw(){
// a changing bg
x = (x+1)%255;
background(x);
//dinamiaclly draw random rects
filler.beginDraw();
filler.noStroke();
filler.fill(random(255), random(255), random(255));
filler.rect(random(width), random(height), random(5,40), random(5,40));
filler.endDraw();
// get an imge out ofthis...
PImage temp = filler.get();
//mask image
temp.mask(mask);
//dispay it
image(temp, 0, 0);
}
void mousePressed(){
mask.beginDraw();
mask.background(0);
mask.noStroke();
mask.fill(255);
mask.ellipse(width/2, height/2, 200, 200);
mask.endDraw();
}
void mouseReleased(){
mask.beginDraw();
mask.background(255);
mask.noStroke();
mask.fill(0);
mask.ellipse(width/2, height/2, 200, 200);
mask.endDraw();
}
second example
PGraphics mask, front, back;
int x;
void setup(){
size(400,400);
background(0);
//init both PGraphics
mask = createGraphics(width, height);
front = createGraphics(width, height);
back = createGraphics(width, height);
}
void draw(){
float x = random(width);
float y = random(height);
float sx = random(5, 40);
// draw a circle as a mask
mask.beginDraw();
mask.background(255);
mask.noStroke();
mask.fill(100);
mask.ellipse(mouseX, mouseY, 200, 200);
mask.endDraw();
//dinamiaclly draw random colored rects to PG
front.beginDraw();
front.noStroke();
front.fill(random(255), random(255), random(255));
front.rect(x, y, sx, sx);
front.endDraw();
//dinamiaclly draw random gray rects to display
back.beginDraw();
back.stroke(200);
back.fill(0, 100);
back.rect(x, y, sx, sx);
back.endDraw();
// get an imge out ofthis...
PImage temp = front.get();
//mask image
temp.mask(mask);
//dispay it
image(back,0,0);
image(temp, 0, 0);
}
example using Unfold maps
import de.fhpotsdam.unfolding.*;
import de.fhpotsdam.unfolding.geo.*;
import de.fhpotsdam.unfolding.utils.*;
PGraphics mask, red;
color transparent = color(0);
color opaque = color(255);
UnfoldingMap map;
void setup() {
size(800, 600, P2D);
mask = createGraphics(width, height);
red = createGraphics(width, height);
map = new UnfoldingMap(this);
map.zoomAndPanTo(new Location(52.5f, 13.4f), 10);
MapUtils.createDefaultEventDispatcher(this, map);
}
void draw() {
map.draw();
PImage temp = get();
//red
red.beginDraw();
red.tint(200,20,20);
red.image(temp, 0, 0);
red.endDraw();
//mask
mask.beginDraw();
mask.noStroke();
mask.background(opaque);
mask.fill(transparent);
mask.ellipseMode(CENTER);
mask.ellipse(mouseX, mouseY, 200,200);
mask.endDraw();
// without this i'm not getting to call mask in red...
// don't really know why, this is a workaround
PImage redCasted = red.get();
redCasted.mask(mask);
image(redCasted, 0, 0);
}
Your question doesn't specify if you want anything more than what that link shows, so perhaps this answer isn't what you want (but it is what you asked). First, fill the entire screen with whatever color you want, then draw your shape on top of that. Example:
background(0);
fill(255);
ellipse(50,50,50,50);

Difficulty with Text in JOGL

I'm trying to display text in my OpenGL / JOGL app. Here is some of the code:
private void display(GLAutoDrawable drawable) {
GL2 gl = drawable.getGL().getGL2();
GLUgl2 glu = new GLUgl2();
float[] rgba = new float[4];
backgroundColor.getRGBComponents(rgba);
gl.glClearColor(rgba[0], rgba[1], rgba[2], 1);
gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT);
gl.glMatrixMode(GL2.GL_MODELVIEW);
gl.glLoadIdentity();
// Position the camera
glu.gluLookAt(cameraPos.x, cameraPos.y, cameraPos.z, cameraPos.x + cameraForward.x, cameraPos.y + cameraForward.y,
cameraPos.z + cameraForward.z, cameraUp.x, cameraUp.y, cameraUp.z);
gl.glPushMatrix();
GLUT glut = new GLUT();
gl.glTranslatef(0, 0, 0);
gl.glColor3f(1, 0, 0);
glut.glutBitmapString(GLUT.BITMAP_HELVETICA_18, "We're going to the moon!");
gl.glPopMatrix();
// ...
The text appears as soon as rendering begins, then runs off the right hand side of the screen. Why is this happening?
I'd like to display text in front of the user, not as a model in the world.
You need to set the current raster position before invoking glutBitmapString. The raster position is the pixel where the string will start being drawn. You can set it using the glRasterPos... family of functions. The reason your text seems to "run off" the right side of the screen is that calling glutBitmapString implicitly moves the raster position to the end of the string (see here).
There is very easy solution but it "links" your app against awt, which might be bad if you try to stay out of it in favour of newt.
Below example draws player osd using number of text renderers: one for play/pause glyph, one more for some information like time, etc., and yet another one for movie name.
import com.jogamp.opengl.util.awt.TextRenderer;
private static final Color DROP_SHADOW_COLOR = new Color(0, 0, 0, 0.5f);
class CustomRenderDelegate implements TextRenderer.RenderDelegate {
private int dropShadowDepth;
private Color color;
CustomRenderDelegate(int dropShadowDepth, Color color) {
this.dropShadowDepth = dropShadowDepth;
this.color = color;
}
public boolean intensityOnly() {
return false;
}
public Rectangle2D getBounds(CharSequence str, Font font, FontRenderContext frc) {
return getBounds(str.toString(), font, frc);
}
public Rectangle2D getBounds(String str, Font font, FontRenderContext frc) {
return getBounds(font.createGlyphVector(frc, str), frc);
}
public Rectangle2D getBounds(GlyphVector gv, FontRenderContext frc) {
Rectangle2D stringBounds = gv.getPixelBounds(frc, 0, 0);
return new Rectangle2D.Double(stringBounds.getX(), stringBounds.getY(), stringBounds.getWidth()
+ dropShadowDepth, stringBounds.getHeight() + dropShadowDepth);
}
public void drawGlyphVector(Graphics2D graphics, GlyphVector str, int x, int y) {
graphics.setColor(DROP_SHADOW_COLOR);
graphics.drawGlyphVector(str, x + dropShadowDepth, y + dropShadowDepth);
graphics.setColor(color);
graphics.drawGlyphVector(str, x, y);
}
public void draw(Graphics2D graphics, String str, int x, int y) {
graphics.setColor(DROP_SHADOW_COLOR);
graphics.drawString(str, x + dropShadowDepth, y + dropShadowDepth);
graphics.setColor(color);
graphics.drawString(str, x, y);
}
}
public void init(GLAutoDrawable drawable) {
...
pathRenderer = new TextRenderer(new Font("Helvetica", Font.ITALIC, 16), true, true, new CustomRenderDelegate(0,
Color.WHITE));
pathRenderer.setSmoothing(true);
playRenderer = new TextRenderer(new Font("Helvetica", Font.BOLD, 65), true, true, new CustomRenderDelegate(0,
Color.WHITE));
pauseRenderer = new TextRenderer(new Font("Helvetica", Font.BOLD, 50), true, true, new CustomRenderDelegate(0,
Color.WHITE));
osdRenderer = new TextRenderer(new Font("Helvetica", Font.PLAIN, 32), true, true, new CustomRenderDelegate(0,
Color.WHITE));
osdRenderer.setSmoothing(true);
}
private final void updateOsd() {
Time t = currentFrame != null ? currentFrame.getTime() : new Time(0, 0, 0, 0, 0);
String direction = video.direction == DirectionType.DIRECTION_LEFT ? "<" : ">";
String frameNumber = enterFrameNumber != null ? String.format("[%s]", enterFrameNumber)
: String.format("(%d)", t.fn);
osdText = String.format(" %s%s x %d # %.2f fps < %d/%d (%s) # %d fps", TimeUtil.hmsms(t.getPtsMillis()), frameNumber, (int) video.getPlaybackRate(), playbackFps, video.readyFrames(), maxFrames, direction, video.getFilterFps());
}
private void renderOsd(GLAutoDrawable drawable) {
updateOsd();
if (isOsdEnabled) {
maxModeWidth = (int) Math.max(maxModeWidth, playRenderer.getBounds("\u25B8").getWidth());
maxOsdHeight = (int) Math.max(maxOsdHeight, playRenderer.getBounds("\u25B8").getHeight());
if (isPaused) {
pauseRenderer.beginRendering(drawable.getWidth(), drawable.getHeight());
pauseRenderer.draw("\u2759", 10, drawable.getHeight() - maxOsdHeight - 2);
int barWidth = (int) pauseRenderer.getBounds("\u2759").getWidth();
pauseRenderer.draw("\u2759", 10 + barWidth - 3, drawable.getHeight() - maxOsdHeight - 2);
pauseRenderer.flush();
pauseRenderer.endRendering();
} else {
playRenderer.beginRendering(drawable.getWidth(), drawable.getHeight());
playRenderer.draw("\u25B8", 10, drawable.getHeight() - maxOsdHeight - 5);
playRenderer.flush();
playRenderer.endRendering();
}
int y = (int) ((maxOsdHeight + 10) - osdRenderer.getBounds(osdText).getHeight() / 2);
osdRenderer.beginRendering(drawable.getWidth(), drawable.getHeight());
osdRenderer.draw(osdText, maxModeWidth + 18, drawable.getHeight() - y - 2);
osdRenderer.flush();
osdRenderer.endRendering();
if (isFullScreen) {
pathRenderer.beginRendering(drawable.getWidth(), drawable.getHeight());
pathRenderer.draw(videoFile.getName(), 18, drawable.getHeight() - y - maxOsdHeight + 15);
pathRenderer.flush();
pathRenderer.endRendering();
}
}
}
public void display(GLAutoDrawable drawable) {
GL gl = drawable.getGL();
gl.glClear(GL.GL_COLOR_BUFFER_BIT);
gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
renderFrame(drawable);
renderOsd(drawable);
gl.glFinish();
}

Categories