Java LWJGL - Heightmap not rendering correctly - java

I am trying to implement a heightmap into my game following Oskar Veerhoek's youtube tutorials. I follow the steps and I get a few methods:
private static void setUpHeightmap() {
try {
// Load the heightmap-image from its resource file
BufferedImage heightmapImage = ImageIO.read(new File("res/img/heightmap.bmp"));
// Initialise the data array, which holds the heights of the heightmap-vertices, with the correct dimensions
data = new float[heightmapImage.getWidth()][heightmapImage.getHeight()];
// Lazily initialise the convenience class for extracting the separate red, green, blue, or alpha channels
// an int in the default RGB color model and default sRGB colourspace.
Color colour;
// Iterate over the pixels in the image on the x-axis
for (int z = 0; z < data.length; z++) {
// Iterate over the pixels in the image on the y-axis
for (int x = 0; x < data[z].length; x++) {
// Retrieve the colour at the current x-location and y-location in the image
colour = new Color(heightmapImage.getRGB(z, x));
// Store the value of the red channel as the height of a heightmap-vertex in 'data'. The choice for
// the red channel is arbitrary, since the heightmap-image itself only has white, gray, and black.
data[z][x] = colour.getRed();
}
}
// Create an input stream for the 'lookup texture', a texture that will used by the fragment shader to
// determine which colour matches which height on the heightmap
FileInputStream heightmapLookupInputStream = new FileInputStream("res/img/heightmap_lookup.png");
// Create a class that will give us information about the image file (width and height) and give us the
// texture data in an OpenGL-friendly manner
PNGDecoder decoder = new PNGDecoder(heightmapLookupInputStream);
// Create a ByteBuffer in which to store the contents of the texture. Its size is the width multiplied by
// the height and 4, which stands for the amount of bytes a float is in Java.
ByteBuffer buffer = BufferUtils.createByteBuffer(4 * decoder.getWidth() * decoder.getHeight());
// 'Decode' the texture and store its data in the buffer we just created
decoder.decode(buffer, decoder.getWidth() * 4, PNGDecoder.Format.RGBA);
// Make the contents of the ByteBuffer readable to OpenGL (and unreadable to us)
buffer.flip();
// Close the input stream for the heightmap 'lookup texture'
heightmapLookupInputStream.close();
// Generate a texture handle for the 'lookup texture'
lookupTexture = glGenTextures();
glBindTexture(GL_TEXTURE_2D, lookupTexture);
// Hand the texture data to OpenGL
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, decoder.getWidth(), decoder.getHeight(), 0, GL_RGBA,
GL_UNSIGNED_BYTE, buffer);
} catch (IOException e) {
e.printStackTrace();
}
// Use the GL_NEAREST texture filter so that the sampled texel (texture pixel) is not smoothed out. Usually
// using GL_NEAREST will make the textured shape appear pixelated, but in this case using the alternative,
// GL_LINEAR, will make the sharp transitions between height-colours ugly.
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
// Generate a display list handle for the display list that will store the heightmap vertex data
heightmapDisplayList = glGenLists(1);
// TODO: Add alternative VBO rendering for pseudo-compatibility with version 3 and higher.
glNewList(heightmapDisplayList, GL_COMPILE);
// Scale back the display list so that its proportions are acceptable.
glScalef(0.2f, 0.06f, 0.2f);
// Iterate over the 'strips' of heightmap data.
for (int z = 0; z < data.length - 1; z++) {
// Render a triangle strip for each 'strip'.
glBegin(GL_TRIANGLE_STRIP);
for (int x = 0; x < data[z].length; x++) {
// Take a vertex from the current strip
glVertex3f(x, data[z][x], z);
// Take a vertex from the next strip
glVertex3f(x, data[z + 1][x], z + 1);
}
glEnd();
}
glEndList();
}
private static void setUpShaders() {
shaderProgram = ShaderLoader.loadShaderPair("res/shaders/landscape.vs", "res/shaders/landscape.fs");
glUseProgram(shaderProgram);
// The following call is redundant because the default value is already 0, but illustrates how you would use
// multiple textures
glUniform1i(glGetUniformLocation(shaderProgram, "lookup"), 0);
}
private static void setUpStates() {
camera.applyOptimalStates();
glPointSize(2);
// Enable the sorting of shapes from far to near
glEnable(GL_DEPTH_TEST);
// Set the background to a blue sky colour
glClearColor(0, 0.75f, 1, 1);
// Remove the back (bottom) faces of shapes for performance
//glEnable(GL_CULL_FACE);
}
When I run the game, the heightmap doesn't show, and my models on the screen get squished like this:
Im thinking it has something to do with it incorrectly rendering the heights and applying it to my models. But I really don't know as I am VERY foreign to 3D development. Some help would be amazing! Thanks!

To get the heightmap information from the image, you simply code:
try {
BufferedImage height = ImageIO.read(new File("utah.jpg"));
hm = new double[height.getHeight()][height.getWidth()];
for (int row = 0; row < height.getHeight(); row++) {
for (int col = 0; col < height.getWidth(); col++) {
hm[row][col] = (height.getRGB(col, row) & 255) / 255.0;
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
To draw the points, you just do the following(translate from JOGL to LWJGL):
gl.glPushMatrix();
for (int x = 0; x < (257 - 1); x++) {
gl.glBegin(GL.GL_TRIANGLE_STRIP);
for (int z = 0; z < (257 - 1); z++) {
double[] row = hm[0];
double y = hm[(x * hm.length) % 10][(z + row.length) % 10]
* 5;
gl.glColor3d(1, 1, 1);
gl.glVertex3d(x, y, z);
//gl.glTexCoord3d(x, y, z);
y = hm[((x + 1) * hm.length) % 10][((z + 1) + row.length) % 10]
* 5;
gl.glColor3d(1, 1, 1);
gl.glVertex3d(x + 1, y, z + 1);
//gl.glTexCoord3d(x + 1, y, z + 1);
}
gl.glEnd();
}
gl.glPopMatrix();

Related

How to create multicolor rasterized picture in processing

I followed this tutorial on Youtube, and I have successfully added colors to the black and white picture. However, my intention was to create a multi-color or gradient effect (like here or here) instead of switching colors when I move the cursor.
I very new at processing, and I have tried to play with the variable, with no success.
Here is the code snippet of the sketch:
`
PImage img;
void setup() {
size(598,336);
colorMode(HSB);
img = loadImage("picture-in-data-folder.jpg");
img.resize(598,336);
//ellipseMode(RADIUS);
frameRate(30);
}
void draw() {
background(255);
noStroke();
// fill(0);
float tiles = mouseX/10;
float tileSize = width/tiles;
// color section
fill(color(tiles, 255, 255));
tileSize++;
if (tiles > width / 2) {
tileSize = 0;
}
// end color section
translate(tileSize/2, tileSize/2);
for (int x = 0; x < tiles; x++) {
for (int y = 0; y < tiles; y++) {
color c = img.get(int(x*tileSize),int(y*tileSize));
float size = map(brightness(c), 0, 255, tileSize, 0);
ellipse(x*tileSize, y*tileSize, size, size);
// image(img, mouseX, mouseY);
}
}
}
I would be grateful if you had any hints, or if you could provide an advice.
Thanks.
Short answer: you need to put a fill() command inside the for loop.
Long answer:
Right now, your code is doing the following:
Define tiles based on mouseX
Set the fill color to (tiles, 255, 255)
Draw all the circles
I think what you want it to do is something like this:
Set the fill color to (21, 255, 255) (or whatever you want the first color to be)
draw the first circle
set the fill color to the next color in the gradient
draw the second circle
etc.
In order to do this, you need to put a command into the for loop which changes the fill color. Here is one way to do that:
for (int x = 0; x < tiles; x++) {
for (int y = 0; y < tiles; y++) {
color c = img.get(int(x*tileSize),int(y*tileSize));
float size = map(brightness(c), 0, 255, tileSize, 0);
fill(map(x, 0, tiles, 0, 255), 255, 255);
ellipse(x*tileSize, y*tileSize, size, size);
}
}
I just added that fill command as a function of x, but you can make it whatever you want. In order for it to be a gradient, it needs to vary somewhat with x or y.

Adding thickness to a 2D sprite when turning

In my game, my entities turn like a piece of paper, as shown here at half-speed: https://imgur.com/a/u2suen6
I want to give the entities a bit of thickness when they turn, making them more cardboard-thin than paper-thin.
I thought about using a Pixmap to detect and extend the edge pixels and give the image some Three-Dimensionality. I also considered duplicating the image along the x-axis to give the same effect. Of the two ideas, the Pixmap holds out the most promise in my mind. However, I'm wondering if there's a better solution.
I'm using a GLSL shader to give the entities highlights and shadows while turning, as you saw in the gif. I think that with the right knowledge, I could achieve what I'm going for using the same shader program.
My shader looks like this:
#ifdef GL_ES
precision mediump float;
#endif
varying vec4 v_color;
varying vec2 v_texCoords;
uniform sampler2D u_texture;
uniform vec2 u_resolution;
uniform vec3 color;
void main()
{
vec4 col = vec4(color, 0.0);
gl_FragColor = texture2D(u_texture, v_texCoords) * v_color + col;
}
I think that one might be able to make calculations based on the uniform vec3 color that I pass it (with its values ranging from 0, 0, 0 to 1, 1, 1. 1's being highlight and 0's being shadow). Unfortunately, I don't have the understanding of shaders to do so.
If any of you have the know-how, could you steer me in the right direction? Or let me know if I should just stick to the Pixmap idea.
Edit: I'm trying to stay away from using a 3D model because I'm 6.4k lines of code deep using a 2d Orthographic Camera.
Edit 2: I figured that the reflection shader wouldn't look good if I tried making the sprite look 3D. I scrapped the shader, went with the Pixmap idea, and plan on implementing shadows and reflections to the pixmap without any shader. Though it looks good so far without reflections.
I ended up going with my pixmap idea. I want to share my code so that others can know how I got 2D thickness to work.
Please note that in the following code:
dir is a floating point value in the range -1.0 to 1.0. It tells the program where the sprite is in its turn. -1 means facing fully left. 1 meaning right. 0 means that it's 'facing' the camera.
right is a boolean that tells the program which direction the entity is turning. true means that the entity is turning from left to right. false means from right to left.
The Code:
private Texture getTurningImage(TextureRegion input, int thickness)
{
if(Math.abs(dir) < 0.1)
dir = (right ? 1 : -1) * 0.1f;
Texture texture = input.getTexture();
if (!texture.getTextureData().isPrepared())
{
texture.getTextureData().prepare();
}
Pixmap pixmap = texture.getTextureData().consumePixmap();
Pixmap p = new Pixmap(64, 64, Pixmap.Format.RGBA8888);
p.setFilter(Pixmap.Filter.NearestNeighbour);
Pixmap texCopy = new Pixmap(input.getRegionWidth(), input.getRegionHeight(), Pixmap.Format.RGBA8888);
// getting a texture out of the input region. I can't use input.getTexture()
// because it's an animated sprite sheet
for (int x = 0; x < input.getRegionWidth(); x++)
{
for (int y = 0; y < input.getRegionHeight(); y++)
{
int colorInt = pixmap.getPixel(input.getRegionX() + x, input.getRegionY() + y);
Color c = new Color(colorInt);
colorInt = Color.rgba8888(c);
texCopy.drawPixel(x, y, colorInt);
}
}
pixmap.dispose();
float offsetVal = Math.round(thickness/2.0) * (float) -Math.cos((dir * Math.PI)/2);
if(offsetVal > -1.23/Math.pow(10, 16))
{
offsetVal = 0;
}
// generate the pixel colors we'll use for the side view
Pixmap sideProfile = new Pixmap(1, 64, Pixmap.Format.RGBA8888);
for (int y = 0; y < texCopy.getHeight(); y++)
{
for (int x = 0; x < texCopy.getWidth(); x++)
{
int colorInt = texCopy.getPixel(x, y);
if(new Color(colorInt).a != 0 && new Color(texCopy.getPixel(x + 1, y)).a == 0)
{
Color c = new Color(colorInt);
c.mul(.8f); // darken the color
c.a = 1;
colorInt = Color.rgba8888(c);
sideProfile.drawPixel(0, y, colorInt);
continue;
}
}
}
// drawing the bottom layer
p.drawPixmap(texCopy, 0, 0, 64, 64, (int) (Math.round(-offsetVal) + (64 - texCopy.getWidth()*Math.abs(dir))/2), 0, (int)(64*Math.abs(dir)), 64);
// drawing the middle (connecting) layer
// based on the edge pixels of the bottom layer, then translated to be in the middle
for (int y = 0; y < p.getHeight(); y++)
{
int colorInt = sideProfile.getPixel(0, y);
for (int x = 0; x < p.getWidth(); x++)
{
if(new Color(p.getPixel(x, y)).a != 0 && new Color(p.getPixel(x + 1, y)).a == 0)
{
for(int i = 0; i <= 2 * Math.round(Math.abs(offsetVal)); i++) // the for the length between the top and bottom
{
p.drawPixel(x + i - 2 * (int)Math.round(Math.abs(offsetVal)), y, colorInt);
}
}
}
}
// drawing the top layer
p.drawPixmap(texCopy, 0, 0, 64, 64, (int) (Math.round(offsetVal) + (64 - texCopy.getWidth()*Math.abs(dir))/2), 0, (int)(64*Math.abs(dir)), 64);
// flip if facing left
if(dir < 0)
{
p = flipPixmap(p);
}
return new Texture(p);
}
My flipPixmap method looks like this (stolen from stack overflow):
private Pixmap flipPixmap(Pixmap src)
{
final int width = src.getWidth();
final int height = src.getHeight();
Pixmap flipped = new Pixmap(width, height, src.getFormat());
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
flipped.drawPixel(x, y, src.getPixel(width - x - 1, y));
}
}
return flipped;
}
Here's the result :D https://imgur.com/a/wGeHg9D

Opengl terrain texture shading

I am currently working on an OpenGL (JOGL) project in java.
The goal is to create a terrain with textures and shading.
I'm creating a random simplex noise, using these values as a heightmap.
The heights are mapped to a 1D texture to simulate coloring based on height.
A material (ambient/diffuse/specular/shininess) is then used to simulate shading.
However; after adding shading to the terrain, 'stripes' appear on each 'column' (Y direction) of the terrain.
The following material is then applied:
TERRAIN(
new float[]{0.5f, 0.5f, 0.5f, 1.0f},
new float[]{0.7f, 0.7f, 0.7f, 1.0f},
new float[]{0.2f, 0.2f, 0.2f, 1.0f},
new float[]{100f})
The material enum constructor:
Material(float[] ambient, float[] diffuse, float[] specular, float[] shininess) {
this.ambient = ambient;
this.diffuse = diffuse;
this.specular = specular;
this.shininess = shininess;
}
I apply the material using the following method:
public void use(GL2 gl) {
// set the material properties
gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GLLightingFunc.GL_AMBIENT, ambient, 0);
gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GLLightingFunc.GL_DIFFUSE, diffuse, 0);
gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GLLightingFunc.GL_SPECULAR, specular, 0);
gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GLLightingFunc.GL_SHININESS, shininess, 0);
}
After creating a 2D 'noisearray' consistent of 0-1 values, an 2D vectorarray is created, consiting of X*Y vectors, where each vector represents a point in the plane/terrain.
Here is the method that draws triangles in between those points, where you can see I draw the plane per column (Y direction):
public void draw(GL2 gl, GLU glu, GLUT glut, Drawer drawer) {
Material.TERRAIN.use(gl);
texture.bind(gl);
if (showGrid)
gl.glPolygonMode( gl.GL_FRONT_AND_BACK, gl.GL_LINE );
ArrayList<Vector[]> normals = new ArrayList<>();
for(int i=1;i<vectors.length;i++) {
gl.glBegin(gl.GL_TRIANGLE_STRIP);
for (int j = 0; j < vectors[i].length; j++) {
Vector normalTopRight, normalBottomLeft;
//Calculate normals top right
Vector v1, v2, triangleCenterTR;
if (j < vectors[i].length - 1)
{
v1 = vectors[i-1][j].subtract(vectors[i][j]);
v2 = vectors[i][j+1].subtract(vectors[i][j]);
normalTopRight = v2.cross(v1).normalized();
// Get center (a+b+c)*(1/3)
triangleCenterTR = (vectors[i][j].add(vectors[i - 1][j]).add(vectors[i][j + 1])).scale(1.0 / 3);
} else {
v1 = vectors[i-1][j].subtract(vectors[i][j]);
v2 = vectors[i][j-1].subtract(vectors[i][j]);
normalTopRight = v1.cross(v2).normalized();
// Get center (a+b+c)*(1/3)
triangleCenterTR = (vectors[i][j].add(vectors[i-1][j]).add(vectors[i][j-1])).scale(1.0/3);
}
normals.add(new Vector[] {triangleCenterTR, triangleCenterTR.add(normalTopRight)});
if (j != 0)
{
v1 = vectors[i][j].subtract(vectors[i-1][j]);
v2 = vectors[i-1][j-1].subtract(vectors[i-1][j]);
normalBottomLeft = v2.cross(v1).normalized();
// Get center (a+b+c)*(1/3)
Vector triangleCenterBL = (vectors[i - 1][j].add(vectors[i][j]).add(vectors[i - 1][j - 1])).scale(1.0 / 3);
normals.add(new Vector[]{triangleCenterBL, triangleCenterBL.add(normalBottomLeft)});
} else {
normalBottomLeft = null; // If j==0, there is no bottom left triangle above
}
/**
* We have everything to start drawing
*/
// Set some color
if (j == 0) {
// Initialization vector
gl.glTexCoord1d(mapTextureToHeight(vectors[i][j].z));
drawer.glVertexV(vectors[i][j]);
} else {
drawer.glNormalV(normalBottomLeft);
}
// Shift left
gl.glTexCoord1d(mapTextureToHeight(vectors[i - 1][j].z));
drawer.glVertexV(vectors[i - 1][j]);
// Right down diagonally
if (j < vectors[i].length - 1) { // Skip if we are reached the end
gl.glTexCoord1d(mapTextureToHeight(vectors[i][j + 1].z));
drawer.glNormalV(normalTopRight);
drawer.glVertexV(vectors[i][j + 1]);
}
}
gl.glEnd();
}
if (showGrid)
gl.glPolygonMode( gl.GL_FRONT_AND_BACK, gl.GL_FILL );
if (drawNormals) {
for (Vector[] arrow : normals) {
if (yellowNormals)
Material.YELLOW.use(gl);
else
gl.glTexCoord1d(mapTextureToHeight(arrow[0].z));
drawer.drawArrow(arrow[0], arrow[1], 0.05);
}
}
texture.unbind(gl);
}
The most obvious reason for the stripes is the fact I draw the triangles per column, causing OpenGL to not be able to smoothen the shading on the polygons (GL_SMOOTH). Is there any way to fix this?
[Edit1] Copied from your comment by Spektre
I just finished calculating the average normals, I indeed have a smooth terrain now, but the lighting looks kind of dull (no depth)
Here is the new code that draws the terrain:
public void draw() {
if (showGrid)
gl.glPolygonMode( gl.GL_FRONT_AND_BACK, gl.GL_LINE);
texture.bind(gl);
Material.TERRAIN.use(gl);
for(int i=1;i<vectors.length;i++) {
gl.glBegin(gl.GL_TRIANGLE_STRIP);
for (int j = 0; j < vectors[i].length; j++) {
// Initialization vector
gl.glTexCoord1d(mapTextureToHeight(vectors[i][j].z));
drawer.glNormalV(normals.get(vectors[i][j]));
drawer.glVertexV(vectors[i][j]);
// Shift left
gl.glTexCoord1d(mapTextureToHeight(vectors[i - 1][j].z));
drawer.glNormalV(normals.get(vectors[i - 1][j]));
drawer.glVertexV(vectors[i - 1][j]);
}
gl.glEnd();
}
if (showGrid)
gl.glPolygonMode( gl.GL_FRONT_AND_BACK, gl.GL_FILL );
if (drawNormals)
drawFaceNormals();
texture.unbind(gl);
}
I cleaned it up, I am sure the normals are pointing the correct way using the drawnormals function and made sure OpenGL is seeing the top of the terrain as FRONT using (gl.GL_FRONT -> draws only above terrain, not below).
Here is the complete class: PasteBin
Thanks to #Spektre for helping me out.
After properly calculating the average normal of all surrounding faces on a vertex and using this normal for glNormal, the shading was correct.

Centering map or camera 2D game

I've tried so many solutions that it's possible that my code is a bit mixed up, but whatever I try, it just won't work.
Basically I made a map with Tiled, where my player can run around and bump into stuff. I want the whole map to be visible for the whole time (it's 20 by 15, 64 pixels a tile). The camera doesn't need to move around or follow the player, it has to stay still at the center of the map.
The problem is that the map only shows in the upper right corner of the screen. When I centered the camera to the map itself it messed up the collission detection, (bumping into trees while they were not visible & walking through visible trees). So what I want to do is center the map to 0,0 where my camera also is (at least I think..).
Another thing I'd like to accomplish is that the size of the map gets resized to match different mobile phones. Tried to accomplish this with the stretchviewport, but haven't been able to test this.
public class PlayScreen implements Screen {
TiledMap map;
OrthogonalTiledMapRenderer mapRenderer;
OrthographicCamera cam;
float unitScale = 1 / 64f;
OrthogonalTiledMapRenderer renderer = new OrthogonalTiledMapRenderer(map, unitScale);
Viewport viewport;
public void show() {
map = new TmxMapLoader().load("maps/map.tmx");
mapRenderer = new OrthogonalTiledMapRenderer(map);
cam = new OrthographicCamera(Gdx.graphics.getWidth() / 2, Gdx.graphics.getHeight() / 2);
cam.setToOrtho(false);
viewport = new StretchViewport(1280, 960, cam);
bounds = new ArrayList<Rectangle>();
for(int i = 0; i < 20; i++){
for(int j = 0; j < 15; j++){
TiledMapTileLayer cur = (TiledMapTileLayer) map.getLayers().get(1);
Cell cell = new Cell();
Vector3 center = new Vector3(cur.getWidth() * cur.getTileWidth() / 2, cur.getHeight() * cur.getTileHeight() / 2, 0);
cam.position.set(Gdx.graphics.getWidth() / 2, Gdx.graphics.getHeight() / 2, 0);
cam.update();
if(cur.getCell(i,j) != null){ //null = first layer != --> if its not
cell = cur.getCell(i, j);
System.out.println(i + ", " + j + ", " + cell.getTile().getId());
bounds.add(new Rectangle(i * 64, j * 64, 64 , 64));
}
}
}
public void render(float delta) {
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
mapRenderer.setView(cam);
mapRenderer.render();
cam.position.set(0, 0, 0);
cam.update();
batch.setProjectionMatrix(cam.combined);
batch.begin();
batch.draw(player.getCurrentFrame(), player.getPosition().x , player.getPosition().y);
player.update();
for(int i = 0; i < bounds.size(); i++){
if(bounds.get(i).overlaps(player.getBounds())){
int x = (int)bounds.get(i).x / 64;
int y = (int)bounds.get(i).y / 64;
TiledMapTileLayer cur = (TiledMapTileLayer)map.getLayers().get(1);
Cell cell = cur.getCell(x, y);
if(cell.getTile().getProperties().containsKey("blocked")){
System.out.println("bush");
}
player.reAdjust();
}
}
batch.end();
}
public void resize(int width, int height) {
viewport.update(width, height);
}
Nevermind, I deleted: cam.position.set(0, 0, 0); and everything seems to work just fine. Guess I already made some changes what caused it to work, just didn't see it cause this was still around.

how to remove a color (make it transparent) taking the color from a pixel in OpenGL

What I want to do is this, imagine I have a little tile (32x32) with the Sun inside, that is a yellow circle with black background.
I want to draw that Sun in the sky (light blue). Obviously the black border will ruin my composition. I have to make OpenGL delete that black color.
In photoshop I would select with the magic tool all the black pixels and then remove them saving the new file with alpha channel.
But this can be too long to do if you have millions of images. I have to handle this issue at runtime.
I was looking for the glStencilMask method, but that will work if you actually have a texture to use as mask.
I found an example for C# that talks about taking the 24bit image and transform to 32bit with alpha channel, this sound to me good, but maybe in matter of time consuming and resource spending is too much especially if the number of tile is high (about 30x20 tiles at 60fps)
The thing is that this is difficult to reach, and the one who reach this goal is not going to tell anybody...
Actually the code to draw the tile is this, that will cut, translate, rotate and all the stuff that are needed.
GL11.glPushMatrix();
// bind to the appropriate texture for this sprite
this.texture.bind();
// translate to the right location and prepare to draw
GL11.glColor3f(1, 1, 1);
GL11.glTranslated(x + ((32 - this.texture.getImageWidth()) / 2) + (this.texture.getImageWidth() / 2), y + ((32 - this.texture.getImageHeight()) / 2)
+ (this.texture.getImageHeight() / 2), 0);
// System.out.println(this.angle);
GL11.glRotated(this.angle, 0, 0, 1);
GL11.glTranslated(-this.texture.getImageWidth() / 2, -this.texture.getImageHeight() / 2, 0);
// draw a quad textured to match the sprite
GL11.glBegin(GL11.GL_QUADS);
{
GL11.glTexCoord2f(0, 0);
GL11.glVertex2f(0, 0);
GL11.glTexCoord2f(0, this.texture.getHeight());
GL11.glVertex2f(0, this.texture.getImageHeight());
GL11.glTexCoord2f(this.texture.getWidth(), this.texture.getHeight());
GL11.glVertex2f(this.texture.getImageWidth(), this.texture.getImageHeight());
GL11.glTexCoord2f(this.texture.getWidth(), 0);
GL11.glVertex2f(this.texture.getImageWidth(), 0);
}
GL11.glEnd();
// restore the model view matrix to prevent contamination
GL11.glPopMatrix();
texture.bind is this:
public void bind() {
GL11.glBindTexture(this.target, this.textureID);
}
With image that contain a transparent layer all is perfect.
Once I have find out how to remove that specific color I wish to remove the color according to the upper-left pixel and that will be done with glReadPixels()
here is the loader:
public Texture getTexture(String resourceName, int target, int dstPixelFormat, int minFilter, int magFilter) throws IOException {
int srcPixelFormat = 0;
// create the texture ID for this texture
int textureID = this.createTextureID();
Texture texture = new Texture(target, textureID);
// bind this texture
GL11.glBindTexture(target, textureID);
BufferedImage bufferedImage = this.loadImage(resourceName);
texture.setWidth(bufferedImage.getWidth());
texture.setHeight(bufferedImage.getHeight());
if (bufferedImage.getColorModel().hasAlpha()) {
srcPixelFormat = GL11.GL_RGBA;
} else {
srcPixelFormat = GL11.GL_RGB;
}
// convert that image into a byte buffer of texture data
ByteBuffer textureBuffer = this.convertImageData(bufferedImage, texture);
if (target == GL11.GL_TEXTURE_2D) {
GL11.glTexParameteri(target, GL11.GL_TEXTURE_MIN_FILTER, minFilter);
GL11.glTexParameteri(target, GL11.GL_TEXTURE_MAG_FILTER, magFilter);
}
// produce a texture from the byte buffer
GL11.glTexImage2D(target, 0, dstPixelFormat, this.get2Fold(bufferedImage.getWidth()), this.get2Fold(bufferedImage.getHeight()), 0, srcPixelFormat,
GL11.GL_UNSIGNED_BYTE, textureBuffer);
return texture;
}
Actually I've created a solution to the problem, so I've created a method that I am going to post here on SO to knowledge for future people.
/**
* Sets the specified colour, or the color taken from the top-left pixel, to transparent
*
* #param image
* The image to process (<code>BufferedImage</code>)
* #param cornerTransparency
* If true the method will take the top-left pixel's colour and make it transparent in the image
* #param transCol
* If <code>cornerTransparency</code> is false, this is the color that will be set to transparent.
* #return The loaded buffered image
* #throws IOException
* Indicates a failure to find a resource
*/
private BufferedImage loadImage(BufferedImage image, boolean cornerTransparency, int transCol) throws IOException {
if(image == null){
throw new IllegalArgumentException();
}
int firstPixel = bufferedImage.getRGB(0, 0);
BufferedImage bff = new BufferedImage(bufferedImage.getWidth(), bufferedImage.getHeight(), BufferedImage.TYPE_INT_ARGB);
for (int y = 0; y < bufferedImage.getHeight(); ++y) {
for (int x = 0; x < bufferedImage.getWidth(); ++x) {
int argb = bufferedImage.getRGB(x, y);
if (cornerTransparency) {
if (argb == firstPixel) {//we are certain that they are of the same type (RGB,ARGB etc)
bff.setRGB(x, y, 0); //black with alpha = 0
} else {
bff.setRGB(x, y, argb);
}
} else {
if ((argb & 0xFF000000) == (transCol & 0xFF000000)) {//not sure if are of the same type, I remove the alpha data.
bff.setRGB(x, y, 0); //black with alpha = 0
} else {
bff.setRGB(x, y, argb);
}
}
}
}
return bff;
} else {
return bufferedImage;
}

Categories