I was browsing sources of the legendary ZenGL library in search of enlightening when I suddenly realized that ZenGL has its own implementation of most common immediate mode functions to be used on top of GL ES (which, by design, doesn't support 'em).
And then I thought: could this be it? Could a well optimized custom implementation be faster than what compatibility layers of modern ICDs provide out of mercy?
All I know that immediate mode performance drops *sharply* after around 20 k vertexes.
Maybe that's artificial?
What if custom implementation packed that array's texture and color values to something more compact than GL_FLOAT ? That would make uploading to video card during glEnd faster. And ZenGL does - it stores color values as GL_UNSIGNED_BYTE.
Or do OA sources *already* use something like this?
The inspirational code (can only be used for inspiration, heh)
Just look at this little beauty!
procedure glEnd;
begin
if bSize = 0 Then exit;
if RenderTextured Then
begin
glEnableClientState( GL_TEXTURE_COORD_ARRAY );
glTexCoordPointer( 2, GL_FLOAT, 24, @bVertices[ 0 ] );
end;
glEnableClientState( GL_COLOR_ARRAY );
glColorPointer( 4, GL_UNSIGNED_BYTE, 24, @bVertices[ 0 ].Color );
glEnableClientState( GL_VERTEX_ARRAY );
glVertexPointer( 3, GL_FLOAT, 24, @bVertices[ 0 ].X );
glDrawArrays( RenderMode, 0, bSize );
glDisableClientState( GL_VERTEX_ARRAY );
glDisableClientState( GL_COLOR_ARRAY );
if RenderTextured Then
glDisableClientState( GL_TEXTURE_COORD_ARRAY );
end;
The rest
procedure glBegin(mode: GLenum);
begin
bSize := 0;
RenderTextured := FALSE;
if Mode = GL_QUADS Then
begin
RenderQuad := TRUE;
newTriangle := 0;
RenderMode := GL_TRIANGLES;
end else
begin
RenderQuad := FALSE;
RenderMode := Mode;
end;
end;
procedure glColor4ub(red, green, blue, alpha: GLubyte);
begin
PByteArray( @bColor )[ 0 ] := red;
PByteArray( @bColor )[ 1 ] := green;
PByteArray( @bColor )[ 2 ] := blue;
PByteArray( @bColor )[ 3 ] := alpha;
end;
procedure glColor4ubv(v: PGLubyte);
begin
bColor := PLongWord( v )^;
end;
procedure glColor4f(red, green, blue, alpha: GLfloat);
begin
PByteArray( @bColor )[ 0 ] := Round( red * 255 );
PByteArray( @bColor )[ 1 ] := Round( green * 255 );
PByteArray( @bColor )[ 2 ] := Round( blue * 255 );
PByteArray( @bColor )[ 3 ] := Round( alpha * 255 );
end;
{$IFDEF ANDROID}
function tan( x : Single ) : Single;
var
_sin,_cos : Single;
begin
m_SinCos( x, _sin, _cos );
tan := _sin / _cos;
end;
{$ENDIF}
procedure gluPerspective(fovy, aspect, zNear, zFar: GLdouble);
var
m : array[ 1..4, 1..4 ] of Single;
f : Single;
begin
f := 1 / tan( FOVY * pi / 360 );
m[ 1, 1 ] := f / aspect;
m[ 1, 2 ] := 0;
m[ 1, 3 ] := 0;
m[ 1, 4 ] := 0;
m[ 2, 1 ] := 0;
m[ 2, 2 ] := f;
m[ 2, 3 ] := 0;
m[ 2, 4 ] := 0;
m[ 3, 1 ] := 0;
m[ 3, 2 ] := 0;
m[ 3, 3 ] := ( zFar + zNear ) / ( zNear - zFar );
m[ 3, 4 ] := -1;
m[ 4, 1 ] := 0;
m[ 4, 2 ] := 0;
m[ 4, 3 ] := 2 * zFar * zNear / ( zNear - zFar );
m[ 4, 4 ] := 0;
glLoadMatrixf( @m[ 1, 1 ] );
end;
procedure glVertex2f(x, y: GLfloat);
var
vertex : zglGLESPVertex;
begin
if ( not RenderTextured ) and ( bSize = Length( bVertices ) ) Then
SetLength( bVertices, bSize + 1024 );
vertex := @bVertices[ bSize ];
vertex.X := x;
vertex.Y := y;
vertex.Z := 0;
vertex.Color := bColor;
INC( bSize );
if RenderQuad Then
begin
INC( newTriangle );
if newTriangle = 3 Then
begin
if bSize = Length( bVertices ) Then
SetLength( bVertices, bSize + 1024 );
bVertices[ bSize ] := bVertices[ bSize - 1 ];
INC( bSize );
end else
if newTriangle = 4 Then
begin
if bSize = Length( bVertices ) Then
SetLength( bVertices, bSize + 1024 );
bVertices[ bSize ] := bVertices[ bSize - 5 ];
INC( bSize );
newTriangle := 0;
end;
end;
end;
procedure glVertex2fv(v: PGLfloat);
var
vertex : zglGLESPVertex;
begin
if ( not RenderTextured ) and ( bSize = Length( bVertices ) ) Then
SetLength( bVertices, bSize + 1024 );
vertex := @bVertices[ bSize ];
vertex.X := zglPPoint2D( v ).X;
vertex.Y := zglPPoint2D( v ).Y;
vertex.Z := 0;
vertex.Color := bColor;
INC( bSize );
if RenderQuad Then
begin
INC( newTriangle );
if newTriangle = 3 Then
begin
if bSize = Length( bVertices ) Then
SetLength( bVertices, bSize + 1024 );
bVertices[ bSize ] := bVertices[ bSize - 1 ];
INC( bSize );
end else
if newTriangle = 4 Then
begin
if bSize = Length( bVertices ) Then
SetLength( bVertices, bSize + 1024 );
bVertices[ bSize ] := bVertices[ bSize - 5 ];
INC( bSize );
newTriangle := 0;
end;
end;
end;
procedure glVertex3f(x, y, z: GLfloat);
var
vertex : zglGLESPVertex;
begin
if ( not RenderTextured ) and ( bSize = Length( bVertices ) ) Then
SetLength( bVertices, bSize + 1024 );
vertex := @bVertices[ bSize ];
vertex.X := x;
vertex.Y := y;
vertex.Z := z;
vertex.Color := bColor;
INC( bSize );
if RenderQuad Then
begin
INC( newTriangle );
if newTriangle = 3 Then
begin
if bSize = Length( bVertices ) Then
SetLength( bVertices, bSize + 1024 );
bVertices[ bSize ] := bVertices[ bSize - 1 ];
INC( bSize );
end else
if newTriangle = 4 Then
begin
if bSize = Length( bVertices ) Then
SetLength( bVertices, bSize + 1024 );
bVertices[ bSize ] := bVertices[ bSize - 5 ];
INC( bSize );
newTriangle := 0;
end;
end;
end;
procedure glGetTexImage(target: GLenum; level: GLint; format: GLenum; atype: GLenum; pixels: Pointer);
begin
end;
procedure glTexCoord2f(s, t: GLfloat);
begin
RenderTextured := TRUE;
if bSize = Length( bVertices ) Then
SetLength( bVertices, bSize + 1024 );
bVertices[ bSize ].U := s;
bVertices[ bSize ].V := t;
end;
procedure glTexCoord2fv(v: PGLfloat);
begin
RenderTextured := TRUE;
if bSize = Length( bVertices ) Then
SetLength( bVertices, bSize + 1024 );
bVertices[ bSize ].U := zglPPoint2D( v ).X;
bVertices[ bSize ].V := zglPPoint2D( v ).Y;
end;