Search code examples
javaopenglrenderingslick2d

Rendering and Cropping/Stretching an Image Using Slick/OpenGL (using getSubImage)


I'm trying to recreate a shadow effect on some 2D sprites in a project using Slick. To do this, I'm recolouring a copy of the sprite and stretching it using Slick OpenGL using this method:

public static void getStretched(Shape shape, Image image) {

    TextureImpl.bindNone();
    image.getTexture().bind();

    SGL GL = Renderer.get();

    GL.glEnable(SGL.GL_TEXTURE_2D);
    GL.glBegin(SGL.GL_QUADS);

    //topleft
    GL.glTexCoord2f(0f, 0f);
    GL.glVertex2f(shape.getPoints()[0], shape.getPoints()[1]);

    //topright
    GL.glTexCoord2f(0.5f, 0f);
    GL.glVertex2f(shape.getPoints()[2], shape.getPoints()[3]);

    //bottom right
    GL.glTexCoord2f(1f, 1f);
    GL.glVertex2f(shape.getPoints()[4], shape.getPoints()[5]);

    //btoom left
    GL.glTexCoord2f(0.5f, 1f);
    GL.glVertex2f(shape.getPoints()[6], shape.getPoints()[7]);

    GL.glEnd();
    GL.glDisable(SGL.GL_TEXTURE_2D);
    TextureImpl.bindNone();
}

This gives the almost the desired effect, aside from the fact that the image is cropped a bit.

This becomes more extreme for higher distortions

I'm new to using OpenGL, so some help regarding how to fix this would be great. Furthermore, if I feed an image into the method that was obtained using getSubImage, OpenGL renders the original image, rather than the sub image.

I'm unsure as to why this happens, as the sprite itself is taken from a spritesheet using getSubImage and has no problem rendering. Help would be greatly appreciated!


Solution

  • I'm recolouring a copy of the sprite and stretching it

    The issue is that you stretch the texture coordinates, but the region which is covered by the sprite stays the same. If the shadow exceeds the the region which is covered by the quad primitive, then it is cropped.
    You have to "stretch" the vertex coordinates rather than the texture coordinates. Define a rhombic geometry for the shadow and wrap the texture on it:

    float distortionX = ...;
    
    GL.glEnable(SGL.GL_TEXTURE_2D);
    GL.glBegin(SGL.GL_QUADS);
    
    //topleft
    GL.glTexCoord2f(0f, 0f);
    GL.glVertex2f(shape.getPoints()[0] + distortionX, shape.getPoints()[1]);
    
    //topright
    GL.glTexCoord2f(1f, 0f);
    GL.glVertex2f(shape.getPoints()[2] + distortionX, shape.getPoints()[3]);
    
    //bottom right
    GL.glTexCoord2f(1f, 1f);
    GL.glVertex2f(shape.getPoints()[4], shape.getPoints()[5]);
    
    //btoom left
    GL.glTexCoord2f(0f, 1f);
    GL.glVertex2f(shape.getPoints()[6], shape.getPoints()[7]);
    
    GL.glEnd();
    

    [...] if I feed an image into the method that was obtained using getSubImage, [...] the sprite itself is taken from a spritesheet [...]

    The sprite is covers just a small rectangular region of the entire texture. This region is defined by the texture coordinates. You have to use the same texture coordinates as when you draw the sprite itself.