VBO text handler will not render.

Started by majikchicken, April 27, 2016, 06:54:27

Previous topic - Next topic

majikchicken

I've been following the VBO tutorial on the wiki, and I tried to optimize my text rendering by switching from drawing to modifying a VBO.

I can't get the VBO to render, and I don't know why.

Here's the code in my font drawing function:
public void drawText(String text, int x, int y) {
    	if(Screen.vidMode == 0x00){
    		GL11.glEnable(GL11.GL_TEXTURE_2D);
    		GL11.glMatrixMode(GL11.GL_PROJECTION);
    		GL11.glLoadIdentity();
    		GL11.glOrtho(0, Screen.windowWidth, Screen.windowHeight, 0, -1, 1);
    		GL11.glMatrixMode(GL11.GL_MODELVIEW);
    		GL11.glLoadIdentity();
    		glBindTexture(GL_TEXTURE_2D, this.fontTextureId);
    		glBegin(GL_QUADS);
    		glColor3f(Screen.DEFAULT_COLOR[0], Screen.DEFAULT_COLOR[1], Screen.DEFAULT_COLOR[2]);
    		
    		int xTmp = x;
    		for (char c : text.toCharArray()) {
    			float width = getCharWidth(c);
    			float height = getCharHeight();
    			float cw = 1f / getFontImageWidth() * width;
    			float ch = 1f / getFontImageHeight() * height;
    			float cx = 1f / getFontImageWidth() * getCharX(c);
    			float cy = 1f / getFontImageHeight() * getCharY(c);
    			
    			glTexCoord2f(cx, cy);
    			glVertex3f(xTmp, y, 0);
    			
    			glTexCoord2f(cx + cw, cy);
    			glVertex3f(xTmp + width, y, 0);
    			
    			glTexCoord2f(cx + cw, cy + ch);
    			glVertex3f(xTmp + width, y + height, 0);
    			
    			glTexCoord2f(cx, cy + ch);
    			glVertex3f(xTmp, y + height, 0);
    			
    			xTmp += width;
    		}
             
    		glEnd();
    		glDisable(GL11.GL_TEXTURE_2D);
    	}else if(Screen.vidMode == 0x01 || Screen.vidMode == 0x02){
    		int xTmp = x;
    		
    		GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, Screen.txtMem);
    		FloatBuffer fbuf = BufferUtils.createFloatBuffer(0);
    		FloatBuffer memory = MemoryUtil.memFloatBuffer(GL15.glGetBufferPointer(GL15.GL_ARRAY_BUFFER, GL15.GL_BUFFER_MAP_POINTER), Screen.txtMemSize);
    		
    		if(memory == null)
    			memory = BufferUtils.createFloatBuffer(0);
    		
    		int i = 32;
    		for (char c : text.toCharArray()) {
    			FloatBuffer dupl = fbuf.duplicate();
    			fbuf = FloatBuffer.allocate(i);
    			fbuf.put(dupl);
    			
    			float width = getCharWidth(c);
    			float height = getCharHeight();
    			float cw = 1f / getFontImageWidth() * width;
    			float ch = 1f / getFontImageHeight() * height;
    			float cx = 1f / getFontImageWidth() * getCharX(c);
    			float cy = 1f / getFontImageHeight() * getCharY(c);
    			
    			fbuf.put(cx);
    			fbuf.put(cy);
    			
    			fbuf.put(xTmp);
    			fbuf.put( y);
    			fbuf.put( 0f);
    			
    			fbuf.put( Screen.DEFAULT_COLOR[0]);
    			fbuf.put( Screen.DEFAULT_COLOR[1]);
    			fbuf.put( Screen.DEFAULT_COLOR[2]);
    			
    			fbuf.put( cx + cw);
    			fbuf.put( cy);
    			
    			fbuf.put( xTmp + width);
    			fbuf.put( y);
    			fbuf.put( 0f);
    			
    			fbuf.put( Screen.DEFAULT_COLOR[0]);
    			fbuf.put( Screen.DEFAULT_COLOR[1]);
    			fbuf.put( Screen.DEFAULT_COLOR[2]);
    			
    			fbuf.put( cx + cw);
    			fbuf.put( cy + ch);
    			
    			fbuf.put( xTmp + width);
    			fbuf.put( y + height);
    			fbuf.put( 0f);
    			
    			fbuf.put( Screen.DEFAULT_COLOR[0]);
    			fbuf.put(Screen.DEFAULT_COLOR[1]);
    			fbuf.put( Screen.DEFAULT_COLOR[2]);
    			
    			fbuf.put( cx);
    			fbuf.put( cy + ch);
    			
    			fbuf.put( xTmp);
    			fbuf.put( y + height);
    			fbuf.put( 0f);
    			
    			fbuf.put( Screen.DEFAULT_COLOR[0]);
    			fbuf.put( Screen.DEFAULT_COLOR[1]);
    			fbuf.put( Screen.DEFAULT_COLOR[2]);
    			
    			xTmp += width;
    			Screen.txtMemSize += 32;
    			i += 32;
    		}
    	
    		FloatBuffer newMem = BufferUtils.createFloatBuffer(Screen.txtMemSize);
    		
    		newMem.put(memory);
    		newMem.put(fbuf);
    		newMem.rewind();
    		newMem.flip();
    		
    		GL15.glBufferData(GL15.GL_ARRAY_BUFFER, newMem, GL15.GL_STATIC_DRAW);
    		
    		GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
    	}
    }



And here's the relevant code in my rendering function:
if(Screen.vidMode == 0x01 || Screen.vidMode == 0x02){
				CLI.println("In mode 0x02");
				
				GL11.glEnable(GL11.GL_BLEND);
	            		GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
				
				GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, Screen.txtMem);
				
				GL11.glTexCoordPointer(2, GL11.GL_FLOAT, 8*4, 0);
	    			GL11.glVertexPointer(3, GL11.GL_FLOAT, 8*4, 2*4);
		    		GL11.glColorPointer(3, GL11.GL_FLOAT, 8*4, 5*4);
	    		
		    		// Unbind VBO
	    			GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
	    	
	    			GL11.glEnableClientState(GL11.GL_VERTEX_ARRAY);
				GL11.glEnableClientState(GL11.GL_TEXTURE_COORD_ARRAY);
				GL11.glEnableClientState(GL11.GL_COLOR_ARRAY);
	    		
		    		GL11.glDrawArrays(GL11.GL_QUADS, 0, Screen.txtMemSize);
	    		
	    			GL11.glDisableClientState(GL11.GL_VERTEX_ARRAY);
	    			GL11.glDisableClientState(GL11.GL_TEXTURE_COORD_ARRAY);
	    			GL11.glDisableClientState(GL11.GL_COLOR_ARRAY);
	    		
	    			GL11.glDisable(GL11.GL_BLEND);
	    			CLI.println("err "+GL11.glGetError());
			}


glGetError returns 0, but the text doesn't render.  What am I doing?

Kai

The problem is that when doing fbuf.put(dupl) then 'dupl' (which was the previous 'fbuf') at that point in time has zero remaining() bytes/floats (i.e. it inherits the position and limit from the 'fbuf' which it was duplicate'd() from whose position was its limit at the time of calling duplicate()).
Therefore, FloatBuffer.put(FloatBuffer) will not put anything into the new 'fbuf'.
So you should do a fbuf.flip() or a dupl.flip() before doing fbuf.put(dupl).
But you should debug that particular code section using breakpoints to inspect the state of those buffers at each for loop iteration.

EDIT: What becomes then the next critical thing, is that your FloatBuffer is never large enough to hold all vertices. You are only always allocating a FloatBuffer with a capacity of 32 floats. You should once before the for loop allocate a FloatBuffer which has `32 * text.toCharArray().length` floats.
FloatBuffer.put(FloatBuffer) does not "grow" the buffer.

majikchicken

Quote from: Kai on April 27, 2016, 09:15:33
EDIT: What becomes then the next critical thing, is that your FloatBuffer is never large enough to hold all vertices. You are only always allocating a FloatBuffer with a capacity of 32 floats. You should once before the for loop allocate a FloatBuffer which has `32 * text.toCharArray().length` floats.
FloatBuffer.put(FloatBuffer) does not "grow" the buffer.

That's what the `i` variable is for.  I realize it's more efficient to do it your way though.

int i = 32; // Initial allocation is 32 indices for 1 char
for(etc){
fbuf = FloatBuffer.allocate(i);
...
i +=32; // Grow the size we allocate by, by 32 indices for the next character
}



Edit:
Here's the updated font processing code using what you suggested
int xTmp = x;
    		
    		GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, Screen.txtMem);
    		FloatBuffer fbuf = BufferUtils.createFloatBuffer(32*text.toCharArray().length);
    		FloatBuffer memory = MemoryUtil.memFloatBuffer(GL15.glGetBufferPointer(GL15.GL_ARRAY_BUFFER, GL15.GL_BUFFER_MAP_POINTER), Screen.txtMemSize);
    		
    		if(memory == null)
    			memory = BufferUtils.createFloatBuffer(0);
    		
    		for (char c : text.toCharArray()) {
    			float width = getCharWidth(c);
    			float height = getCharHeight();
    			float cw = 1f / getFontImageWidth() * width;
    			float ch = 1f / getFontImageHeight() * height;
    			float cx = 1f / getFontImageWidth() * getCharX(c);
    			float cy = 1f / getFontImageHeight() * getCharY(c);
    			
    			fbuf.put(cx);
    			fbuf.put(cy);
    			
    			fbuf.put(xTmp);
    			fbuf.put( y);
    			fbuf.put( 0f);
    			
    			fbuf.put( Screen.DEFAULT_COLOR[0]);
    			fbuf.put( Screen.DEFAULT_COLOR[1]);
    			fbuf.put( Screen.DEFAULT_COLOR[2]);
    			
    			fbuf.put( cx + cw);
    			fbuf.put( cy);
    			
    			fbuf.put( xTmp + width);
    			fbuf.put( y);
    			fbuf.put( 0f);
    			
    			fbuf.put( Screen.DEFAULT_COLOR[0]);
    			fbuf.put( Screen.DEFAULT_COLOR[1]);
    			fbuf.put( Screen.DEFAULT_COLOR[2]);
    			
    			fbuf.put( cx + cw);
    			fbuf.put( cy + ch);
    			
    			fbuf.put( xTmp + width);
    			fbuf.put( y + height);
    			fbuf.put( 0f);
    			
    			fbuf.put( Screen.DEFAULT_COLOR[0]);
    			fbuf.put(Screen.DEFAULT_COLOR[1]);
    			fbuf.put( Screen.DEFAULT_COLOR[2]);
    			
    			fbuf.put( cx);
    			fbuf.put( cy + ch);
    			
    			fbuf.put( xTmp);
    			fbuf.put( y + height);
    			fbuf.put( 0f);
    			
    			fbuf.put( Screen.DEFAULT_COLOR[0]);
    			fbuf.put( Screen.DEFAULT_COLOR[1]);
    			fbuf.put( Screen.DEFAULT_COLOR[2]);
    			
    			xTmp += width;
    			Screen.txtMemSize += 32;
    		}
    	
    		memory.flip();
    		fbuf.flip();
    		
    		FloatBuffer newMem = BufferUtils.createFloatBuffer(Screen.txtMemSize);
    		
    		newMem.put(memory);
    		newMem.put(fbuf);
    		newMem.rewind();
    		newMem.flip();
    		
    		GL15.glBufferData(GL15.GL_ARRAY_BUFFER, newMem, GL15.GL_STATIC_DRAW);
    		
    		GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);


It still doesn't work though

majikchicken

I have found that in my program, when I switch from drawing points to drawing shapes using GL_TRIANGLE_FANS, I get GLerror 1282 everytime I render.  I'm not sure it's related to the VBO issue though, as I don't get the error when drawing points instead.


majikchicken

Okay, so I have found that the newMem FloatBuffer has every value set to 0.0 even after putting in the fbuf buffer, which does have the correct values.  Anyone know why?

Edit: After checking the memory buffer, I found the glGetBufferSubData(GL15.GL_ARRAY_BUFFER, 0, FloatBuffer memory) gives me a float buffer with 3.8k members that are set to zero.  I'm clearly doing something wrong lol.

majikchicken

I have determined that something in this code is causing the VBO to be stored as an array of all zeroes.

    		//if(hasMemory)
    		//	memory.flip();
    		
    		fbuf.rewind();
    		//fbuf.flip();
    		
    		FloatBuffer newMem = FloatBuffer.allocate(Screen.txtMemSize);
    		
    		if(hasMemory)
    			newMem.put(memory);
    		
    		newMem.put(fbuf);
    		
    		for(int n = Screen.txtMemSize; n > 0; n--)
    			CLI.getDebugger().print("nMem(" + (Screen.txtMemSize - n) + ") - " + newMem.get(Screen.txtMemSize - n));
    		

    		newMem.rewind();
    		//newMem.flip();
    		
    		
    		GL15.glBufferData(GL15.GL_ARRAY_BUFFER, newMem, GL15.GL_STATIC_DRAW);
    		
    		GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);

majikchicken

Solved it.  I need to initialize my buffers as native ordered.

So, instead of doing
FloatBuffer newMem = FloatBuffer.allocate(Screen.txtMemSize);


I needed to do
FloatBuffer newMem = BufferUtils.createFloatBuffer(Screen.txtMemSize);