Search code examples
javalibgdx

How to draw pixelized shapes (LIBGDX conceptional)


I would like to daw shapes in a pixelized style. My cirlce currently drawn with shaperenderer renders in real pixels.

enter image description here

but i like it to be more pixelized.

enter image description here

I played around with camera and viewport to get the effect, but not succeeded. I prefer to use FillViewport.

Do we need create our own drawLine funtion and draw small squares along a line? Or can this be done with Viewports whith keeping the aspect ratio?

Is there any small sample project that shows how to create simple shapes that are pixelized.

I know I can code myself, but I would like to avoid when using a framework.

In skretch you can draw a line an just specify the pixelsize, so easy.

Any hints?

public class SimpleCirleActor extends Actor {
        ShapeRenderer renderer;
        float radius;
        public SimpleCirleActor(int x , int y, float radius) {
            setBounds(0,0, Constants.pixelsPerSector(),Constants.pixelsPerSector());
            this.radius = radius;
            setX(x);setY(y);
            renderer = new ShapeRenderer();
        }

        @Override
        public void draw(Batch batch, float parentAlpha) {
            super.draw(batch, parentAlpha);
            renderer.setProjectionMatrix(getStage().getCamera().combined);
            renderer.begin(ShapeRenderer.ShapeType.Line);
            renderer.setColor(Color.CYAN);
            float x = getX();
            renderer.circle(x, getY(), radius);
            renderer.end();
        }

    @Override
    public void act(float delta) {
        super.act(delta);
    }

}

Solution

  • ok, got bored. Here you go.

    enter image description here

    Notes:

    Green box is just to show where the framebuffer texture is being drawn to, just change the fill colour to zero alpha after the fbo.begin() statement to make it clear.

    BINDING_DEPTH_FRAMEBUFFER,BINDING_DEFAULT variables are from my code. You probably won't need to worry about these unless you mess around with switching textures and using bespoke shaders.

    Drawing the fbo, batch.draw(fbo.getColorBufferTexture(), 20, 20, 200, 200, 0, 0, 1, 1); Hopefully this will be ok for you. If you want to rotate the fbo you should just be able to create a rotated projection matrix from your camera. If you want to use a bespoke shader, you just have to be careful about linking the fbo as a texture to the shader.

    package com.funferret.pixelshapes;
    
    import com.badlogic.gdx.ApplicationAdapter;
    import com.badlogic.gdx.Gdx;
    import com.badlogic.gdx.graphics.GL20;
    import com.badlogic.gdx.graphics.OrthographicCamera;
    import com.badlogic.gdx.graphics.Pixmap;
    import com.badlogic.gdx.graphics.Texture;
    import com.badlogic.gdx.graphics.g2d.SpriteBatch;
    import com.badlogic.gdx.graphics.glutils.FrameBuffer;
    import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
    import com.badlogic.gdx.utils.ScreenUtils;
    
    public class MyGdxGame extends ApplicationAdapter {
        ShapeRenderer shapeBatch;
        SpriteBatch batch;
        Texture img;
        FrameBuffer fbo;
        public OrthographicCamera fboCamera;
    
        int fboWidth=40;
        int fboHeight=40;
        int BINDING_DEPTH_FRAMEBUFFER=3;
        int BINDING_DEFAULT=0;
    
        void createFrameBuffer()
        {
            if (fbo!=null)
            {
                fbo.dispose();
            }
            fbo = new FrameBuffer(Pixmap.Format.RGBA8888, fboWidth, fboHeight, false);
            fbo.getColorBufferTexture().setFilter(Texture.TextureFilter.Nearest, Texture.TextureFilter.Nearest);
            fbo.getColorBufferTexture().bind(BINDING_DEPTH_FRAMEBUFFER);
            Gdx.graphics.getGL20().glActiveTexture(GL20.GL_TEXTURE0 + BINDING_DEFAULT); //make sure this is set to 0 for batch draws
            fboCamera=new OrthographicCamera();
            fboCamera.setToOrtho(false, fboWidth, fboHeight);
            fboCamera.update();
        }
    
        @Override
        public void create () {
            batch = new SpriteBatch();
            shapeBatch=new ShapeRenderer();
            img = new Texture("badlogic.jpg");
        }
    
        @Override
        public void render ()
        {
        //I had some initialisation problems with the fbo when trying to create a framebuffer. Need to be absolutely certain
            //size is correct and opengl context is set up before creating the framebuffer (as far as I remember). This if statement and the
            //createFrameBuffer function works for me and will allow you to change the size of fboWidth/fboHeight on the fly (though will cause stutters if you do)
            if ((fbo==null) || (fbo.getWidth()!=fboWidth) || (fbo.getHeight()!=fboHeight))
            {
                createFrameBuffer();
            }
    
            //start drawing to a small framebuffer, that we will then scale up to create a pixelated effect
            fbo.begin();
            ScreenUtils.clear(0, 1, 0, 0.5f);
            shapeBatch.begin(ShapeRenderer.ShapeType.Line);
            shapeBatch.setProjectionMatrix(fboCamera.combined);
            Gdx.gl.glDisable(GL20.GL_BLEND);
            shapeBatch.setColor(1f, 0f, 1f, 1);
            shapeBatch.circle(20,20,15,10);
            shapeBatch.end();
            fbo.end();
    
    
            ScreenUtils.clear(1, 0, 0, 1);
            batch.begin();
            batch.draw(img, 0, 0);
            batch.draw(fbo.getColorBufferTexture(), 20, 20, 200, 200, 0, 0, 1, 1);
            batch.end();
        }
        
        @Override
        public void dispose () {
            batch.dispose();
            img.dispose();
            shapeBatch.dispose();
            fbo.dispose();
        }
    }