Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 8721921
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 13, 20262026-06-13T07:18:05+00:00 2026-06-13T07:18:05+00:00

Backstory: I’m trying to draw as many squares the the screen as possible using

  • 0

Backstory:
I’m trying to draw as many squares the the screen as possible using a single draw call. I’m using a custom glsl vertex shader that is specialized for 2D drawing, and that is supposed to be pulling position data for the vertices of the squares from a samplerBuffer. Since I don’t need to worry about rotating or scaling the squares all I should need to do is load the position data into a buffer, bind a texture to that buffer, and then use the sampler to get each vertex’s position in the shader. In order to get an index into the texture I store each elements index as the z-component of the vertices.

Everything seems to work really well for a thousand or so squares, but after that I start to get weird blinking. It sort of seems like it’s not drawing all of the squares every draw step, or possibly not using all of the positions so that many of the squares are overlapping.

The weird thing is, that if I use drawElements instead of drawElementsMulti, the blinking goes away (but of course then all the squares are drawn as one single object, which I don’t want)

One question I have is if my position data is limited to the max texture size, or the max texture buffer size. And if I am limited to the much smaller max texture size, how do I get around it? There’s got to be a reason all of that texture buffer space is there, but I obviously don’t get how to properly use it.

I’m also thinking maybe glMultiDrawElements is doing something I’m not accounting for with the sampler somehow. Idk, I’m really lost at this point, and yet..it works perfectly for smaller numbers of squares, so I must be doing something right.

[EDIT] Code had changed to reflect suggestions below (and for readability), but the problem persists.

Ok, so here’s some code. First the vertex shader:

uniform mat3 projection;
attribute vec3 vertex;

uniform samplerBuffer positionSampler;

attribute vec4 vertex_color;
varying vec4 color;

float positionFetch(int index)
{
    // I've tried texelFetch here as well, same effect
    float value = texelFetchBuffer(positionSampler, index).r;
    return value;
}

void main(void)  
{ 
    color = vec4(1, 1, 1, 1);
    // use the z-component of the vertex to look up the position of this instance in the texture
    vec3 real_position = vec3(vertex.x + positionFetch(int(vertex.z)*2), vertex.y + positionFetch(int(vertex.z)*2+1), 1); 
    gl_Position = vec4(projection * real_position, 1); 
}

And now my GLRenderer, sorry there is so much code, I just really want to make sure there’s enough info here to get an answer. This has really been driving me nuts, and examples for java seem to be hard to come by (maybe this code will help someone else on their quest):

public class GLRenderer extends GLCanvas implements GLEventListener, WindowListener
{

    private static final long serialVersionUID = -8513201172428486833L;

    private static final int bytesPerFloat = Float.SIZE / Byte.SIZE;
    private static final int bytesPerShort = Short.SIZE / Byte.SIZE;

    public float viewWidth, viewHeight;
    public float screenWidth, screenHeight;

    private FPSAnimator animator;

    private boolean didInit = false;

    JFrame the_frame;
    SquareGeometry geometry;

    // Thought power of 2 might be required, doesn't seem to make a difference
    private static final int NUM_THINGS = 2*2*2*2*2*2*2*2*2*2*2*2*2*2; 

    float[] position = new float[NUM_THINGS*2];

    // Shader attributes
    private int shaderProgram, projectionAttribute, vertexAttribute, positionAttribute;

    public static void main(String[] args) 
    {
        new GLRenderer();
    }

    public GLRenderer()
    {
        // setup OpenGL Version 2
        super(new GLCapabilities(GLProfile.get(GLProfile.GL2)));

        addGLEventListener(this);
        setSize(1800, 1000);

        the_frame = new JFrame("Hello World");
        the_frame.getContentPane().add(this);
        the_frame.setSize(the_frame.getContentPane().getPreferredSize());
        the_frame.setVisible(true);
        the_frame.addWindowListener(this);

        animator = new FPSAnimator(this, 60);
        animator.start();
    }

    // Called by the drivers when the gl context is first made available
    public void init(GLAutoDrawable d)
    {        
        final GL2 gl = d.getGL().getGL2();
        IntBuffer asd = IntBuffer.allocate(1);
        gl.glGetIntegerv(GL2.GL_MAX_TEXTURE_BUFFER_SIZE, asd);
        System.out.println(asd.get(0));
        asd = IntBuffer.allocate(1);
        gl.glGetIntegerv(GL2.GL_MAX_TEXTURE_SIZE, asd);
        System.out.println(asd.get(0));
        shaderProgram = ShaderLoader.compileProgram(gl, "default");
        gl.glLinkProgram(shaderProgram);

        _getShaderAttributes(gl);

        gl.glUseProgram(shaderProgram);
        _checkGLCapabilities(gl);
        _initGLSettings(gl);

        // Calculate batch of vertex data from dirt geometry
        geometry = new SquareGeometry(.1f);
        geometry.buildGeometry(viewWidth, viewHeight);
        geometry.finalizeGeometry(NUM_THINGS);

        geometry.vertexBufferID = _generateBufferID(gl);
        _loadVertexBuffer(gl, geometry);

        geometry.indexBufferID = _generateBufferID(gl);
        _loadIndexBuffer(gl, geometry);

        geometry.positionBufferID = _generateBufferID(gl);

        // initialize buffer object
        int size = NUM_THINGS * 2 * bytesPerFloat;
        System.out.println(size);

    IntBuffer bla = IntBuffer.allocate(1);
    gl.glGenTextures(1, bla);
    geometry.positionTextureID = bla.get(0);

        gl.glUniform1i(positionAttribute, 0);

        gl.glActiveTexture(GL2.GL_TEXTURE0);
        gl.glBindTexture(GL2.GL_TEXTURE_BUFFER, geometry.positionTextureID);
        gl.glBindBuffer(GL2.GL_TEXTURE_BUFFER, geometry.positionBufferID);
        gl.glBufferData(GL2.GL_TEXTURE_BUFFER, size, null, GL2.GL_DYNAMIC_DRAW);
        gl.glTexBuffer(GL2.GL_TEXTURE_BUFFER, GL2.GL_R32F, geometry.positionBufferID);
    }

    private void _initGLSettings(GL2 gl)
    {
        gl.glClearColor(0f, 0f, 0f, 1f);
    }

    private void _loadIndexBuffer(GL2 gl, SquareGeometry geometry)
    {
        gl.glBindBuffer(GL2.GL_ELEMENT_ARRAY_BUFFER, geometry.indexBufferID);
        gl.glBufferData(GL2.GL_ELEMENT_ARRAY_BUFFER, bytesPerShort*NUM_THINGS*geometry.getNumPoints(), geometry.indexBuffer, GL2.GL_STATIC_DRAW);
    }

    private void _loadVertexBuffer(GL2 gl, SquareGeometry geometry)
    {
        int numBytes = geometry.getNumPoints() * 3 * bytesPerFloat * NUM_THINGS;

        gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, geometry.vertexBufferID);
        gl.glBufferData(GL2.GL_ARRAY_BUFFER, numBytes, geometry.vertexBuffer, GL2.GL_STATIC_DRAW);
        gl.glEnableVertexAttribArray(vertexAttribute);
        gl.glVertexAttribPointer(vertexAttribute, 3, GL2.GL_FLOAT, false, 0, 0);
    }

    private int _generateBufferID(GL2 gl)
    {
        IntBuffer bufferIDBuffer = IntBuffer.allocate(1);
        gl.glGenBuffers(1, bufferIDBuffer);

        return bufferIDBuffer.get(0);
    }

    private void _checkGLCapabilities(GL2 gl)
    {
        // TODO: Respond to this information in a meaningful way.
        boolean VBOsupported = gl.isFunctionAvailable("glGenBuffersARB") && gl.isFunctionAvailable("glBindBufferARB")
                && gl.isFunctionAvailable("glBufferDataARB") && gl.isFunctionAvailable("glDeleteBuffersARB");

        System.out.println("VBO Supported: " + VBOsupported);
    }

    private void _getShaderAttributes(GL2 gl)
    {
        vertexAttribute = gl.glGetAttribLocation(shaderProgram, "vertex");
        projectionAttribute = gl.glGetUniformLocation(shaderProgram, "projection");
        positionAttribute = gl.glGetUniformLocation(shaderProgram, "positionSampler");
    }

    // Called by me on the first resize call, useful for things that can't be initialized until the screen size is known
    public void viewInit(GL2 gl)
    {
        for(int i = 0; i < NUM_THINGS; i++)
        {
            position[i*2] = (float) (Math.random()*viewWidth);
            position[i*2+1] = (float) (Math.random()*viewHeight);
        }

        gl.glUniformMatrix3fv(projectionAttribute, 1, false, Matrix.projection3f, 0);

        // Load position data into a texture buffer
        gl.glBindBuffer(GL2.GL_TEXTURE_BUFFER, geometry.positionBufferID);
        ByteBuffer textureBuffer = gl.glMapBuffer(GL2.GL_TEXTURE_BUFFER, GL2.GL_WRITE_ONLY);
        FloatBuffer textureFloatBuffer = textureBuffer.order(ByteOrder.nativeOrder()).asFloatBuffer();

        for(int i = 0; i < position.length; i++)
        {
            textureFloatBuffer.put(position[i]);
        }

        gl.glUnmapBuffer(GL2.GL_TEXTURE_BUFFER);
        gl.glBindBuffer(GL2.GL_TEXTURE_BUFFER, 0);
    }

    public void display(GLAutoDrawable d)
    {

        if (!didInit || geometry.vertexBufferID == 0)
        {
            return;
        }

        //long startDrawTime = System.currentTimeMillis();
        final GL2 gl = d.getGL().getGL2();

        gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT);


        // If we were drawing any other buffers here we'd need to set this every time
        // but instead we just leave them bound after initialization, saves a little render time
        // No combination of these seems to fix the problem
        //gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, geometry.vertexBufferID);
        //gl.glVertexAttribPointer(vertexAttribute, 3, GL2.GL_FLOAT, false, 0, 0);
        //gl.glBindBuffer(GL2.GL_ELEMENT_ARRAY_BUFFER, geometry.indexBufferID);
        gl.glBindBuffer(GL2.GL_TEXTURE_BUFFER, geometry.positionBufferID);
        //gl.glActiveTexture(GL2.GL_TEXTURE0);
        //gl.glTexBuffer(GL2.GL_TEXTURE_BUFFER, GL2.GL_R32F, geometry.positionBufferID);

        _render(gl, geometry);

        // Also tried these
        //gl.glFlush();
        //gl.glFinish();
    }

    public void _render(GL2 gl, SquareGeometry geometry)
    {
        gl.glMultiDrawElements(geometry.drawMode, geometry.countBuffer, GL2.GL_UNSIGNED_SHORT, geometry.offsetBuffer, NUM_THINGS);
        // This one works, but isn't what I want
        //gl.glDrawElements(GL2.GL_LINE_LOOP, count, GL2.GL_UNSIGNED_SHORT, 0);
    }

    public void reshape(GLAutoDrawable d, int x, int y, int width, int height)
    {
        final GL2 gl = d.getGL().getGL2();
        gl.glViewport(0, 0, width, height);
        float ratio = (float) height / width;

        screenWidth = width;
        screenHeight = height;
        viewWidth = 100;
        viewHeight = viewWidth * ratio;

        Matrix.ortho3f(0, viewWidth, 0, viewHeight);

        if (!didInit)
        {
            viewInit(gl);
            didInit = true;
        } 
        else
        {
            // respond to view size changing
        }
    }
}

The final bit is the SquareGeometry class which holds all the bufferIDs and vertex data, but also is responsible for filling the vertex buffer correctly so that each vertex’s z component can function as an index into the position texture:

public class SquareGeometry
{
    public float[] vertices = null;

    ShortBuffer indexBuffer;
    IntBuffer countBuffer;
    PointerBuffer offsetBuffer;
    FloatBuffer vertexBuffer;

    public int vertexBufferID = 0;
    public int indexBufferID = 0;
    public int positionBufferID = 0;
    public int positionTextureID = 0;

    public int drawMode;

    protected float width = 0;
    protected float height = 0;

    public SquareGeometry(float size)
    {
        width = size;
        height = size;
    }

    public void buildGeometry(float viewWidth, float viewHeight)
    {
        vertices = new float[4 * 2];
        vertices[0] = -width/2;
        vertices[1] = -height/2;
        vertices[2] = -width/2;
        vertices[3] = height/2;
        vertices[4] = width/2;
        vertices[5] = height/2;
        vertices[6] = width/2;
        vertices[7] = -height/2;

        drawMode = GL2.GL_POLYGON;
    }

    public void finalizeGeometry(int numInstances)
    {
        if(vertices == null) return;

        int num_vertices = this.getNumPoints();
        int total_num_vertices = numInstances * num_vertices;

        // initialize vertex Buffer (# of coordinate values * 4 bytes per float)  
        ByteBuffer vbb = ByteBuffer.allocateDirect(total_num_vertices * 3 * Float.SIZE);
        vbb.order(ByteOrder.nativeOrder());
        vertexBuffer = vbb.asFloatBuffer();

        for(int i = 0; i < numInstances; i++)
        {
            for(int v = 0; v < num_vertices; v++)
            {
                int vertex_index = v * 2;
                vertexBuffer.put(vertices[vertex_index]);
                vertexBuffer.put(vertices[vertex_index+1]);
                vertexBuffer.put(i);
            }
        }
        vertexBuffer.rewind();

        // Create the indices
        vbb = ByteBuffer.allocateDirect(total_num_vertices * Short.SIZE);
        vbb.order(ByteOrder.nativeOrder());
        indexBuffer = vbb.asShortBuffer();

        for(int i = 0; i < total_num_vertices; i++)
        {
            indexBuffer.put((short) (i));
        }
        indexBuffer.rewind();

        // Create the counts
        vbb = ByteBuffer.allocateDirect(numInstances * Integer.SIZE);
        vbb.order(ByteOrder.nativeOrder());
        countBuffer = vbb.asIntBuffer();
        for(int i = 0; i < numInstances; i++)
        {
            countBuffer.put(num_vertices);
        }
        countBuffer.rewind();

        // create the offsets
        offsetBuffer = PointerBuffer.allocateDirect(numInstances);
        for(int i = 0; i < numInstances; i++)
        {
            offsetBuffer.put(num_vertices*i*2);
        }
        offsetBuffer.rewind();
    }

    public int getNumPoints() 
    {
        return vertices.length/2;
    }
}
  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-13T07:18:06+00:00Added an answer on June 13, 2026 at 7:18 am

    Alright, I’ve got it solved, though I’m still really not clear on what the original problem was. I fixed it by simplifying the drawing to use drawArrays instead of drawElements or multiDrawElements. I’m really not sure why I thought I needed them, as I really don’t in this case. I’m pretty sure I was messing up a few things with the indexes and offsets.

    Furthermore, as far as the proper way to bind the texture buffer, neither the code I have above, nor example found at the link I posted in a comment are correct at all.

    If anyone is interested in the correct way to use the texture buffer like this I just did a pretty extensive write-up on it here http://zebadiah.me/?p=44. Thanks all for the help.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

Backstory:I've created a tool to type in and press enter to add as many
Backstory: I'm using log4net to handle all logging for a project I'm working on.
Is it possible to create a singleton function inside of mysql? BackStory: Looking to
BackStory I am writing an ipad app which has images that scrolls horizontally using
Short backstory: My UI code uses tabs heavly and as time progresses and features
Brief backstory, our previous developer used ASIHTTPRequest to make POST requests and retrieve data
A little backstory, currently I'm working on implementing a triangle rendering system in Expression2
Bit of a backstory to this one... I have an ASP.NET Login App on
Alright, I'm at my wit's end on this issue. First, backstory. I'm working on
Backstory: So I was driving to band practice this evening. My car has a

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.