I am trying to select a specific region of a texture in LWJGL during the drawing process, but my efforts have been fruitless. How (if possible) can I select only a region of a whole texture during drawing.
Please note that I am nowhere new to Java, I am an experienced programmer, but not when it comes to LWGJL, as I'm still getting the full grasps with it.
Below is my code.
Sprite.java
public class Sprite
{
private Icon icon;
private int width;
private int height;
private int offcutX; // all below and this for selecting the region of the image.
private int offcutY;
private int imageX;
private int imageY;
public Sprite(TextureRegistry registry, String ref)
{
this(registry, ref, 0, 0, 0, 0);
}
public Sprite (TextureRegistry registry, String ref, int offcutX, int offcutY, int imageX, int imageY)
{
try
{
icon = registry.getIcon("net/blockbuster/resources/" + ref); // loads the icon and converts it to opengl-readable format.
width = icon.getIconWidth();
height = icon.getIconHeight();
this.offcutX = offcutX;
this.offcutY = offcutY;
this.imageX = imageX;
this.imageY = imageY;
}
catch (IOException e)
{
e.printStackTrace();
System.exit(-1);
}
}
public int getWidth()
{
return icon.getIconWidth();
}
public int getHeight()
{
return icon.getIconHeight();
}
public void draw(int x, int y) // drawing method, called on every loop.
{
glPushMatrix();
icon.bind();
glTranslatef(x, y, 0);
glBegin(GL_QUADS);
{ // I would like to be able to do this within this block.
glTexCoord2f(0, 0);
glVertex2f(0, 0);
glTexCoord2f(0, 1);
glVertex2f(0, height);
glTexCoord2f(1, 1);
glVertex2f(width, height);
glTexCoord2f(1, 0);
glVertex2f(width, 0);
}
glEnd();
glPopMatrix();
}
}
TextureRegistry.java
public class TextureRegistry
{
private HashMap<String, Icon> table = new HashMap<String, Icon>(); // map to hold all loaded textures
public Icon getIcon(String resourceName) throws IOException
{
Icon tex = table.get(resourceName);
if (tex != null)
{
return tex;
}
tex = getIcon(resourceName, GL_TEXTURE_2D, GL_RGBA8, GL_LINEAR, GL_LINEAR);
table.put(resourceName, tex);
return tex;
}
public Icon getIcon(String resourceName, int target, int dstPixelFormat, int minFilter, int magFilter) throws IOException
{
BufferedImage image = loadImage(resourceName);
int textureID = loadTexture(image);
Icon icon = new Icon(target, textureID);
icon.setWidth(image.getWidth());
icon.setHeight(image.getHeight());
return icon;
}
public static int loadTexture(BufferedImage image)
{
int[] pixels = new int[image.getWidth() * image.getHeight()];
image.getRGB(0, 0, image.getWidth(), image.getHeight(), pixels, 0, image.getWidth());
ByteBuffer buffer = BufferUtils.createByteBuffer(image.getWidth() * image.getHeight() * 4);
for (int y = 0; y < image.getHeight(); y++)
{
for (int x = 0; x < image.getWidth(); x++)
{
int pixel = pixels[y * image.getWidth() + x];
buffer.put((byte)((pixel >> 16) & 0xFF)); // r
buffer.put((byte)((pixel >> 8) & 0xFF)); // g
buffer.put((byte)(pixel * 0xFF)); // b
buffer.put((byte)((pixel >> 24) & 0xFF)); // a
}
}
buffer.flip();
int textureID = glGenTextures();
glBindTexture(GL_TEXTURE_2D, textureID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL12.GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, image.getWidth(), image.getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
return textureID;
}
public static BufferedImage loadImage(String ref) throws IOException
{
URL url = TextureRegistry.class.getClassLoader().getResource(ref);
if (url == null)
{
throw new IOException("Cannot find: " + ref);
}
Image img = new ImageIcon(url).getImage();
BufferedImage bufferedImage = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB);
Graphics g = bufferedImage.getGraphics();
g.drawImage(img, 0, 0, null);
g.dispose();
return bufferedImage;
}
}
Icon.java
public class Icon
{
private int target;
private int iconID;
private int width;
private int height;
private int iconWidth;
private int iconHeight;
private float widthRatio;
private float heightRatio;
public Icon(int target, int iconID)
{
this.target = target;
this.iconID = iconID;
}
public void bind()
{
glBindTexture(target, iconID); // binds the texture
}
public void setHeight(int newHeight)
{
this.height = newHeight;
setHeight();
}
public void setWidth(int newWidth)
{
this.width = newWidth;
setWidth();
}
public int getIconHeight()
{
return height;
}
public int getIconWidth()
{
return width;
}
public float getHeight()
{
return heightRatio;
}
public float getWidth()
{
return widthRatio;
}
public void setIconHeight(int iconHeight)
{
this.iconHeight = iconHeight;
setHeight();
}
public void setIconWidth(int iconWidth)
{
this.iconWidth = iconWidth;
setWidth();
}
private void setHeight()
{
if (iconHeight != 0)
{
heightRatio = ((float)height) / iconHeight;
}
}
private void setWidth()
{
if (iconWidth != 0)
{
widthRatio = ((float)width) / iconWidth;
}
}
}
To specify a region of a texture to be drawn all you need to do is modify your texCoords. Currently you are using your entire texture, if for example you wanted only the quarter of it closest to the origin you would use this in your draw method:
glTexCoord2f(0, 0);
glVertex2f(0, 0);
glTexCoord2f(0, 1/2f);
glVertex2f(0, height);
glTexCoord2f(1/2f, 1/2f);
glVertex2f(width, height);
glTexCoord2f(1/2f, 0);
glVertex2f(width, 0);
which would result in an image the same size as before although using only the bottom left quarter of the texture.
Related
I'm tryng to create a Minecraft clone, but my code render only one texture, i'm a opengl beginner, some help please?
(I'm italian so excuse me for my bad english)
Here my Texture class
private String location;
private int id;
private boolean loaded = false;
public Texture(String location) {
this.location = location;
}
public void loadTexture() {
if (!this.loaded) {
this.loaded = true;
try {
InputStream stream = new FileInputStream("Textures/" + this.location);
PNGDecoder decoder = new PNGDecoder(stream);
ByteBuffer buffer = ByteBuffer.allocateDirect(4 * decoder.getWidth() * decoder.getHeight());
decoder.decode(buffer, decoder.getWidth() * 4);
buffer.flip();
this.id = GL11.glGenTextures();
GL11.glBindTexture(GL11.GL_TEXTURE_2D, this.id);
GL11.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 1);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST);
GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, decoder.getWidth(), decoder.getHeight(), 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, buffer);
GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public int getId() {
return this.id;
}
my chunk data class that renderize
public class ChunkData {
private final Vector3i chunkPos;
private final Block[][][] blocks;
public ChunkData(Vector3i pos) {
this.chunkPos = new Vector3i(pos);
this.blocks = new Block[16][16][16];
}
public static boolean inChunk(int x, int y, int z) {
return x >= 0 && y >= 0 && z >= 0 && x < 16 && y < 16 && z < 16;
}
public void setBlockAt(int x, int y, int z, Block block) {
if (inChunk(x, y, z)) {
this.blocks[x][y][z] = block;
}
}
public Block getBlockAt(int x, int y, int z) {
if (inChunk(x, y, z)) {
return this.blocks[x][y][z];
}
return null;
}
public Vector3i getChunkPos() {
return this.chunkPos;
}
public void render() {
blocks[1][1][2].getTexture().loadTexture();
blocks[2][2][1].getTexture().loadTexture();
}
}
there are 2 blocks, one contains this texture
#Override
public Texture getTexture() {
return new Texture("Dirt.png");
}
and another is this
#Override
public Texture getTexture() {
return new Texture("Stone.png");
}
the blocks[1][1][2] contains a Stone texture and the [2][2][2] a Dirt texture but when i run the program it displays both as a stone texture.
I've been following a tutorial by LWJGLGameDev on LWJGL found at https://lwjglgamedev.gitbooks.io/3d-game-development-with-lwjgl/content/. I'm using its source code and have my project set up the same way as theirs. Everything seemed fine until I tried to run the code from the tutorial in chapter 8 when the Renderer tries to create the modelViewMatrix uniform and it throws an exception that it could not find the uniform modelViewMatrix. I'm a newbie at LWJGL and openGL so I don't fully understand what is happening. Thank you in advance. Here is the relevant code:
public class Renderer {
/**
* Field of View in Radians
*/
private static final float FOV = (float) Math.toRadians(60.0f);
private static final float Z_NEAR = 0.01f;
private static final float Z_FAR = 1000.f;
private final Transformation transformation;
private ShaderProgram shaderProgram;
public Renderer() {
transformation = new Transformation();
}
public void init(Window window) throws Exception {
// Create shader
shaderProgram = new ShaderProgram();
shaderProgram.createVertexShader(Utils.loadResource("/shaders/vertex.vs"));
shaderProgram.createFragmentShader(Utils.loadResource("/shaders/fragment.fs"));
shaderProgram.link();
// Create uniforms for modelView and projection matrices and texture
shaderProgram.createUniform("projectionMatrix");
shaderProgram.createUniform("texture_sampler");
shaderProgram.createUniform("modelViewMatrix");
}
public void clear() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
public void render(Window window, Camera camera, GameItem[] gameItems) {
clear();
if ( window.isResized() ) {
glViewport(0, 0, window.getWidth(), window.getHeight());
window.setResized(false);
}
shaderProgram.bind();
// Update projection Matrix
Matrix4f projectionMatrix = transformation.getProjectionMatrix(FOV, window.getWidth(), window.getHeight(), Z_NEAR, Z_FAR);
shaderProgram.setUniform("projectionMatrix", projectionMatrix);
// Update view Matrix
Matrix4f viewMatrix = transformation.getViewMatrix(camera);
shaderProgram.setUniform("texture_sampler", 0);
// Render each gameItem
for(GameItem gameItem : gameItems) {
// Set model view matrix for this item
Matrix4f modelViewMatrix = transformation.getModelViewMatrix(gameItem, viewMatrix);
shaderProgram.setUniform("modelViewMatrix", modelViewMatrix);
// Render the mes for this game item
gameItem.getMesh().render();
}
shaderProgram.unbind();
}
public void cleanup() {
if (shaderProgram != null) {
shaderProgram.cleanup();
}
}
}
ShaderProgram:
public class ShaderProgram {
private final int programId;
private int vertexShaderId;
private int fragmentShaderId;
private final Map<String, Integer> uniforms;
public ShaderProgram() throws Exception {
programId = glCreateProgram();
if (programId == 0) {
throw new Exception("Could not create Shader");
}
uniforms = new HashMap<>();
}
public void createUniform(String uniformName) throws Exception {
int uniformLocation = glGetUniformLocation(programId, uniformName);
if (uniformLocation < 0) {
throw new Exception("Could not find uniform:" + uniformName);
}
uniforms.put(uniformName, uniformLocation);
}
public void setUniform(String uniformName, Matrix4f value) {
try (MemoryStack stack = MemoryStack.stackPush()) {
// Dump the matrix into a float buffer
FloatBuffer fb = stack.mallocFloat(16);
value.get(fb);
glUniformMatrix4fv(uniforms.get(uniformName), false, fb);
}
}
public void setUniform(String uniformName, int value) {
glUniform1i(uniforms.get(uniformName), value);
}
public void createVertexShader(String shaderCode) throws Exception {
vertexShaderId = createShader(shaderCode, GL_VERTEX_SHADER);
}
public void createFragmentShader(String shaderCode) throws Exception {
fragmentShaderId = createShader(shaderCode, GL_FRAGMENT_SHADER);
}
protected int createShader(String shaderCode, int shaderType) throws Exception {
int shaderId = glCreateShader(shaderType);
if (shaderId == 0) {
throw new Exception("Error creating shader. Type: " + shaderType);
}
glShaderSource(shaderId, shaderCode);
glCompileShader(shaderId);
if (glGetShaderi(shaderId, GL_COMPILE_STATUS) == 0) {
throw new Exception("Error compiling Shader code: " + glGetShaderInfoLog(shaderId, 1024));
}
glAttachShader(programId, shaderId);
return shaderId;
}
public void link() throws Exception {
glLinkProgram(programId);
if (glGetProgrami(programId, GL_LINK_STATUS) == 0) {
throw new Exception("Error linking Shader code: " + glGetProgramInfoLog(programId, 1024));
}
if (vertexShaderId != 0) {
glDetachShader(programId, vertexShaderId);
}
if (fragmentShaderId != 0) {
glDetachShader(programId, fragmentShaderId);
}
glValidateProgram(programId);
if (glGetProgrami(programId, GL_VALIDATE_STATUS) == 0) {
System.err.println("Warning validating Shader code: " + glGetProgramInfoLog(programId, 1024));
}
}
public void bind() {
glUseProgram(programId);
}
public void unbind() {
glUseProgram(0);
}
public void cleanup() {
unbind();
if (programId != 0) {
glDeleteProgram(programId);
}
}
}
Transformation:
public class Transformation {
private final Matrix4f projectionMatrix;
private final Matrix4f modelViewMatrix;
private final Matrix4f viewMatrix;
public Transformation() {
projectionMatrix = new Matrix4f();
modelViewMatrix = new Matrix4f();
viewMatrix = new Matrix4f();
}
public final Matrix4f getProjectionMatrix(float fov, float width, float height, float zNear, float zFar) {
float aspectRatio = width / height;
projectionMatrix.identity();
projectionMatrix.perspective(fov, aspectRatio, zNear, zFar);
return projectionMatrix;
}
public Matrix4f getViewMatrix(Camera camera) {
Vector3f cameraPos = camera.getPosition();
Vector3f rotation = camera.getRotation();
viewMatrix.identity();
// First do the rotation so camera rotates over its position
viewMatrix.rotate((float)Math.toRadians(rotation.x), new Vector3f(1, 0, 0))
.rotate((float)Math.toRadians(rotation.y), new Vector3f(0, 1, 0));
// Then do the translation
viewMatrix.translate(-cameraPos.x, -cameraPos.y, -cameraPos.z);
return viewMatrix;
}
public Matrix4f getModelViewMatrix(GameItem gameItem, Matrix4f viewMatrix) {
Vector3f rotation = gameItem.getRotation();
modelViewMatrix.identity().translate(gameItem.getPosition()).
rotateX((float)Math.toRadians(-rotation.x)).
rotateY((float)Math.toRadians(-rotation.y)).
rotateZ((float)Math.toRadians(-rotation.z)).
scale(gameItem.getScale());
Matrix4f viewCurr = new Matrix4f(viewMatrix);
return viewCurr.mul(modelViewMatrix);
}
}
Utils:
public class Utils {
public static String loadResource(String fileName) throws Exception {
String result;
try (InputStream in = Utils.class.getClass().getResourceAsStream(fileName);
Scanner scanner = new Scanner(in, "UTF-8")) {
result = scanner.useDelimiter("\\A").next();
}
return result;
}
}
GameItem:
public class GameItem
{
private final Mesh mesh;
private final Vector3f position;
private float scale;
private final Vector3f rotation;
public GameItem(Mesh mesh)
{
this.mesh=mesh;
position=new Vector3f(0,0,0);
scale=1;
rotation=new Vector3f(0,0,0);
}
public Vector3f getPosition()
{
return position;
}
public void setPosition(float x, float y, float z)
{
this.position.x=x;
this.position.y=y;
this.position.z=z;
}
public float getScale()
{
return scale;
}
public void setScale(float scale)
{
this.scale=scale;
}
public Vector3f getRotation()
{
return rotation;
}
public void setRotation(float x, float y, float z) {
this.rotation.x = x;
this.rotation.y = y;
this.rotation.z = z;
}
public Mesh getMesh() {
return mesh;
}
}
Mesh:
public class Mesh {
private final int vaoId;
private final List<Integer> vboIdList;
private final int vertexCount;
private final Texture texture;
public Mesh(float[] positions, float[] textCoords, int[] indices, Texture texture) {
FloatBuffer posBuffer = null;
FloatBuffer textCoordsBuffer = null;
IntBuffer indicesBuffer = null;
try {
this.texture = texture;
vertexCount = indices.length;
vboIdList = new ArrayList();
vaoId = glGenVertexArrays();
glBindVertexArray(vaoId);
// Position VBO
int vboId = glGenBuffers();
vboIdList.add(vboId);
posBuffer = MemoryUtil.memAllocFloat(positions.length);
posBuffer.put(positions).flip();
glBindBuffer(GL_ARRAY_BUFFER, vboId);
glBufferData(GL_ARRAY_BUFFER, posBuffer, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
// Texture coordinates VBO
vboId = glGenBuffers();
vboIdList.add(vboId);
textCoordsBuffer = MemoryUtil.memAllocFloat(textCoords.length);
textCoordsBuffer.put(textCoords).flip();
glBindBuffer(GL_ARRAY_BUFFER, vboId);
glBufferData(GL_ARRAY_BUFFER, textCoordsBuffer, GL_STATIC_DRAW);
glVertexAttribPointer(1, 2, GL_FLOAT, false, 0, 0);
// Index VBO
vboId = glGenBuffers();
vboIdList.add(vboId);
indicesBuffer = MemoryUtil.memAllocInt(indices.length);
indicesBuffer.put(indices).flip();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboId);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indicesBuffer, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
} finally {
if (posBuffer != null) {
MemoryUtil.memFree(posBuffer);
}
if (textCoordsBuffer != null) {
MemoryUtil.memFree(textCoordsBuffer);
}
if (indicesBuffer != null) {
MemoryUtil.memFree(indicesBuffer);
}
}
}
public int getVaoId() {
return vaoId;
}
public int getVertexCount() {
return vertexCount;
}
public void render() {
// Activate firs texture bank
glActiveTexture(GL_TEXTURE0);
// Bind the texture
glBindTexture(GL_TEXTURE_2D, texture.getId());
// Draw the mesh
glBindVertexArray(getVaoId());
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glDrawElements(GL_TRIANGLES, getVertexCount(), GL_UNSIGNED_INT, 0);
// Restore state
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glBindVertexArray(0);
}
public void cleanUp() {
glDisableVertexAttribArray(0);
// Delete the VBOs
glBindBuffer(GL_ARRAY_BUFFER, 0);
for (int vboId : vboIdList) {
glDeleteBuffers(vboId);
}
// Delete the texture
texture.cleanup();
// Delete the VAO
glBindVertexArray(0);
glDeleteVertexArrays(vaoId);
}
}
Window:
public class Window {
private final String title;
private int width;
private int height;
private long windowHandle;
private boolean resized;
private boolean vSync;
public Window(String title, int width, int height, boolean vSync) {
this.title = title;
this.width = width;
this.height = height;
this.vSync = vSync;
this.resized = false;
}
public void init() {
// Setup an error callback. The default implementation
// will print the error message in System.err.
GLFWErrorCallback.createPrint(System.err).set();
// Initialize GLFW. Most GLFW functions will not work before doing this.
if (!glfwInit()) {
throw new IllegalStateException("Unable to initialize GLFW");
}
glfwDefaultWindowHints(); // optional, the current window hints are already the default
glfwWindowHint(GLFW_VISIBLE, GL_FALSE); // the window will stay hidden after creation
glfwWindowHint(GLFW_RESIZABLE, GL_TRUE); // the window will be resizable
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
// Create the window
windowHandle = glfwCreateWindow(width, height, title, NULL, NULL);
if (windowHandle == NULL) {
throw new RuntimeException("Failed to create the GLFW window");
}
// Setup resize callback
glfwSetFramebufferSizeCallback(windowHandle, (window, width, height) -> {
this.width = width;
this.height = height;
this.setResized(true);
});
// Setup a key callback. It will be called every time a key is pressed, repeated or released.
glfwSetKeyCallback(windowHandle, (window, key, scancode, action, mods) -> {
if (key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE) {
glfwSetWindowShouldClose(window, true); // We will detect this in the rendering loop
}
});
// Get the resolution of the primary monitor
GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
// Center our window
glfwSetWindowPos(
windowHandle,
(vidmode.width() - width) / 2,
(vidmode.height() - height) / 2
);
// Make the OpenGL context current
glfwMakeContextCurrent(windowHandle);
if (isvSync()) {
// Enable v-sync
glfwSwapInterval(1);
}
// Make the window visible
glfwShowWindow(windowHandle);
GL.createCapabilities();
// Set the clear color
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glEnable(GL_DEPTH_TEST);
}
public long getWindowHandle() {
return windowHandle;
}
public void setClearColor(float r, float g, float b, float alpha) {
glClearColor(r, g, b, alpha);
}
public boolean isKeyPressed(int keyCode) {
return glfwGetKey(windowHandle, keyCode) == GLFW_PRESS;
}
public boolean windowShouldClose() {
return glfwWindowShouldClose(windowHandle);
}
public String getTitle() {
return title;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public boolean isResized() {
return resized;
}
public void setResized(boolean resized) {
this.resized = resized;
}
public boolean isvSync() {
return vSync;
}
public void setvSync(boolean vSync) {
this.vSync = vSync;
}
public void update() {
glfwSwapBuffers(windowHandle);
glfwPollEvents();
}
}
Never mind, the problem was that the vertex.vs file had to specify the uniform:
#version 330
layout (location=0) in vec3 position;
layout (location=1) in vec2 texCoord;
out vec2 outTexCoord;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
void main()
{
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
outTexCoord = texCoord;
}
there! I try to display a video stream, which comes from server as byte array.
Data in this array is h264 encoded image and i decode it with bytedeco javacpp-presets library in this way:
public class DMDecoder {
private static final String LOG_TAG = "DMDecoder";
private AVCodec avCodec;
private AVCodecContext avCodecContext;
private AVFrame avFrame;
private AVPacket avPacket;
private boolean wasIFrame;
private long IFrameTimeStampMs;
private int maxFps;
private int codecId;
private DMDecoderCallback callback;
public DMDecoder(DMDecoderCallback cb) {
this.callback = cb;
this.codecId = AV_CODEC_ID_H264;
avcodec_register_all();
restart();
}
public void restart() {
stop();
start();
}
public void stop() {
frames = 0;
if (avCodecContext != null) {
avcodec_close(avCodecContext);
avcodec_free_context(avCodecContext);
avCodecContext = null;
}
if (avCodec != null) {
av_free(avCodec);
avCodec = null;
}
if (avFrame != null) {
av_frame_free(avFrame);
avFrame = null;
}
if (avPacket != null) {
av_free_packet(avPacket);
avPacket = null;
}
}
public void start() {
avCodec = avcodec_find_decoder(codecId);
avCodecContext = avcodec_alloc_context3(avCodec);
AVDictionary opts = new AVDictionary();
avcodec_open2(avCodecContext, avCodec, opts);
avFrame = av_frame_alloc();
avPacket = new AVPacket();
av_init_packet(avPacket);
}
public VideoFrame decode(byte[] data, int dataOffset, int dataSize) {
avPacket.pts(AV_NOPTS_VALUE);
avPacket.dts(AV_NOPTS_VALUE);
avPacket.data(new BytePointer(data).position(dataOffset));
avPacket.size(dataSize);
avPacket.pos(-1);
IntBuffer gotPicture = IntBuffer.allocate(1);
int processedBytes = avcodec_decode_video2(
avCodecContext, avFrame, gotPicture, avPacket);
if (avFrame.width() == 0 || avFrame.height() == 0) return null;
VideoFrame frame = new VideoFrame();
frame.colorPlane0 = new byte[avFrame.width() * avFrame.height()];
frame.colorPlane1 = new byte[avFrame.width() / 2 * avFrame.height() / 2];
frame.colorPlane2 = new byte[avFrame.width() / 2 * avFrame.height() / 2];
if (avFrame.data(0) != null) avFrame.data(0).get(frame.colorPlane0);
if (avFrame.data(1) != null) avFrame.data(1).get(frame.colorPlane1);
if (avFrame.data(2) != null) avFrame.data(2).get(frame.colorPlane2);
frame.lineSize0 = avFrame.width();
frame.lineSize1 = avFrame.width() / 2;
frame.lineSize2 = avFrame.width() / 2;
frame.width = avFrame.width();
frame.height = avFrame.height();
return frame;
}
}
VideoFrame class is just simple POJO:
public class VideoFrame {
public byte[] colorPlane0;
public byte[] colorPlane1;
public byte[] colorPlane2;
public int lineSize0;
public int lineSize1;
public int lineSize2;
public int width;
public int height;
public long presentationTime;
}
After decoding i send this frame to my GLRenderer class
public class GLRenderer implements GLSurfaceView.Renderer {
private static final String LOG_TAG = "GLRenderer";
private TexturePlane plane;
private ConcurrentLinkedQueue<VideoFrame> frames;
private int maxFps = 30;
private VideoFrame currentFrame;
private long startTime, endTime;
private int viewWidth, viewHeight;
private boolean isFirstFrameProcessed;
public GLRenderer(int viewWidth, int viewHeight) {
frames = new ConcurrentLinkedQueue<>();
this.viewWidth = viewWidth;
this.viewHeight = viewHeight;
}
// mMVPMatrix is an abbreviation for "Model View Projection Matrix"
private final float[] mMVPMatrix = new float[16];
private final float[] mProjectionMatrix = new float[16];
private final float[] mViewMatrix = new float[16];
#Override
public void onSurfaceCreated(GL10 unused, EGLConfig config) {
// Set the background frame color
GLES20.glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
plane = new TexturePlane();
}
public void setMaxFps(int maxFps) {
this.maxFps = maxFps;
}
#Override
public void onDrawFrame(GL10 unused) {
// Draw background color
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
// Set the camera position (View matrix)
Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
// Calculate the projection and view transformation
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
if (!isFirstFrameProcessed) checkViewPort(viewWidth, viewHeight);
if (maxFps > 0 && startTime > 0) {
endTime = System.currentTimeMillis();
long time = endTime - startTime;
//
long wantedTime = 1000 / maxFps;
//
long wait;
if (time < wantedTime) {
wait = wantedTime - time;
//
try {
Thread.sleep(wait);
} catch (InterruptedException e) {
Log.e(LOG_TAG, "thread interrupted exception");
}
}
}
startTime = System.currentTimeMillis();
tick();
plane.draw(mMVPMatrix);
}
private void updateFrame(VideoFrame frame) {
plane.updateTexture(frame.colorPlane0, frame.width, frame.height, 0);
plane.updateTexture(frame.colorPlane1, frame.width / 2, frame.height / 2, 1);
plane.updateTexture(frame.colorPlane2, frame.width / 2, frame.height / 2, 2);
plane.setTextureWidth(frame.width);
plane.setTextureHeight(frame.height);
}
private void tick() {
if (frames.isEmpty()) return;
VideoFrame frame = frames.peek();
if (frame == null) return;
long tms = System.currentTimeMillis();
if (frame.presentationTime <= tms) {
updateFrame(frame);
currentFrame = frame;
frames.remove(frame);
}
}
#Override
public void onSurfaceChanged(GL10 unused, int width, int height) {
checkViewPort(width, height);
viewWidth = width;
viewHeight = height;
plane.setTextureWidth(width);
plane.setTextureHeight(height);
}
private void checkViewPort(int width, int height) {
float viewRatio = (float) width / height;
if (currentFrame != null) {
float targetRatio = (float) currentFrame.width / currentFrame.height;
int x, y, newWidth, newHeight;
if (targetRatio > viewRatio) {
newWidth = width;
newHeight = (int) (width / targetRatio);
x = 0;
y = (height - newHeight) / 2;
} else {
newHeight = height;
newWidth = (int) (height * targetRatio);
y = 0;
x = (width - newWidth) / 2;
}
GLES20.glViewport(x, y, newWidth, newHeight);
} else {
GLES20.glViewport(0, 0, width, height);
}
Matrix.frustumM(mProjectionMatrix, 0, 1, -1, -1, 1, 3, 4);
}
public void addFrame(VideoFrame frame) {
if (frame != null) {
frames.add(frame);
}
}
}
GLRenderer works with simple openGL polygon, on which i draw all textures
public class TexturePlane {
private static final String LOG_TAG = "TexturePlane";
private final String vertexShaderCode = "" +
"uniform mat4 uMVPMatrix;" +
"attribute vec4 vPosition;" +
"attribute vec2 a_TexCoordinate;" +
"varying vec2 v_TexCoordinate;" +
"void main() {" +
" gl_Position = uMVPMatrix * vPosition;" +
" v_TexCoordinate = a_TexCoordinate;" +
"}";
private final String fragmentShaderCode = "" +
"precision mediump float;" +
"varying vec2 v_TexCoordinate;" +
"uniform sampler2D s_texture_y;" +
"uniform sampler2D s_texture_u;" +
"uniform sampler2D s_texture_v;" +
"void main() {" +
" float y = texture2D(s_texture_y, v_TexCoordinate).r;" +
" float u = texture2D(s_texture_u, v_TexCoordinate).r - 0.5;" +
" float v = texture2D(s_texture_v, v_TexCoordinate).r - 0.5;" +
" float r = y + 1.13983 * v;" +
" float g = y - 0.39465 * u - 0.58060 * v;" +
" float b = y + 2.03211 * u;" +
" gl_FragColor = vec4(r, g, b, 1.0);" +
"}";
private final FloatBuffer vertexBuffer;
private final FloatBuffer textureBuffer;
private final ShortBuffer drawListBuffer;
private final int mProgram;
private int mPositionHandle;
private int mMVPMatrixHandle;
// number of coordinates per vertex in this array
private static final int COORDS_PER_VERTEX = 3;
private static final int COORDS_PER_TEXTURE = 2;
private static float squareCoords[] = {
-1f, 1f, 0.0f,
-1f, -1f, 0.0f,
1f, -1f, 0.0f,
1f, 1f, 0.0f
};
private static float uvs[] = {
0.0f, 0.0f,
0.0f, 1.0f,
1.0f, 1.0f,
1.0f, 0.0f
};
private final short drawOrder[] = {0, 1, 2, 0, 2, 3}; // order to draw vertices
private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex
private int textureWidth = 640;
private int textureHeight = 480;
private int yTextureUniformHandle;
private int uTextureUniformHandle;
private int vTextureUniformHandle;
private int yTextureHandle;
private int uTextureHandle;
private int vTextureHandle;
private int mTextureCoordinateHandle;
public void setTextureWidth(int textureWidth) {
this.textureWidth = textureWidth;
}
public int getTextureWidth() {
return textureWidth;
}
public void setTextureHeight(int textureHeight) {
this.textureHeight = textureHeight;
}
public int getTextureHeight() {
return textureHeight;
}
/**
* Sets up the drawing object data for use in an OpenGL ES context.
*/
public TexturePlane() {
// initialize vertex byte buffer for shape coordinates
ByteBuffer bb = ByteBuffer.allocateDirect(squareCoords.length * 4);
bb.order(ByteOrder.nativeOrder());
vertexBuffer = bb.asFloatBuffer();
vertexBuffer.put(squareCoords);
vertexBuffer.position(0);
// initialize byte buffer for the draw list
ByteBuffer dlb = ByteBuffer.allocateDirect(drawOrder.length * 2);
dlb.order(ByteOrder.nativeOrder());
drawListBuffer = dlb.asShortBuffer();
drawListBuffer.put(drawOrder);
drawListBuffer.position(0);
// initialize byte buffer for the draw list
ByteBuffer tbb = ByteBuffer.allocateDirect(uvs.length * 4);
tbb.order(ByteOrder.nativeOrder());
textureBuffer = tbb.asFloatBuffer();
textureBuffer.put(uvs);
textureBuffer.position(0);
mProgram = GLES20.glCreateProgram(); // create empty OpenGL Program
compileShaders();
setupTextures();
}
public void setupTextures() {
yTextureHandle = setupTexture(null, textureWidth, textureHeight, 0);
uTextureHandle = setupTexture(null, textureWidth, textureHeight, 1);
vTextureHandle = setupTexture(null, textureWidth, textureHeight, 2);
}
public int setupTexture(ByteBuffer data, int width, int height, int index) {
final int[] textureHandle = new int[1];
GLES20.glGenTextures(1, textureHandle, 0);
if (textureHandle[0] != 0) {
// Bind to the texture in OpenGL
GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + index);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]);
updateTexture(data, width, height, index);
// Set filtering
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
// Set wrapping mode
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);
}
if (textureHandle[0] == 0) {
Log.e(LOG_TAG, "Error loading texture.");
}
return textureHandle[0];
}
public void updateTexture(byte[] data, int width, int height, int index) {
if (data == null) {
if (width == 0 || height == 0) {
width = textureWidth;
height = textureHeight;
}
data = new byte[width * height];
if (index == 0) {
Arrays.fill(data, y);
} else if (index == 1) {
Arrays.fill(data, u);
} else {
Arrays.fill(data, v);
}
}
byteBuffer.wrap(data);
byteBuffer.position(0);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + index);
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE,
width, height, 0, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, byteBuffer);
}
private void compileShaders() {
// prepare shaders and OpenGL program
int vertexShader = loadShader(
GLES20.GL_VERTEX_SHADER,
vertexShaderCode);
int fragmentShader = loadShader(
GLES20.GL_FRAGMENT_SHADER,
fragmentShaderCode);
GLES20.glAttachShader(mProgram, vertexShader); // add the vertex shader to program
GLES20.glAttachShader(mProgram, fragmentShader); // add the fragment shader to program
GLES20.glLinkProgram(mProgram); // create OpenGL program executables
checkGlError("glLinkProgram");
// Add program to OpenGL environment
GLES20.glUseProgram(mProgram);
mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
mTextureCoordinateHandle = GLES20.glGetAttribLocation(mProgram, "a_TexCoordinate");
GLES20.glEnableVertexAttribArray(mPositionHandle);
GLES20.glEnableVertexAttribArray(mTextureCoordinateHandle);
yTextureUniformHandle = GLES20.glGetUniformLocation(mProgram, "s_texture_y");
uTextureUniformHandle = GLES20.glGetUniformLocation(mProgram, "s_Texture_u");
vTextureUniformHandle = GLES20.glGetUniformLocation(mProgram, "s_Texture_v");
mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
checkGlError("glGetUniformLocation");
}
/**
* Utility method for compiling a OpenGL shader.
* <p/>
* <p><strong>Note:</strong> When developing shaders, use the checkGlError()
* method to debug shader coding errors.</p>
*
* #param type - Vertex or fragment shader type.
* #param shaderCode - String containing the shader code.
* #return - Returns an id for the shader.
*/
public int loadShader(int type, String shaderCode) {
// create a vertex shader type (GLES20.GL_VERTEX_SHADER)
// or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)
int shader = GLES20.glCreateShader(type);
// add the source code to the shader and compile it
GLES20.glShaderSource(shader, shaderCode);
GLES20.glCompileShader(shader);
return shader;
}
/**
* Utility method for debugging OpenGL calls. Provide the name of the call
* just after making it:
* <p/>
* <pre>
* mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
* MyGLRenderer.checkGlError("glGetUniformLocation");</pre>
*
* If the operation is not successful, the check throws an error.
*
* #param glOperation - Name of the OpenGL call to check.
*/
public void checkGlError(String glOperation) {
int error;
String errorString;
while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
errorString = GLU.gluErrorString(error);
String message = glOperation + ": glError " + error + ": " + errorString;
Log.e(LOG_TAG, message);
throw new RuntimeException(message);
}
}
public void draw(float[] mvpMatrix) {
// Prepare the triangle coordinate data
GLES20.glVertexAttribPointer(
mPositionHandle, COORDS_PER_VERTEX,
GLES20.GL_FLOAT, false,
vertexStride, vertexBuffer);
GLES20.glVertexAttribPointer(
mTextureCoordinateHandle, COORDS_PER_TEXTURE,
GLES20.GL_FLOAT, false,
0, textureBuffer);
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
checkGlError("glUniformMatrix4fv");
GLES20.glUniform1i(yTextureUniformHandle, 0);
GLES20.glUniform1i(uTextureUniformHandle, 1);
GLES20.glUniform1i(vTextureUniformHandle, 2);
// Draw the square
GLES20.glDrawElements(
GLES20.GL_TRIANGLES, drawOrder.length,
GLES20.GL_UNSIGNED_SHORT, drawListBuffer);
}
}
But i have a problem there. My GL surface display image with wrong colors. image
What i'm doing wrong?
UPDATE:
As Ronald S. Bultje say, i added glBindTexture(...) function in my code. And now updateTexture(...) method looks like this:
public void updateTexture(byte[] data, int width, int height, int index) {
if (data == null) {
if (width == 0 || height == 0) {
width = textureWidth;
height = textureHeight;
}
data = new byte[width * height];
if (index == 0) {
Arrays.fill(data, y);
} else if (index == 1) {
Arrays.fill(data, u);
} else {
Arrays.fill(data, v);
}
}
byteBuffer.wrap(data);
byteBuffer.position(0);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + index);
int textureHandle = index == 0 ? yTextureHandle : index == 1 ? uTextureHandle : vTextureHandle;
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle);
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE,
width, height, 0, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, byteBuffer);
}
Your updateTexture() function doesn't call GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[index]); after calling GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + index);
[edit] actually given your code, it would be index==0?yTextureHandle:index==1?uTextureHandle?vTextureHandle, I'm sure you can figure out how to refactor your code to make this easier.
I wrote a game in Java and I want to put it on a HTML page. I know how, but the problem is that it gives me a AcessControlException (java.io.FilePermission "/SomePath/SomeFile.SomeExtension" "read").
Here is the Game class (loads the files at initGame method and init the JApplet):
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.swing.JApplet;
public class Game extends JApplet implements Runnable {
private static final long serialVersionUID = 1L;
private Thread thread;
public static BufferedImage level;
public static BufferedImage background;
public static Image2d tileset;
public static Sprite red;
public static Sprite green;
public static Sprite player;
public static boolean mouse_left, mouse_right;
public static boolean jumping;
public static boolean play;
private boolean running = false;
private Image screen;
public static RandomLevel map;
public static Listener listener;
public static Gui gui;
public static int FALL_SPEED = 3;
public static int JUMP_SPEED = 3;
public static int JUMP_HEIGHT = 20;
public static int jump_amount = 0;
public static float START_OFFSET_SPEED = 3.0f;
public static float OFFSET_SPEED = 2.0f;
public static final int sxOffset = 0, syOffset = 0;
public static int xOffset = 0, yOffset = 0;
public static final int CURR_COLOR_SCALE = 32;
public static Sprite[] tiles = new Sprite[2];
public static int selected_color = 0;
public static int SCORE = 0;
public static final int TILE_SIZE = 16;
public static final int SCALE = TILE_SIZE * 2;
public static boolean left, right;
public static int currTime = 0;
public static final Dimension size = new Dimension(800, 600);
public static final Dimension pixel = new Dimension(size.width - SCALE, size.height - SCALE);
public void initGame() {
try {
URL levelUrl = new URL(getCodeBase(), "res/map.png");
level = new Image2d(levelUrl).getImage();
URL backgroundUrl = new URL(getCodeBase(), "res/background.png");
background = new Image2d(backgroundUrl).getImage();
URL tilesetUrl = new URL(getCodeBase(), "res/tileset.png");
tileset = new Image2d(tilesetUrl);
} catch (IOException e) {
}
red = new Sprite(new Image2d(tileset.crop(0, 0, Game.TILE_SIZE, Game.TILE_SIZE)));
green = new Sprite(new Image2d(tileset.crop(1, 0, Game.TILE_SIZE, Game.TILE_SIZE)));
player = new Sprite(new Image2d(tileset.crop(2, 0, Game.TILE_SIZE, Game.TILE_SIZE)));
tiles[0] = red;
tiles[1] = green;
gui = new Gui();
listener = new Listener();
player.setX((size.width - player.getImage().getWidth(null)) / 2);
player.setY((size.height - player.getImage().getHeight(null)) / 2 + 100);
map = new RandomLevel(10000, 20, TILE_SIZE, SCALE, size, xOffset, yOffset);
map.addCollsion(tiles[0]);
addMouseListener(listener);
addMouseMotionListener(new Mouse());
}
public static void switchCollision(Sprite tile) {
map.collision.add(0, tile);
for (int i = 0; i < map.collision.size(); i++) {
if (i != 0)
map.collision.remove(i);
}
}
public void resetGame() {
xOffset = sxOffset;
yOffset = syOffset;
OFFSET_SPEED = START_OFFSET_SPEED;
Game.SCORE = 0;
play = false;
map.generateLevel();
}
public void startGame() {
if (running)
return;
initGame();
running = true;
thread = new Thread(this);
thread.start();
}
public void stopGame() {
if (!running)
return;
running = true;
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void run() {
screen = createVolatileImage(pixel.width, pixel.height);
requestFocus();
while (running) {
long lastTime = System.nanoTime();
long timer = System.currentTimeMillis();
final double ns = 1000000000.0 / 60.0;
double delta = 0;
while (running) {
long now = System.nanoTime();
delta += (now - lastTime) / ns;
lastTime = now;
while (delta >= 1) {
update();
delta--;
}
render();
if (System.currentTimeMillis() - timer > 100) {
timer += 1000;
}
}
stop();
}
}
public void update() {
if (!play && mouse_left)
play = true;
if (play) {
switchCollision(tiles[selected_color]);
if (yOffset > 180)
resetGame();
map.update();
map.setxOffset(xOffset);
map.setyOffset(yOffset);
player.update(25);
gui.update();
if (!map.getTileDownCollision(player))
yOffset += FALL_SPEED;
if (!Game.map.getTileRightCollision(player))
xOffset += Math.round(OFFSET_SPEED);
if (SCORE > 20)
OFFSET_SPEED = 4.0f;
if (SCORE > 40)
OFFSET_SPEED = 5.0f;
if (SCORE > 60)
OFFSET_SPEED = 6.0f;
if (SCORE > 80)
OFFSET_SPEED = 7.0f;
if (SCORE > 100)
OFFSET_SPEED = 8.0f;
if (SCORE > 120)
OFFSET_SPEED = 9.0f;
if (SCORE > 140)
OFFSET_SPEED = 10.0f;
if (jumping) {
FALL_SPEED = 0;
yOffset -= JUMP_SPEED;
jump_amount++;
if (jump_amount >= JUMP_HEIGHT) {
jumping = false;
FALL_SPEED = 3;
jump_amount = 0;
}
}
}
}
public void render() {
Graphics g = screen.getGraphics();
g.setColor(Color.black);
g.fillRect(0, 0, size.width, size.height);
map.render(g);
g.drawImage(player.getImage(), Math.round(player.getX()), Math.round(player.getY()), Game.TILE_SIZE + Game.SCALE, Game.TILE_SIZE + Game.SCALE, null);
g.setFont(new Font("new Font", Font.PLAIN, 10));
g.setColor(Color.white);
g.drawString("CLICK ON THIS SIDE TO JUMP", 200 - xOffset, 240);
g.drawString("CLICK ON THIS SIDE TO SWITCH COLOR", size.width - 350 - xOffset, 240);
g.drawImage(background, 0, 0, null);
g.drawImage(map.collision.get(0).getImage(), (size.width - (Game.TILE_SIZE + CURR_COLOR_SCALE)) / 2, CURR_COLOR_SCALE / 2 - 5, Game.TILE_SIZE + CURR_COLOR_SCALE, Game.TILE_SIZE + CURR_COLOR_SCALE, null);
gui.render(g);
g.setFont(new Font("new Font", Font.BOLD, 32));
g.setColor(Color.yellow);
g.drawString("SCORE: " + SCORE, 10, 32);
g = getGraphics();
g.drawImage(screen, 0, 0, size.width, size.height, 0, 0, pixel.width, pixel.height, null);
g.dispose();
}
public void destroy() {
System.exit(0);
}
public void init() {
setSize(size);
setVisible(true);
startGame();
}
}
EDIT: Here is the Image2d class(holds ImageIO.read command)
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
public class Image2d{
private BufferedImage image;
public Image2d(URL url) {
try {
image = ImageIO.read(url);
} catch (IOException e) {
System.err.println("No file found at: " + url);
}
}
public Image2d(String path) {
try {
image = ImageIO.read(new File(path));
} catch (IOException e) {
System.err.println("No file found at: " + path);
}
}
public static BufferedImage load(URL url) {
try {
return ImageIO.read(url);
} catch (IOException e) {
System.err.println("No file found at: " + url.getPath());
return null;
}
}
public static BufferedImage load(String path) {
try {
return ImageIO.read(new File(path));
} catch (IOException e) {
System.err.println("No file found at: " + path);
return null;
}
}
public Image2d(BufferedImage image) {
this.image = image;
}
public BufferedImage crop(int x, int y, int w, int h) {
return image.getSubimage(x * w, y * h, w, h);
}
public static BufferedImage insert(Image2d target, Image2d component) {
BufferedImage tile = new BufferedImage(target.getImage().getWidth(), target.getImage().getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics g = tile.getGraphics();
g.drawImage(component.getImage(), 0, 0, component.getImage().getWidth(), component.getImage().getHeight(), null);
g.drawImage(target.getImage(), 0, 0, target.getImage().getWidth(), target.getImage().getHeight(), null);
return tile;
}
public static BufferedImage switchColor(BufferedImage image, Color color1, Color color2) {
Graphics g = image.getGraphics();
for (int y = 0; y < image.getHeight(); y++) {
for (int x = 0; x < image.getWidth(); x++) {
Color color = new Color(image.getRGB(x, y));
if (color.getRed() == color1.getRed() && color.getGreen() == color1.getGreen() && color.getBlue() == color1.getBlue() && color.getAlpha() == color1.getAlpha()) {
g.setColor(color2);
g.fillRect(x, y, 1, 1);
}
}
}
return image;
}
public static BufferedImage fill(Color color, int width, int height) {
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics g = image.getGraphics();
g.setColor(color);
g.fillRect(0, 0, width, height);
return image;
}
public static BufferedImage switchColor(BufferedImage image, Color[] color1, Color[] color2) {
Graphics g = image.getGraphics();
for (int y = 0; y < image.getHeight(); y++) {
for (int x = 0; x < image.getWidth(); x++) {
Color color = new Color(image.getRGB(x, y));
for (int i = 0; i < color1.length; i++)
if (color.getRed() == color1[i].getRed() && color.getGreen() == color1[i].getGreen() && color.getBlue() == color1[i].getBlue() && color.getAlpha() == color1[i].getAlpha()) {
g.setColor(color2[i]);
g.fillRect(x, y, 1, 1);
}
}
}
return image;
}
public static BufferedImage createYDropShadow(int width, int height, int startAlpha, float density, float offset, Color color) {
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics g = image.getGraphics();
int alpha = startAlpha;
for (int y = 0; y < image.getHeight(); y++) {
if (alpha >= density)
alpha -= density;
for (int x = 0; x < image.getWidth(); x++) {
g.setColor(new Color(color.getRed(), color.getGreen(), color.getBlue(), alpha));
g.fillRect(x + Math.round(offset), y + Math.round(offset), 1 + Math.round(offset), 1 + Math.round(offset));
}
}
return image;
}
public static BufferedImage createXDropShadow(int width, int height, int startAlpha, float density, float offset, Color color) {
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics g = image.getGraphics();
int alpha = startAlpha;
for (int x = 0; x < image.getWidth(); x++) {
if (alpha >= density)
alpha -= density;
for (int y = 0; y < image.getHeight(); y++) {
g.setColor(new Color(color.getRed(), color.getGreen(), color.getBlue(), alpha));
g.fillRect(x + Math.round(offset), y + Math.round(offset), 1 + Math.round(offset), 1 + Math.round(offset));
}
}
return image;
}
public BufferedImage getImage() {
return image;
}
}
And here is html code (it is inside a jar file called Blocks.jar):
<!DOCTYPE html>
<html>
<body>
<applet code="Game.class" archive="Blocks.jar" width="600" height="600"> </applet>
</body>
</html>
I saw people getting the same error but, no answer gave me a solution that worked. So what shoud I do for load the images without erros?
PS: The JApplet is running fine in eclipse, but at the html page throws me this error.
Thanks!
I'm trying to create a shadow effect (with java) on an image.
I've seen multiple related questions and I've implemented several of the suggested solutions. Unfortunately I always have the same problem: the shadow effect repaints the entire image in gray (i.e. the shadow color) - hence the original image is not visible anymore.
Example of code I tested (based on the JIDE freely available library):
ShadowFactory sf = new ShadowFactory(2, 0.5f, Color.black);
ImageIO.write(sf.createShadow(ImageIO.read(new File("c:\\out2.png"))), "png", new File("c:\\out3.png"));
No need to says that I tested this with multiple source files (out2.png).
I'm clueless: any hint/help would be highly appreciated.
The over all theory is simple. Basically, you need to generate a mask of the image (using a AlphaComposite and fill that resulting image with the color you want (also using an AlphaComposite. This, of course, all works on the alpha channel of the image...
Once you have that mask, you need to combine the two images (overlaying the original image with the masked image)
This examples make use of JHLabs filters to supply the blur...
public class TestImageDropShadow {
public static void main(String[] args) {
new TestImageDropShadow();
}
public TestImageDropShadow() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new ImagePane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class ImagePane extends JPanel {
private BufferedImage background;
public ImagePane() {
try {
BufferedImage master = ImageIO.read(getClass().getResource("/Scaled.png"));
background = applyShadow(master, 5, Color.BLACK, 0.5f);
} catch (IOException ex) {
Logger.getLogger(TestImageDropShadow.class.getName()).log(Level.SEVERE, null, ex);
}
}
#Override
public Dimension getPreferredSize() {
return background == null ? super.getPreferredSize() : new Dimension(background.getWidth(), background.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (background != null) {
int x = (getWidth() - background.getWidth()) / 2;
int y = (getHeight() - background.getHeight()) / 2;
g.drawImage(background, x, y, this);
}
}
}
public static void applyQualityRenderingHints(Graphics2D g2d) {
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
}
public static BufferedImage createCompatibleImage(int width, int height) {
return createCompatibleImage(width, height, Transparency.TRANSLUCENT);
}
public static BufferedImage createCompatibleImage(int width, int height, int transparency) {
BufferedImage image = getGraphicsConfiguration().createCompatibleImage(width, height, transparency);
image.coerceData(true);
return image;
}
public static BufferedImage createCompatibleImage(BufferedImage image) {
return createCompatibleImage(image, image.getWidth(), image.getHeight());
}
public static BufferedImage createCompatibleImage(BufferedImage image,
int width, int height) {
return getGraphicsConfiguration().createCompatibleImage(width, height, image.getTransparency());
}
public static GraphicsConfiguration getGraphicsConfiguration() {
return GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
}
public static BufferedImage generateMask(BufferedImage imgSource, Color color, float alpha) {
int imgWidth = imgSource.getWidth();
int imgHeight = imgSource.getHeight();
BufferedImage imgBlur = createCompatibleImage(imgWidth, imgHeight);
Graphics2D g2 = imgBlur.createGraphics();
applyQualityRenderingHints(g2);
g2.drawImage(imgSource, 0, 0, null);
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_IN, alpha));
g2.setColor(color);
g2.fillRect(0, 0, imgSource.getWidth(), imgSource.getHeight());
g2.dispose();
return imgBlur;
}
public static BufferedImage generateBlur(BufferedImage imgSource, int size, Color color, float alpha) {
GaussianFilter filter = new GaussianFilter(size);
int imgWidth = imgSource.getWidth();
int imgHeight = imgSource.getHeight();
BufferedImage imgBlur = createCompatibleImage(imgWidth, imgHeight);
Graphics2D g2 = imgBlur.createGraphics();
applyQualityRenderingHints(g2);
g2.drawImage(imgSource, 0, 0, null);
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_IN, alpha));
g2.setColor(color);
g2.fillRect(0, 0, imgSource.getWidth(), imgSource.getHeight());
g2.dispose();
imgBlur = filter.filter(imgBlur, null);
return imgBlur;
}
public static BufferedImage applyShadow(BufferedImage imgSource, int size, Color color, float alpha) {
BufferedImage result = createCompatibleImage(imgSource, imgSource.getWidth() + (size * 2), imgSource.getHeight() + (size * 2));
Graphics2D g2d = result.createGraphics();
g2d.drawImage(generateShadow(imgSource, size, color, alpha), size, size, null);
g2d.drawImage(imgSource, 0, 0, null);
g2d.dispose();
return result;
}
public static BufferedImage generateShadow(BufferedImage imgSource, int size, Color color, float alpha) {
int imgWidth = imgSource.getWidth() + (size * 2);
int imgHeight = imgSource.getHeight() + (size * 2);
BufferedImage imgMask = createCompatibleImage(imgWidth, imgHeight);
Graphics2D g2 = imgMask.createGraphics();
applyQualityRenderingHints(g2);
int x = Math.round((imgWidth - imgSource.getWidth()) / 2f);
int y = Math.round((imgHeight - imgSource.getHeight()) / 2f);
g2.drawImage(imgSource, x, y, null);
g2.dispose();
// ---- Blur here ---
BufferedImage imgGlow = generateBlur(imgMask, (size * 2), color, alpha);
return imgGlow;
}
public static Image applyMask(BufferedImage sourceImage, BufferedImage maskImage) {
return applyMask(sourceImage, maskImage, AlphaComposite.DST_IN);
}
public static BufferedImage applyMask(BufferedImage sourceImage, BufferedImage maskImage, int method) {
BufferedImage maskedImage = null;
if (sourceImage != null) {
int width = maskImage.getWidth(null);
int height = maskImage.getHeight(null);
maskedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D mg = maskedImage.createGraphics();
int x = (width - sourceImage.getWidth(null)) / 2;
int y = (height - sourceImage.getHeight(null)) / 2;
mg.drawImage(sourceImage, x, y, null);
mg.setComposite(AlphaComposite.getInstance(method));
mg.drawImage(maskImage, 0, 0, null);
mg.dispose();
}
return maskedImage;
}
}
This is my Version:
private static Image dropShadow(BufferedImage img) {
// a filter which converts all colors except 0 to black
ImageProducer prod = new FilteredImageSource(img.getSource(), new RGBImageFilter() {
#Override
public int filterRGB(int x, int y, int rgb) {
if (rgb == 0)
return 0;
else
return 0xff000000;
}
});
// create whe black image
Image shadow = Toolkit.getDefaultToolkit().createImage(prod);
// result
BufferedImage result = new BufferedImage(img.getWidth(), img.getHeight(), img.getType());
Graphics2D g = (Graphics2D) result.getGraphics();
// draw shadow with offset
g.drawImage(shadow, 10, 0, null);
// draw original image
g.drawImage(img, 0, 0, null);
return result;
}