OpenGL object - Fish-In-A-Suit/Conquest GitHub Wiki
OpenGL object An OpenGL Object is an OpenGL construct that contains some state. When they (objects) are bound to the context, the state that they contain is mapped into the context's state. Thus, changes to context state will be stored in this object, and functions that act on this context state will use the state stored in the object.
OpenGL is defined as a state machine. The various API calls change the OpenGL state, query some part of that state, or cause OpenGL to use its current state to render something. Because of this, an OpenGL object mustn't be treated as a regular object. Instead, you set a series of states.
For example: Instead of saying "Hey, draw me a triangle", and passing in all of the stuff that OpenGL needs to draw that triangle, OpenGL knows already what it has to use to draw that triangle, as that is part of the state. You say: "I want you to select this buffer.", "I want you to select this shader.", "Now, draw a triangle." Based on which buffer and which shader is selected, that's going to determine what triangle gets drawn.
OBJECT CREATION AND DESTRUCTION:
To create an object, you generate the object's name (which is represented as an integer - the reference must be an int). This creates a reference to that object. However, this does not necessarily create the object's state data. For most object types, the object will only contain its default state when it is first bound to the context; until it is bound, attempting to use it will fail.
The methods to generate object names are of the form glGen*, where * is the object's type in plural form (for example, glGenVertexArrays). All methods have the same signature: glGen*()
, which creates an object name (which you have to store in some variable of type int, since the name will be given as an int).
An object name is always a GLuint. These names are not pointers, nor should you assume that they are. They are references, numbers that identify an object. They can be any 32-bit unsigned integer except 0. The GLuint is just one of the many OpenGL data types, which can be seen here.
Once you are finished with an object, you should delete it. The methods for performing object deletion are of type glDelete*, using the same naming convention as the methods for creating objects:
void glDelete*();
OBJECT USAGE - BINDING IT TO THE CONTEXT
Because objects in OpenGL are defined as a collections of state, to modify objects, you must first bind them to the OpenGL context. Binding objects to the context causes the state in them to be set to be the current context's state. This means that any methods that change the state governed by that object will simply change the state within the object, thus preserving that state.
Binding a newly generated object name will create new state for that object. In some cases, the target to which it is first bound (see below) will affect properties of the newly created state for the object.
Different objects have different binding functions. They do share a naming convention and general parameters: void glBind*(GLenum target, GLuint object);
- The * is the type of the object and the object is the object to be bound
- The target is where different object types differ. Different types of objects can be bound to different targets. It must be one of the following: ARRAY_BUFFER, ELEMENT_ARRAY_BUFFER, PIXEL_PACK_BUFFER, PIXEL_UNPACK_BUFFER, TRANSFORM_FEEDBACK_BUFFER, UNIFORM_BUFFER, TEXTURE_BUFFER, COPY_READ_BUFFER, COPY_WRITE_BUFFER, DRAW_INDIRECT_BUFFER, ATOMIC_COUNTER_BUFFER, DISPATCH_INDIRECT_BUFFER, SHADER_STORAGE_BUFFER, PARAMETER_BUFFER_ARB
- The object represents the name of an OpenGL object (AN INT!!!)
Buffer object
Buffer objects are OpenGL objects that store an array of memory allocated by the OpenGL context (aka the GPU). They can be used to store vertex data = VBO, pixel data retrieved from images or the framebuffer, etc.
- Creating buffer objects: void glGenBuffers()
- Deleting buffer objects: void glDeleteBuffers(java.nio.Buffer buffer)
- Binding buffer objects: void glBindBuffer(int target, int bufferName)
- target: specifies the target buffer object and must be for example (GL_ARRAY_BUFFER or GL_UNIFORM_BUFFER). Take a look here to see all of the possible target values
- buffer: specifies the name of a buffer object
Buffer objects hold memory. This memory must be allocated before it can be uploaded or used.
Use: void glBufferData(int target, java.nio.OneOfTheBufferTypes data, int usage) to allocate storage to a buffer.
- target parameter is just like the one for glBindBuffer; it determines which bound buffer to modify
- data parameter is a pointer to memory that will be copied into the buffer object's data store. If this value is NULL, then no copying will occur, and the buffer object's data will be undefined
- usage specifies the expected usage pattern of the data store. The symbolic constant must be GL_STREAM_DRAW, GL_STREAM_READ, GL_STREAM_COPY, GL_STATIC_DRAW, GL_STATIC_READ, GL_STATIC_COPY, GL_DYNAMIC_DRAW, GL_DYNAMIC_READ, or GL_DYNAMIC_COPY
There exist numerous glBufferData methods with different signatures (as one can take in FloatBuffers, the others IntBuffers, the third ones doubles, etc.), so it's best to take a look at all of them here
glBufferData creates a new data store (a repository for persistently storing and managing collections of data) for the buffer object currently bound to target. Any pre-existing data store is deleted. The new data store is created with the specified usage.
usage is a hint to the GL implementation as to how a buffer object's data store will be accessed. This enables the GL implementation to make more intelligent decisions that may significantly impact buffer object performance. It does not, however, constrain the actual usage of the data store. usage can be broken down into two parts: first, the frequency of access (modification and usage), and second, the nature of that access. The frequency of access may be one of these:
- STREAM: The data store contents will be modified once and used at most a few times.
- STATIC: The data store contents will be modified once and used many times.
- DYNAMIC: The data store contents will be modified repeatedly and used many times.
The nature of access may be one of these:
- DRAW: The data store contents are modified by the application, and used as the source for GL drawing and image specification commands - the user will be writing data to the buffer, but the user will not read it
- READ: The data store contents are modified by reading data from the GL, and used to return that data when queried by the application - the user will not be writing data, but will be reading it back
- COPY: The data store contents are modified by reading data from the GL, and used as the source for GL drawing and image specification commands - the user will be neither writing nor reading data
DRAW is useful for, as the name suggests, drawing. The user is uploading data, but only the GL is reading it. Buffer objects holding vertex data are generally specified as DRAW, though there can be exceptions.
READ is used when a buffer object is used as the destination for OpenGL commands. This could be rendering to a Buffer Texture, using arbitrary writes to buffer textures, doing a pixel transfer into a buffer object, using Transform Feedback, or any other OpenGL operation that writes to buffer objects.
COPY is used when a buffer object is used to pass data from one place in OpenGL to another. For example, you can read image data into a buffer (you've got an image and perform a read operation on it: the OpenGL reads data from the picture and puts it inside the buffer object), then use that image data as vertex data in a draw call. Your code never actually sends data to the buffer directly, nor does it read data back. You can also use Transform Feedback to achieve the same thing in a more direct way. You have the feedback data go to a buffer object, then use that buffer object as vertex data. And while the user is causing the buffer to be updated via rendering commands, at no time is the user directly either reading from or writing to the buffer's storage.
Retrieving parameters of objects
OpenGL objects (such as shaders or programs) contain various different parameters, which can be quieried by different methods. OpenGL could be imagined like an onion. The whole OpenGL is represented as the context, which is further divided into various functionality/fields, which in turn, contain even more parameters, which specify their state.
Parameters of shader objects
The parameters of shader objects can be queried by public static int glGetShaderi(int shader, int pname) method.
- shader: the shader object to be queried
- pname: the object parameter, one of SHADER_TYPE, DELETE_STATUS, COMPILE_STATUS, INFO_LOG_LENGTH, SHADER_SOURCE_LENGTH
Only the parameters which are used inside the source code will be described:
- GL_COMPILE_STATUS: returns 1 if the last compile operation on shader was succesful, or 0 otherwise
- GL_SHADER_TYPE: returns GL_VERTEX_SHADER if shader is a vertex shader object, GL_GEOMETRY_SHADER if shader is a geometry shader object, and GL_FRAGMENT_SHADER if shader is a fragment shader object.
Parameters of program objects
can be queried by the public static int glGetProgrami(int program, int pname) method:
- program: the program object to be queried
- pname: the object parameter
pname can contain one of the following values: DELETE_STATUS, LINK_STATUS, VALIDATE_STATUS, INFO_LOG_LENGTH, ATTACHED_SHADERS, ACTIVE_ATTRIBUTES, ACTIVE_ATTRIBUTE_MAX_LENGTH, ACTIVE_UNIFORMS, ACTIVE_UNIFORM_MAX_LENGTH, TRANSFORM_FEEDBACK_BUFFER_MODE, TRANSFORM_FEEDBACK_VARYINGS, TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH, ACTIVE_UNIFORM_BLOCKS, ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, GEOMETRY_VERTICES_OUT, GEOMETRY_INPUT_TYPE, GEOMETRY_OUTPUT_TYPE, PROGRAM_BINARY_LENGTH, ACTIVE_ATOMIC_COUNTER_BUFFERS, COMPUTE_WORK_GROUP_SIZE
Only the values which are used inside the source code will be explained:
- GL_LINK_STATUS: returns 1 if the last link operation on the specified program was successful, or 0 otherwise.