unit uglcArrayBuffer; { Package: OpenGLCore Prefix: glc - OpenGL Core Beschreibung: diese Unit enthält eine Klassen-Kapselung für OpenGL Array Buffer Beispiel: type TVertex = packed record pos: TgluVector3f; // vertex position tex: TgluVector2f; // texture coordinates nor: TgluVector3f; // normal end; PVertex = ^TVertex; var vBuffer: TglcArrayBuffer; iBuffer: TglcArrayBuffer; p: Pointer; vBuffer := TglcArrayBuffer.Create(TglcBufferTarget.btArrayBuffer); iBuffer := TglcArrayBuffer.Create(TglcBufferTarget.btElementArrayBuffer); try // write vertex data to vertex buffer vBuffer.Bind; vBuffer.BufferData(4, SizeOf(TresMeshVertex), TglcBufferUsage.buStaticDraw, nil); p := vBuffer.MapBuffer(TglcBufferAccess.baWriteOnly); try PVertex(p).pos := gluVertex3f(0.0, 0.0, 0.0); PVertex(p).tex := gluVertex2f(0.0, 0.5); PVertex(p).nor := gluVertex3f(0.0, 1.0, 0.0); inc(p, SizeOf(TVertex)); // ... finally vBuffer.UnmapBuffer; vBuffer.Unbind; end; // write indices to index buffer iBuffer.Bind; iBuffer.BufferData(4, SizeOf(GLuint), TglcBufferUsage.buStaticDraw, nil); p := iBuffer.MapBuffer(TglcBufferAccess.baWriteOnly); try PGLuint(p) := 0; // ... finally iBuffer.UnmapBuffer; iBuffer.Unbind; end; // use array buffers to draw primitive vBuffer.Bind; iBuffer.Bind; glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(3, GL_FLOAT, 8, Pointer(0)); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoordPointer(2, GL_FLOAT, 8, Pointer(3)); glEnableClientState(GL_NORMAL_ARRAY); glNormalPointer(GL_FLOAT, 8, Pointer(5)); glEnableClientState(GL_INDEX_ARRAY); glIndexPointer(GL_INT, 0, nil); glDrawElements(GL_QUADS, iBuffer.DataCount, GL_UNSIGNED_INT, nil); glDisableClientState(GL_INDEX_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); fIndexBuffer.Unbind; fVertexBuffer.Unbind; finally FreeAndNil(vBuffer); FreeAndNil(iBuffer); end; } {$mode objfpc}{$H+} interface uses {$IFNDEF OPENGL_ES}dglOpenGL{$ELSE}dglOpenGLES{$ENDIF}, sysutils, uglcTypes; type EglcArrayBuffer = class(Exception); TglcArrayBuffer = class(TObject) private fID: GLuint; fTarget: TglcBufferTarget; fUsage: TglcBufferUsage; protected fDataCount: Integer; fDataSize: Integer; public property ID: gluInt read fID; property Target: TglcBufferTarget read fTarget; property Usage: TglcBufferUsage read fUsage; property DataCount: Integer read fDataCount; property DataSize: Integer read fDataSize; procedure BufferData(const aDataCount, aDataSize: Cardinal; const aUsage: TglcBufferUsage; const aData: Pointer); function MapBuffer(const aAccess: TglcBufferAccess): Pointer; function MapBufferRange(const aOffset: GLintptr; const aSize: GLsizeiptr; const aAccess: TglcBufferAccess): Pointer; procedure UnmapBuffer; procedure Bind; procedure Unbind; constructor Create(const aTarget: TglcBufferTarget); destructor Destroy; override; end; implementation //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TglcArrayBuffer/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////[c] procedure TglcArrayBuffer.BufferData(const aDataCount, aDataSize: Cardinal; const aUsage: TglcBufferUsage; const aData: Pointer); begin glGetError(); //clear Errors Bind; fDataCount := aDataCount; fDataSize := aDataSize; fUsage := aUsage; glBufferData(GLenum(fTarget), fDataCount * fDataSize, aData, GLenum(fUsage)); glcCheckAndRaiseError; end; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////[c] function TglcArrayBuffer.MapBuffer(const aAccess: TglcBufferAccess): Pointer; begin glGetError(); result := nil; if (fDataCount * fDataSize) <= 0 then exit; {$IFNDEF OPENGL_ES} result := glMapBuffer(GLenum(fTarget), GLenum(aAccess)); {$ELSE} if GL_OES_mapbuffer then result := glMapBufferOES(GLenum(fTarget), GLenum(aAccess)) else raise EglcArrayBuffer.Create('map buffer is not supported by video card'); {$ENDIF} glcCheckAndRaiseError; end; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////[c] function TglcArrayBuffer.MapBufferRange(const aOffset: GLintptr; const aSize: GLsizeiptr; const aAccess: TglcBufferAccess): Pointer; begin {$IFNDEF OPENGL_ES} if not (GL_ARB_map_buffer_range or GL_VERSION_3_0) then raise EglcArrayBuffer.Create('map buffer range is not supported by video card'); result := glMapBufferRange(GLenum(fTarget), aOffset, aSize, GLenum(aAccess)); {$ELSE} if GL_VERSION_3_0 then result := glMapBufferRange(GLenum(fTarget), aOffset, aSize, GLenum(aAccess)) else if GL_EXT_map_buffer_range then result := glMapBufferRangeEXT(GLenum(fTarget), aOffset, aSize, GLenum(aAccess)) else raise EglcArrayBuffer.Create('map buffer range is not supported by video card'); {$ENDIF} end; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////[c] procedure TglcArrayBuffer.UnmapBuffer; begin {$IFNDEF OPENGL_ES} glUnmapBuffer(GLenum(fTarget)); {$ELSE} if GL_VERSION_3_0 then glUnmapBuffer(GLenum(fTarget)) else if GL_OES_mapbuffer then glUnmapBufferOES(GLenum(fTarget)) else raise EglcArrayBuffer.Create('unmap buffer is not supported by video card'); {$ENDIF} end; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////[c] procedure TglcArrayBuffer.Bind; begin glBindBuffer(GLenum(fTarget), fID); end; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////[c] procedure TglcArrayBuffer.Unbind; begin glBindBuffer(GLenum(fTarget), 0); end; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////[c] constructor TglcArrayBuffer.Create(const aTarget: TglcBufferTarget); begin {$IFNDEF OPENGL_ES} if not (GL_ARB_Vertex_Buffer_Object or GL_VERSION_2_0) then raise EglcArrayBuffer.Create('Create - VertexBuffer: not supported'); {$ELSE} if not GL_VERSION_2_0 then raise EglcArrayBuffer.Create('Create - VertexBuffer: not supported'); {$ENDIF} glGetError(); inherited Create; glGenBuffers(1, @fID); fDataCount := 0; fDataSize := 0; fTarget := aTarget; glcCheckAndRaiseError; end; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////[c] destructor TglcArrayBuffer.Destroy; begin glDeleteBuffers(1, @fID); inherited Destroy; end; end.