BplusApp.Service_BasicGraphicsType

A Context service which defines a bunch of useful GL resources:

  • screen_triangle : A 1-triangle mesh with 2D positions in NDC-space. When drawn, it will perfectly cover the entire screen, making it easy to spin up post-processing effects. The UV coordinates can be calculated from the XY positions (or from gl_FragCoord).
  • screen_quad : A 2-triangle mesh describing a square, with 2D coordinates in the range (-1, -1) to (+1, +1). This can be used for post-processing effects, but it's less efficient than screen_triangle, for technical reasons.
  • blit : A simple shader to render a 2D texture (e.x. copy a Target to the screen). Refer to simple_blit().
  • empty_mesh : A mesh with no vertex data, for dispatching entirely procedural geometry. Has the 'points' PrimitiveType.
BplusApp.simple_blitMethod
Renders the given texure, using the given screen-screen_quad transform
    and the given color transform on the texture's pixels.
BplusApp.@game_loopMacro

Runs a basic game loop, with all the typical B+ services. The syntax looks like this:

@game_loop begin
    INIT(
        # Pass all the usual arguments to the constructor for a `GL.Context`.
        # For example:
        v2i(1920, 1080), "My Window Title";
        debug_mode=true
    )

    SETUP = begin
        # Julia code block that runs just before the loop.
        # Initialize your assets and game state, add custom fonts to CImGui, etc.
        # You can configure loop parameters by changing certain fields
        #    of the variable `LOOP::GameLoop`.
    end
    LOOP = begin
        # Julia code block that runs inside the loop.
        # Runs in a `for` loop in the same scope as `SETUP`.
        # You should end the loop with a `break` statement --
        #   if you `return` or `throw`, then the `TEARDOWN` section won't run.
    end
    TEARDOWN = begin
        # Julia code block that runs after the loop.
        # Runs in the same scope as `SETUP`.
    end
end

In all the code blocks but INIT, you have access to the game loop state through the variable LOOP::GameLoop

BplusApp.GUIModule

Implementation of a Dear IMGUI renderer/controller within B+, plus various helpers.

BplusApp.GUI.GuiTextType

Encapsulates a Dear ImGUI text editor.

Run the GUI with gui_text!() and get the current string with string(). Update the value externally with update!().

BplusApp.GUI.Service_GUIType

A CImGui (Dear IMGUI) backend, implemented as a B+ GL Service.

To use a GL.Texture or GL.View in CImGui, wrap it with gui_tex_handle().

Base.stringMethod

Gets the current value of a GUI-edited text.

BplusApp.GUI.gui_next_window_spaceFunction

Sizes the next CImGui window in terms of a percentage of the actual window's size, optionally with a pixel-space border padding it inwards.

BplusApp.GUI.gui_tab_itemFunction

Defines one tab, as part of a tab bar (see gui_tab_views()). Returns whether the tab view was open.

BplusApp.GUI.gui_tab_viewsFunction

Defines a set of tabs, and the contents underneath each. Within this block you can create new tab views as follows:

gui_tab_views("Tab1") do
    # GUI code for the tab's contents
end
gui_tab_views("Tab2") do
    # GUI code for the other tab's contents
end
BplusApp.GUI.gui_text!Method

Displays a Dear ImGUI widget for the given text editor. Returns whether the text has been edited on this frame.

BplusApp.GUI.gui_windowMethod

Nests some GUI code within a window. Extra arguments get passed directly into CImGui.Begin(). Returns the output of your code block, or nothing if the UI was culled.

BplusApp.GUI.gui_with_item_widthMethod

Executes some GUI code with a different item width.

See: https://pixtur.github.io/mkdocs-for-imgui/site/api-imgui/ImGui–Dear-ImGui-end-user/#PushItemWidth

  • 0.0f: width in pixels

  • <0.0f: align xx pixels to the right of window (so -1.0f always align width to the right side)
  • ==0.0f: default to ~⅔ of windows width
BplusApp.GUI.gui_with_nested_idMethod

Executes some GUI code with the given ID data (ptr, String, Integer, or begin + end Strings) pushed onto the stack.

BplusApp.GUI.gui_within_foldMethod

Executes some GUI within a fold (what Dear ImGUI calls a 'tree node'). If it's open, returns the output of your lambda; otherwise returns nothing.

BplusApp.GUI.gui_within_groupMethod

Groups widgets together for placement within larger layouts (such as a vertical group within a horizontal line).

BplusApp.GUI.service_GUI_end_frameMethod
Call at the end of a frame to render the GUI
  into the current framebuffer (presumably the screen).
Must be preceded by a corresponding call to `service_GUI_start_frame()`.
BplusApp.Input.create_buttonMethod
Creates a new button (throwing an error if it already exists), with the given inputs.
Returns the source list of button inputs, so you can further configure them at will.
All button inputs will be OR-ed together.
BplusApp.Input.get_button_inputsMethod
Gets the source list of button inputs for a named button.
You can modify this list at will to reconfigure the button.
Throws an error if the button doesn't exist.
BplusApp.GL.LEGAL_APPARENT_SIMPLEVIEW_FORMATSConstant

Maps every possible format for a simple texture view to its type-name in the shader.

Comes from this reference: https://registry.khronos.org/OpenGL-Refpages/gl4/html/glBindImageTexture.xhtml#Description

BplusApp.GL.MipFiltersType

Mip-maps can be sampled in the same way as neighboring pixels, or turned off entirely

BplusApp.GL.PixelIOValueType

Types which can be uploaded to/downloaded from a texture. One-component texture data can be a number or a Vec1; higher-component data must be a Vec.

BplusApp.GL.SUPPRESS_SPAMMY_LOGSConstant

By default, when using @check_gl_logs, a very annoying spammy message about buffers is suppressed. Disable that by setting this var to false.

BplusApp.GL.UniformType

Acceptable types of data for set_uniform() and set_uniforms() (note that buffers are handled separately)

BplusApp.GL.AbstractOglBlockType

Some kind of bitstype data, laid out in a way that OpenGL/GLSL can understand. While the structs themselves are immutable, they are backed by a mutable array so you can set their properties.

To pass it into a C function, wrap it with a Ref() call. To create an array of your block type T, construct StaticBlockArray with either StaticBlockArray{T}(bytes::AbstractVector{UInt8}) or StaticBlockArray{N, T}().

For simplicity, the buffer's bytes will always be filled with 0xAA by default, and the == operator is defined to do fast bytewise comparison.

BplusApp.GL.AbstractResourceType

A mutable OpenGL object which cannot be copied, and whose fields should not be set directly. Resources should be created within a Context, and can be cleaned up with Base.close(). The resource's OpenGL handle must be set to a null value after the resource is closed, so that it's easy to see if a resource has been destroyed.

BplusApp.GL.AbstractServiceType

A Context-wide mutable singleton, providing some utility for users. It is highly recommended to define a service with @bp_service.

BplusApp.GL.BlendState_Type

A way of blending new rendered pixels onto an existing image. The T type parameter determines the type of the blend data, which is important when using a 'Constant' blend factor.

BplusApp.GL.BufferType

A contiguous block of memory on the GPU, for storing any kind of data. Most commonly used to store mesh vertices/indices, or other arrays of things.

To initialize, you can provide its byte-size or some data to upload (which passes through buffer_data_convert()). For help with uploading a whole data structure to a buffer, see @std140 and @std430.

UNIMPLEMENTED: Instances can be "mapped" to the CPU, allowing you to write/read them directly as if they were a plain C array. This is often more efficient than setting the buffer data the usual way, e.x. you could read the mesh data from disk directly into this mapped memory.

BplusApp.GL.ContextType

The OpenGL context, which owns all state and data, including the GLFW window it belongs to. This type is a per-thread singleton, because OpenGL only allows one active context per thread. Like the other GL resource objects, you can't set the fields of this struct; use the provided functions to change its state.

It's highly recommended to wrap a context with bp_gl_context(), as otherwise Julia may juggle the Task running that context across threads, which breaks OpenGL.

BplusApp.GL.DeviceMethod

Reads the device constants from OpenGL using the current context

BplusApp.GL.MeshType

A collection of vertices (and optionally indices), representing geometry that the GPU can render. The vertex data and indices are taken from a set of Buffers. This is what OpenGL calls a 'VAO' or 'VertexArrayObject'. Most data will be per-'vertex', but some data can be per-instance, for instanced rendering.

BplusApp.GL.Service_SamplerProviderType

Samplers can be re-used between textures, so you only need to define a few sampler objects across an entire rendering context.

This service provides re-usable sampler objects for all possible configurations of sampler parameters.

BplusApp.GL.Service_ViewDebuggingType

Provides a Context service in debug builds which checks that a program's Views are properly activated before use. Note that this can't catch them in all circumstances! View handles are just a plain uint64, so you can sneak them into a shader in all sorts of ways. In particular, reading the handle from mesh data isn't something this service can notice.

BplusApp.GL.ShaderBlockDataType

Information about a specific Program buffer block (a.k.a. UBO/SSBO).

The name is not stored because it will be used as the key for an instance of this struct.

BplusApp.GL.SimpleViewParamsType

The parameters defining a 'simple' View.

Note that mip levels start at 1, not 0, to reflect Julia's 1-based indexing convention.

The 'layer' field allows you to pick a single layer of a 3D or cubemap texture, causing the view to act like a 2D texture.

The 'apparent_format' field changes how the texture is interpreted in the shader; it defaults to the texture's actual format.

BplusApp.GL.StencilResultType

What happens to the stencil buffer when a fragment is going through the stencil/depth tests

BplusApp.GL.StencilTestType

A predicate/filter evaluated for the stencil buffer, to control which pixels can be drawn into.

BplusApp.GL.TargetType

Creates a target with no outputs, which acts like it has the given size and number of layers.

BplusApp.GL.TargetType

Creates a target with the given color output, and generates a corresponding depth/stencil buffer. By default, the depth/stencil will be a TargetBuffer and not a Texture. The Target is not responsible for cleaning up the color texture, only the new depth/stencil buffer.

BplusApp.GL.TargetType

A destination for rendering, as opposed to rendering into the screen itself. Has a set of Textures attached to it, described as TargetOutput instances, which receive the rendered output.

OpenGL calls these "framebuffers".

The full list of attached textures is fixed after creation, but the specific subset used in rendering can be configured with target_configure_fragment_outputs().

BplusApp.GL.TargetMethod

Creates a depth-/stencil-only target, with no color attachments. The target is not responsible for cleaning them up.

BplusApp.GL.TargetMethod

Creates a target with the given output size, format, and mip levels, using a single 2D color Texture and a Texture or TargetBuffer for depth/stencil.

BplusApp.GL.TargetMethod

Creates a Target which uses already-existing texture[s]. The Target is not responsible for cleaning them up.

BplusApp.GL.TargetBufferType

Something like a texture, but highly optimized for rendering into it and not much else – you cannot easily manipulate or sample its data. The OpenGL term for this is "renderbuffer".

The main use for this is as a depth or stencil buffer, any time you don't care about sampling depth/stencil data (it can still be used for depth/stencil tests, just not sampled in shaders).

This is an AbstractResource, but it's managed internally by Target instances. You probably won't interact with it much yourself.

BplusApp.GL.TargetOutputType

A reference to part or all of a texture, to be attached to a Target and rendered into.

You can attach any texture at any mip level. In the case of 3D and cubemap textures, you can optionally attach a specific "layer" of that texture. The layers of a cubemap texture are its faces, ordered in the usual way. The layers of a 3D texture are its Z-slices.

Note that mip levels and layers are counted starting at 1, to be consistent with Julia's 1-based convention.

BplusApp.GL.TargetUnsupportedExceptionType

Thrown if the graphics driver doesn't support a particular combination of texture attachments. This is the only Target-related error that can't be foreseen, so it's given special representation; the others are thrown with error().

BplusApp.GL.TexSubsetType

Parameters for specifying a subset of data in an N-dimensional texture. Note that mips and pixel ranges follow the 1-based Julia convention, not the 0-based convention of OpenGL.

BplusApp.GL.TextureType

Some kind of organized color data which can be 'sampled'. This includes regular images, as well as 1D and 3D textures and 'cubemaps'. Note that mip levels are counted from 1, not from 0, to match Julia's convention.

BplusApp.GL.TextureMethod

Creates a texture similar to the given one, but with a different format. The new texture's data will not be initialized to anything.

BplusApp.GL.UniformDataType

Information about a specific Program uniform. A uniform can be an array of its data type; if the uniform is an array of structs, each UniformData instance will be about one specific field of one specific element.

The name is not stored because it will be used as the key for an instance of this struct.

BplusApp.GL.VSInput_FVector_FixedType

Vertex data that comes in as a vector of fixed-point decimals (16 integer bits, 16 fractional bits) and gets casted into float32

BplusApp.GL.VSInput_FVector_FromIntType

Vertex data that comes in as some kind of integer vector, and gets interpreted as 32-bit float vector.

If 'normalized' is true, then the values are converted from the integer's range to the range [0, 1] or [-1, 1]. Otherwise, the values are simply casted to float.

BplusApp.GL.VSInput_FVector_Packed_A2_BGR10Type

Vertex data that comes in as a 32-bit uint, and gets interpreted as an RGBA vector of 32-bit floats. The uint stores the components as integers, optionally signed and/or normalized: 2 bits for Alpha/W, 10 bits for Blue/Z, 10 bits for Green/Y, then 10 bis for Red/X.

The integer values for each component are either normalized to the 0-1 range, or simply casted to float.

BplusApp.GL.VSInput_FVector_Packed_UF_B10_G11_R11Type

Vertex data that comes in as a 32-bit uint, and gets interpreted as an RGB vector of 32-bit floats. The uint stores 3 unsigned floats, in order:

  1. 10 bits for Blue/Z
  2. 11 bits for Green/Y
  3. 11 more for Red/X

#TODO: How many bits for mantissa vs exponent?

BplusApp.GL.VertexDataSourceType

A reference to an array of data stored in a Buffer. The elements of the array could be numbers, vectors, matrices, or entire structs.

BplusApp.GL.ViewType

Some kind of view into a texture's data, which can be passed into a shader as a simple 64-bit integer handle, or one of the opaque sampler types. Assumes the OpenGL extension ARB_bindless_texture. This is much easier to manage than the old-school texture units and binding. You can even pass an array of unrelated textures, as an array of uint64 (or uvec2)!

You should never create these yourself; they're generated by their owning Texture.

IMPORTANT: you must view_activate() an instance before it's used in a shader, and it should be view_deactivate()-d when not in use to free up GPU resources for other render passes. Using an inactive handle leads to Undefined Behavior (a.k.a. wacky crashes).

The lifetime of this resource is managed by its owning Texture, which is why this type does not inherit from AbstractResource.

BplusApp.GL.ViewMethod

Creates a new simple view on a texture.

IMPORTANT: users shouldn't ever be creating these by hand; they should come from the Texture interface.

BplusApp.GL.ViewMethod

Creates a new sampled view from the given texture and optional sampler. If no sampler is given, the texture's default sampler settings are used.

IMPORTANT: users shouldn't ever be creating these by hand; they should come from the Texture interfae.

Base.splitMethod

Pulls the depth and stencil values out of a packed texture pixel

BplusApp.GL.ON_OGL_MSGFunction

The global callback for OpenGL errors and log messages. Only raised if the context is created in debug mode. You can freely set this to point to a different function.

BplusApp.GL.VSInput_FVectorMethod

Creates a type for an integer vector that get casted or normalized into a float vector in the shader

BplusApp.GL.block_byte_sizeMethod

Gets the total byte-size of the given struct (or array property), including padding. Use this instead of sizeof().

For convenience, falls through to sizeof() for non-block data types.

BplusApp.GL.block_modeMethod

Gets the layout type of a struct (or struct type). An example return value is OglBlock_std140

BplusApp.GL.block_simple_typeMethod

Block structs (and block arrays) have a type parameter for the kind of array backing their data. This function strips that parameter from the type.

BplusApp.GL.bp_gl_contextMethod

Runs the given code on a new OpenGL context, ensuring the context will get cleaned up.

This call blocks as if the context runs on this thread/task, but for technical reasons it actually runs on a separate task. The reason is that Julia tasks can get shifted to different threads unless you explicitly mark them as sticky.

BplusApp.GL.bp_glsl_strMethod

Compiles a string with special formatting into a Program. For info on how to format it, refer to the docs for @bp_glsl_str (the string macro version).

To debug-log the generated shaders, pass a stream to 'debug_out'.

BplusApp.GL.clear_tex_colorFunction

Clears a color texture to a given value.

The dimensionality of the subset parameter must match the dimensionality of the texture. Cubemaps textures are 3D, where Z spans the 6 faces.

BplusApp.GL.clear_tex_depthMethod

Clears a depth texture to a given value.

The dimensionality of the subset parameter must match the dimensionality of the texture. Cubemaps textures are 3D, where Z spans the 6 faces.

BplusApp.GL.clear_tex_depthstencilFunction

Clears a depth/stencil hybrid texture to a given value with 24 depth bits and 8 stencil bits.

The dimensionality of the subset parameter must match the dimensionality of the texture. Cubemaps textures are 3D, where Z spans the 6 faces.

BplusApp.GL.clear_tex_pixelsMethod

Clears a texture to a given value, without knowing yet what kind of texture it is.

The dimensionality of the subset parameter must match the dimensionality of the texture. Cubemaps textures are 3D, where Z spans the 6 faces.

BplusApp.GL.clear_tex_stencilFunction

Clears a stencil texture to a given value.

The dimensionality of the subset parameter must match the dimensionality of the texture. Cubemaps textures are 3D, where Z spans the 6 faces.

BplusApp.GL.compile_programFunction

Run the given compile job. Returns the new program's handle, or a compile error message. Also optionally updates the compiler 'cached_binary' field to contain the program's up-to-date binary blob.

BplusApp.GL.compile_stageMethod

Internal helper that compiles a single stage of a shader program. Returns the program's handle, or an error message.

BplusApp.GL.convert_pixelMethod

Converts an incoming pixel of an ImageIO image into GPU-friendly pixel data of the given type

BplusApp.GL.copy_bufferMethod

Copies data from one buffer to another. By default, copies as much data as possible.

BplusApp.GL.copy_tex_pixelsFunction

Copies between two textures.

The operation is comparable to memcpy(), in that the bit data is directly transferred over without casting or normalizing. The only format requirement is that the bit size of a pixel is the same for each texture.

When copying between a compressed and uncompressed texture, the requirement is slightly different: the bit size of a block of the compressed texture must match the bit size of a pixel from the uncompressed texture.

For simplicity, the dest_min parameter can have more dimensions than the texture itself; extra dimensions are ignored. As with other texture operations, cubemaps are treated as 3D with 6 Z-slices.

BplusApp.GL.count_attribsMethod

Gets the number of OpenGL vertex attributes that are needed for this data type (i.e. 1 for a vector, or the number of rows in a matrix).

BplusApp.GL.count_componentsMethod

Gets the number of components in this type's OpenGL vertex attributes (i.e. the length of a vector, or the number of columns in a matrix).

BplusApp.GL.count_mesh_verticesMethod

Gets the maximum number of vertices this mesh can offer for rendering, based only on vertex data (not index data).

BplusApp.GL.get_block_countMethod

Gets the number of blocks along each axis for a block-compressed texture of the given size and format

BplusApp.GL.get_block_sizeMethod

Gets the width/height/depth of each block of pixels in a block-compressed texture of the given format

BplusApp.GL.get_buffer_dataFunction

Gets a buffer's data and writes it to the given pointer. Optionally uses a subset of the buffer's bytes.

BplusApp.GL.get_cube_dirMethod

Converts a UV coordinate on a cubemap face to a 3D cubemap vector. NOTE: be careful with your UV computation! If your cubemap faces are 512x512 pixels, then the first pixel should have UV 0.5/512, and the last pixel should have UV 511.5/512.

BplusApp.GL.get_from_oglMethod

Helper function that calls OpenGL, reads N elements of data into a buffer, then returns that buffer as an NTuple.

BplusApp.GL.get_native_ogl_enumMethod

Gets the OpenGL enum value for the actual format that this machine's GPU will use to represent the given format, on the given type of texture. Often-times, the graphics driver will pick a more robust format (e.x. r3g3b2 is almost always upgraded to r5g6b5). If no texture type is given, then the format will be used in a TargetBuffer. Returns 'nothing' if the format is invalid for the given texture type.

BplusApp.GL.get_ogl_enumFunction

Gets the OpenGL enum value representing this format, or 'nothing' if the format isn't valid.

BplusApp.GL.get_ogl_enumMethod

Gets the OpenGL enum for a set of channels being uploaded to a texture. Needs to know whether the texture has an int/uint format.

BplusApp.GL.get_pixel_bit_sizeFunction

Gets the size (in bits) of each pixel for the given texture format. If the format is block-compressed, this will provide an accurate answer by dividing the block's bit-size by the number of pixels in that block.

BplusApp.GL.get_subset_rangeMethod

Calculates the subset of a texture to use. The full_size parameter should have the same dimensionality as the subset; for convenience it can have more and those extra dimensions will be ignored.

BplusApp.GL.get_tex_colorMethod

Gets the data for a color texture and writes them into the given array. The dimensionality of the array and subset parameter must match the dimensionality of the texture. Cubemaps textures are 3D, where Z spans the 6 faces.

BplusApp.GL.get_tex_depthMethod

Gets the data for a depth texture and writes them into the given array. The dimensionality of the array and subset parameter must match the dimensionality of the texture. Cubemaps textures are 3D, where Z spans the 6 faces.

BplusApp.GL.get_tex_depthstencilMethod

Gets the data for a depth-stencil hybrid texture and writes them into the given array. The dimensionality of the array and subset parameter must match the dimensionality of the texture. Cubemaps textures are 3D, where Z spans the 6 faces.

BplusApp.GL.get_tex_pixelsMethod

Gets a texture's pixels, figuring out dynamically whether they're color, depth, etc. For specific overloads based on texture format, see get_tex_color(), get_tex_depth(), etc, respectively.

The dimensionality of the array and subset parameter must match the dimensionality of the texture. Cubemaps textures are 3D, where Z spans the 6 faces.

BplusApp.GL.get_tex_stencilFunction

Gets the data for a stencil texture and writes them into the given array. The dimensionality of the array and subset parameter must match the dimensionality of the texture. Cubemaps textures are 3D, where Z spans the 6 faces.

BplusApp.GL.get_viewFunction

Gets a view of this texture, using the given sampler (or the texture's built-in sampler settings).

BplusApp.GL.get_viewMethod

Gets a view of this texture's pixels without sampling, which allows for other uses like writing to the pixels.

BplusApp.GL.gl_catch_up_beforeMethod

Inserts a memory barrier in OpenGL so that the given operations definitely happen after all shader operations leading up to this call.

For example, if you ran a compute shader to modify a texture and are about to sample from it, call gl_catch_up_before(SyncTypes.texture_samples).

This is only needed for incoherent operations. For example, you do not need a barrier after rendering into a Target.

BplusApp.GL.gl_catch_up_renders_beforeMethod

Inserts a memory barrier in OpenGL, like gl_catch_up_before(), but specifically for the subset of the framebuffer that was just rendered to, in preparation for more fragment shader behavior.

The actions you pass in must be a subset of MemoryActions.USE_IN_FRAGMENT_SHADERS.

BplusApp.GL.gl_execute_everythingMethod

Waits until OpenGL is done executing all previously-issued render commands.

This has limited usefulness, but here are a few scenarios:

  • You are sharing resources with another context (not natively supported in B+ anyway), and must ensure the shared resources are done being written to by the source context.
  • You are tracking down a driver bug or tricky compute bug, and want to invoke this after every command to track down the one that crashes.
  • You are working around a driver bug.
BplusApp.GL.gl_flush_texture_writes_in_placeMethod

If you want to sample from the same texture you are rendering to, which is legal as long as the read area and write area are distinct, you should call this afterwards to ensure the written pixels can be read.

This helps you ping-pong within a single target rather than having to set up two of them.

BplusApp.GL.glsl_declFunction

Emits declarations of the fields of an OpenGL struct or block, based on the Julia struct you created with @std140 or @std430

BplusApp.GL.is_colorFunction

Is the given format a color type (as opposed to depth and/or stencil)?

BplusApp.GL.is_destroyedMethod

Gets whether a resource has already been destroyed. By default, checks if its OpenGL handle is null.

BplusApp.GL.is_signedFunction

Does the given format have signed components, or unsigned components? NOTE that for color formats, this is primarily about the RGB components; the Alpha may sometimes be in a different format.

BplusApp.GL.process_tex_subsetMethod

Processes data representing a subset of a texture, checking it for errors and returning the final pixel range and mip-level.

For simplicity, the returned range is always 3D. Cubemap textures use Z to represent the cube faces.

BplusApp.GL.pull_gl_logsMethod

Pulls all unread event logs from the current OpenGL context, in chronological order. Only works if the context was started in debug mode.

BplusApp.GL.raise_ogl_msgMethod

Raises the global OpenGL message-handling callback with some message. This must be called from a thread with an active OpenGL context.

BplusApp.GL.refreshMethod

You can call this after some external tool messes with OpenGL state, to force the Context to read the new state and update itself. However, keep in mind this function is pretty slow!

BplusApp.GL.remove_index_dataMethod

Removes any existing index data from this Mesh, so that its vertices are no longer indexed. Does nothing if it already wasn't indexed.

BplusApp.GL.render_meshMethod

Renders a mesh using the currently-active shader program.

IMPORTANT NOTE: All counting/indices follow Julia's 1-based convention. Under the hood, they will get converted to 0-based for OpenGL.

You can manually disable the use of indexed rendering for an indexed mesh by passing 'indexed_params=nothing'.

You can configure one (and only one) of the following optional features:

  1. Instanced rendering (by setting 'instances' to a range like IntervalU(1, N))
  2. Multi-draw (by setting 'elements' to a list of ranges, instead of a single range).
  3. An optimization hint (by setting 'knownvertexrange') about what vertices are actually going to be drawn with indexed rendering, to help the GPU driver optimize memory usage.

NOTE: There is one small, relatively-esoteric OpenGL feature that is not included (adding it would probably require separating this function into 3 different ones): indexed multi-draw could use different index offsets for each subset of elements.

BplusApp.GL.set_scissorMethod

Changes the area of the screen where rendering can happen, in terms of pixels (using 1-based indices). Any rendering outside this view is discarded. Pass 'nothing' to disable the scissor. The 'max' corner is inclusive.

BplusApp.GL.set_stencil_resultMethod

Sets the stencil operations to use on front-faces and back-faces, separately, based on the stencil and depth tests.

BplusApp.GL.set_stencil_write_maskMethod

Sets the bitmasks which enable/disable bits of the stencil buffer for writing. Applies different values to front-faces and back-faces.

BplusApp.GL.set_storage_blockFunction

set_storage_block(::Buffer, ::Int; byte_range=[full buffer])

Sets the given buffer to be used for one of the globally-available Shader Storage Block (a.k.a. "SSBO") slots.

set_storage_block(::Program, ::String, ::Int)

Sets a program's Shader-Storage Block (a.k.a. "SSBO") to use the given global slot, which can be assigned a Buffer with the other overload.

set_storage_block(::Int)

Clears the binding for the given global SSBO slot.

NOTE: Indices and byte ranges are 1-based!

BplusApp.GL.set_tex_colorMethod

Sets the data for a color texture. The dimensionality of the input array and subset parameter must match the dimensionality of the texture. Cubemaps textures are 3D, where Z spans the 6 faces.

BplusApp.GL.set_tex_depthMethod

Sets the data for a depth texture. The dimensionality of the input array and subset parameter must match the dimensionality of the texture. Cubemaps textures are 3D, where Z spans the 6 faces.

BplusApp.GL.set_tex_depthstencilMethod

Sets the data for a depth/stencil hybrid texture. The dimensionality of the input array and subset parameter must match the dimensionality of the texture. Cubemaps textures are 3D, where Z spans the 6 faces.

BplusApp.GL.set_tex_pixelsMethod

Sets a texture's pixels, figuring out dynamically whether they're color, depth, etc. For specific overloads based on texture format, see set_tex_color(), set_tex_depth(), etc respectively.

The dimensionality of the input array and subset parameter must match the dimensionality of the texture. Cubemaps textures are 3D, where Z spans the 6 faces.

BplusApp.GL.set_tex_stencilFunction

Sets the data for a stencil texture. The dimensionality of the input array and subset parameter must match the dimensionality of the texture. Cubemaps textures are 3D, where Z spans the 6 faces.

BplusApp.GL.set_uniformFunction

set_uniform(::Program, ::String, ::T[, array_index::Int])

Sets a program's uniform to the given value.

If the uniform is an array, you must provide a (1-based) index.

If the uniform is a struct or array of structs, you must name the individual fields/elements, e.x. set_uniform(p, "my_lights[0].pos", new_pos). This naming is 0-based, not 1-based, unfortunately.

BplusApp.GL.set_uniform_blockFunction

set_uniform_block(::Buffer, ::Int; byte_range=[full buffer])

Sets the given buffer to be used for one of the globally-available Uniform Block (a.k.a. "UBO") slots.

set_uniform_block(::Program, ::String, ::Int)

Sets a program's Uniform Block (a.k.a. "UBO") to use the given global slot, which can be assigned a Buffer with the other overload.

set_uniform_block(::Int)

Clears the binding for the given global UBO slot.

NOTE: Indices and byte ranges are 1-based!

BplusApp.GL.set_uniformsFunction

set_uniforms(::Program, ::String, ::AbstractVector{T}[, dest_offset=0]) set_uniforms(::Program, ::String, T, ::Contiguous{T}[, dest_offset=0])

Sets a program's uniform to the given value.

You must provide an array of contiguous values. If the contiguous array is more nested than a mere Array{T}, Vec{N, T}, NTuple{N, T}, etc (e.x. Vector{NTuple{5, v2f}}), then you must also pass the T value to remove ambiguity. If you are passing an array of Texture/View instances, rather than raw Ptr_Views, then the collection does not need to be contiguous.

If the uniform is a struct or array of structs, you must name the individual fields/elements, e.x. set_uniform(p, "my_lights[0].pos", new_pos). This naming is 0-based, not 1-based, unfortunately.

BplusApp.GL.set_viewportMethod

Changes the area of the screen which rendering outputs to, in terms of pixels (using 1-based indices). By default, the min/max corners of the render are the min/max corners of the screen, but you can set this to render to a subset of the whole screen. The max corner is inclusive.

BplusApp.GL.supported_pixel_io_typesMethod

The set of all number types which can be used for pixel upload/download. Does not include special packed types like Depth24uStencil8.

BplusApp.GL.target_activateMethod

Sets a Target as the active one for rendering. Pass nothing to render directly to the screen instead.

BplusApp.GL.target_clearFunction

Clears a Target's hybrid depth/stencil attachment. This is more efficient than clearing depth and stencil separately.

See above for important details about clearing depth and clearing stencil.

BplusApp.GL.target_clearFunction

Clears a Target's color attachment.

If the color texture is uint, then you must clear to a vRGBAu. If the color texture is int, then you must clear to a vRGBAi. Otherwise, the color texture is float or normalized_[u]int, and you must clear to a vRGBAf.

The index is not the color attachment itself but the render slot, a.k.a. the fragment shader output. For example, if you previously called target_configure_fragment_outputs(t, [ 3, nothing, 1]), and you want to clear color attachment 1, pass the index 3.

BplusApp.GL.target_clearFunction

Clears a Target's stencil attachment. Note that this is legal on a hybrid depth-stencil buffer; the depth values will be left alone.

The clear value will be casted to UInt8.

Watch your Context's stencil write mask carefully! If some bits are disabled from writing, then this clear operation wouldn't affect those bits.

By default, there is a debug check to prevent the stencil write mask from surprising you. If the masking behavior is desired, you can disable the check by passing false.

BplusApp.GL.target_clearMethod

Clears a Target's depth attachment. Note that this is legal on a hybrid depth-stencil buffer; the stencil values will be left alone.

The clear value will be casted to Float32 and clamped to 0-1.

Be sure that depth writes are turned on in the Context! Otherwise this would become a no-op, and an error may be thrown.

BplusApp.GL.target_configure_fragment_outputsMethod

Selects a subset of a Target's color attachments to use for rendering, by their (1-based) index.

For example, passing [5, nothing, 1] means that the fragment shader's first output goes to color attachment 5, the third output goes to color attachment 1, and all other outputs (i.e. 2 and 4+) are safely discarded.

BplusApp.GL.tex_sizeMethod

Gets a type-unstable texture size based on its type.

Cube-maps are treated as 3D with a Z-size of 6.

1D textures are returned as 1D vectors for consistency.

BplusApp.GL.view_activateFunction

Tells the GPU to activate this handle so it can be used in a shader. Simple Views are activated with an access type (read, write, read_write).

BplusApp.GL.view_deactivateMethod

Tells the GPU to deactivate this handle, potentially freeing up resources for other data to be loaded.

BplusApp.GL.with_blendingMethod

Executes some code with the given Alpha blend mode, then restores the original setting. Optionally takes an explicit context if you have the reference to it already.

BplusApp.GL.with_blendingMethod

Executes some code with the given Color+Alpha blend mode, then restores the original setting. Optionally takes an explicit context if you have the reference to it already.

BplusApp.GL.with_blendingMethod

Executes some code with the given Color+Alpha blend mode, then restores the original setting. Optionally takes an explicit context if you have the reference to it already.

BplusApp.GL.with_blendingMethod

Executes some code with the given Color blend mode, then restores the original setting. Optionally takes an explicit context if you have the reference to it already.

BplusApp.GL.with_color_writesMethod

Executes some code with the given color write mask, then restores the original setting. Optionally takes an explicit context if you have the reference to it already.

BplusApp.GL.with_cullingMethod

Executes some code with the given cull state, then restores the original setting. Optionally takes an explicit context if you have the reference to it already.

BplusApp.GL.with_depth_testMethod

Executes some code with the given depth test, then restores the original setting. Optionally takes an explicit context if you have the reference to it already.

BplusApp.GL.with_depth_writesMethod

Executes some code with the given depth write flag, then restores the original setting. Optionally takes an explicit context if you have the reference to it already.

BplusApp.GL.with_render_stateMethod

Executes some code with the given all render state, then restores the original setting. Optionally takes an explicit context if you have the reference to it already.

BplusApp.GL.with_scissorMethod

Executes some code with the given scissor rect, then restores the original setting. Optionally takes an explicit context if you have the reference to it already.

BplusApp.GL.with_stencil_resultMethod

Executes some code with the given per-face stencil results, then restores the original setting. Optionally takes an explicit context if you have the reference to it already.

BplusApp.GL.with_stencil_resultMethod

Executes some code with the given stencil result, then restores the original setting. Optionally takes an explicit context if you have the reference to it already.

BplusApp.GL.with_stencil_result_backMethod

Executes some code with the given back-face stencil result, then restores the original setting. Optionally takes an explicit context if you have the reference to it already.

BplusApp.GL.with_stencil_result_frontMethod

Executes some code with the given front-face stencil result, then restores the original setting. Optionally takes an explicit context if you have the reference to it already.

BplusApp.GL.with_stencil_testMethod

Executes some code with the given per-face stencil tests, then restores the original setting. Optionally takes an explicit context if you have the reference to it already.

BplusApp.GL.with_stencil_testMethod

Executes some code with the given stencil test, then restores the original setting. Optionally takes an explicit context if you have the reference to it already.

BplusApp.GL.with_stencil_test_backMethod

Executes some code with the given back-face stencil test, then restores the original setting. Optionally takes an explicit context if you have the reference to it already.

BplusApp.GL.with_stencil_test_frontMethod

Executes some code with the given front-face stencil test, then restores the original setting. Optionally takes an explicit context if you have the reference to it already.

BplusApp.GL.with_stencil_write_maskMethod

Executes some code with the given per-face stencil write mask, then restores the original setting. Optionally takes an explicit context if you have the reference to it already.

BplusApp.GL.with_stencil_write_maskMethod

Executes some code with the given stencil write mask, then restores the original setting. Optionally takes an explicit context if you have the reference to it already.

BplusApp.GL.with_stencil_write_mask_backMethod

Executes some code with the given back-faces stencil write mask, then restores the original setting. Optionally takes an explicit context if you have the reference to it already.

BplusApp.GL.with_stencil_write_mask_frontMethod

Executes some code with the given front-faces stencil write mask, then restores the original setting. Optionally takes an explicit context if you have the reference to it already.

BplusApp.GL.with_viewportMethod

Executes some code with the given viewport rect, then restores the original setting. Optionally takes an explicit context if you have the reference to it already.

BplusApp.GL.@bp_glsl_strMacro

Compiles an OpenGL Program from a string literal containing the various shader stages. To compile a non-literal string in the same way, call bp_glsl_str(shader_string).

The code at the top of the shader is shared between all shader stages. The Vertex Shader starts with the custom command #START_VERTEX. The Fragment Shader starts with the custom command #START_FRAGMENT. The optional Geometry Shader starts with the custom command #START_GEOMETRY.

For a Compute Shader, use #START_COMPUTE.

BplusApp.GL.@bp_serviceMacro

Defines a B+ Context service with a standardized interface. Services are a mutable struct with the name Service_X, where X is the name you provide.

Example usage:

@bp_service Input(args...) begin
    # Some data that the service will hold:
    buttons::Dict{AbstractString, Any}
    axes::Dict{AbstractString, Any}
    current_scroll_pos::v2f
    # ... # [etc]

    # The service's initializer.
    INIT(a, b) = begin
        return new(a, b, zero(v2f)) # Provide values for the above fields
    end

    # The service's cleanup code.
    SHUTDOWN(service, is_context_closing::Bool) = begin
        close(service.some_file_handle)
        if !is_context_closing # Waste of time to destroy GL resources if the whole context is going away
            for tex in service.all_my_textures
                close(tex)
            end
        end
    end

    # If you want to be notified when the context refreshes,
    #    for example if outside OpenGL code ran and potentially changed OpenGL's state,
    #    you can define this:
    REFRESH(service) = begin
        service.last_rendered_program = glGetIntegerv(blah, blah)
    end

    # Custom functions for your service.
    # See below for info on how they are transformed into real functions.
    get_button(service, name) = service.buttons[name]
    add_button(service, name, value) = service.buttons[name] = value
end

The args... in the service name includes the following values:

  • force_unique makes the service a singleton across the entire Context, forbidding you from creating multiple ones and removing the need to pass the service in manually to every service function.
  • lazy makes the service initialize automatically (with no passed arguments) if it's retrieved before it's created.

Interface

The following functions are generated for you based on your service's name (here we assume you named it X, case-sensitive):

Startup/shutdown

  • service_X_init(args...) : Executes your defined INIT(args...) code, adds the service to the Context, and returns it. If you did not specify force_unique, then you may call this multiple times to create multiple service instances.
  • service_X_shutdown([service]) : Closes your service, executing your defined SHUTDOWN(service, is_context_closing) code. Called automatically on context close, but you may kill it early if you want, in which case the value of the second parameter will be false. If you specified force_unique, then you do not have to provide the service instance when calling.

Utility

  • service_X() : Gets the current service instance, assuming it's already been created. This function only exists if you specified force_unique.
  • service_X_exists() : Gets whether the service has already been created. This function only exists if you specified force_unique.

Custom

Any other functions you declared get generated basically as-is. The first argument must always be the service, and then if you specified force_unique, the user of your function omits that parameter when calling. For example, f(service, a, b) = a*b + service.z turns into f(a, b) if force_unique. You're encouraged, but not required, to name your functions in the same style as the others: service_X_f().

Notes

You can provide type parameters in your service name, in which case you must also pass them in when calling new in your INIT, and the service_X() getter will take those types as normal function parameters.

You can similarly provide type parameters in all functions, including special ones like INIT.

BplusApp.GL.@check_gl_logsMacro

A macro to help find OpenGL issues. Place it before or after each OpenGL call to detect the most recent errors.

By default, a very annoying spammy message about buffers is suppressed; disable this by setting GL.SUPPRESS_SPAMMY_LOGS to false.

BplusApp.GL.@ogl_handleMacro

Defines a primitive type representing an OpenGL handle. Think of this like a stronger version of type aliasing, which provides more type safety. The type will also have an empty constructor which creates a "null" value (usually 0 or -1).

BplusApp.GL.@render_state_wrapperMacro

Defines a function which sets some render state, executes a lambda, then restores the original render state.

There will be two overloads, one which takes an explicit Context and one which does not.

The signature you provide should not include the context or the lambda; those parameters are inserted automatically.

The doc-string will be generated with the help of the last macro parameter.

The function is automatically exported.

BplusApp.GL.@std140Macro

Generates a struct of OpenGL data, whose byte layout exactly follows the std140 standard in shader blocks.

The struct is backed by a mutable byte array, so you can get and set its properties. You can also nest @std140 structs within each other and they will be laid out as the GPU expects.

Sample usage:

@std140 struct MyInnerUniformBlock
    f::Float32
    bools::vb4
    position_array::StaticBlockArray{12, v3f}
end

@std140 struct MyOuterUniformBlock
    i::Int32 # Be careful; 'Int' in Julia means Int64
    items::StaticBlockArray{5, MyInnerUniformBlock}
    b::Bool
end

const MY_UBO_DATA = MyOuterUniformBlock(
    3,
    ntuple(i -> zero(MyInnerUniformBlock), 5),
    true
)
println("MyOuterUniformBlock takes up ", length(block_byte_array(MY_UBO_DATA)), " bytes, ",
          block_padding_size(MY_UBO_DATA), " of which is padding")
println("i is ", MY_UBO_DATA.i)

MY_UBO_DATA.i = 1122334455
println("Now i is ", MY_UBO_DATA.i)

# Upload the data to your GPU buffer:
set_buffer_data(my_ubo, MY_UBO_DATA)

# Download the data from your GPU buffer into a new or existing instance of the struct:
my_ubo_data = get_buffer_data(my_ubo, MyOuterUniformBlock)
get_buffer_data(my_second_ubo, my_ubo_data)
BplusApp.GL.@std430Macro

Generates a struct of OpenGL data, whose byte layout exactly follows the std430 standard in shader blocks.

The struct is backed by a mutable byte array, so you can get and set its properties. You can also nest @std430 structs within each other and they will be laid out as the GPU expects.

Sample usage:

@std140 struct MyInnerUniformBlock
    f::Float32
    bools::vb4
    position_array::StaticBlockArray{12, v3f}
end

@std430 struct MyOuterShaderStorageBlock
    i::Int32 # Be careful; 'Int' in Julia means Int64
    items::StaticBlockArray{5, MyInnerShaderStorageBlock}
    b::Bool
end

const MY_SSBO_DATA = MyOuterShaderStorageBlock(
    3,
    ntuple(i -> zero(MyInnerShaderStorageBlock), 5),
    true
)
println("MyOuterShaderStorageBlock takes up ", length(block_byte_array(MY_SSBO_DATA)), " bytes, ",
          block_padding_size(MY_SSBO_DATA), " of which is padding")
println("i is ", MY_SSBO_DATA.i)

MY_SSBO_DATA.i = 1122334455
println("Now i is ", MY_SSBO_DATA.i)

# Upload the data to your GPU buffer:
set_buffer_data(my_ssbo, MY_SSBO_DATA)

# Download the data from your GPU buffer into a new or existing instance of the struct:
my_ssbo_data = get_buffer_data(my_ssbo, MyOuterShaderStorageBlock)
get_buffer_data(my_second_ssbo, my_ssbo_data)
BplusApp.ModernGLbp.GLENUMMethod

Overload this method (with a Val(::UInt32) parameter) to change the name of specific GL constants