OpenGL::Sandbox::ResMan - Resource manager for OpenGL prototyping


version 0.120


  my $r= OpenGL::Sandbox::ResMan->default_instance;
  $r->path( $path );
  my $tex= $r->tex('foo');
  my $font= $r->font('default');


This object caches references to various OpenGL resources like textures and fonts. It is usually instantiated as a singleton from "default_instance" or from importing the $res variable from OpenGL::Sandbox. It pulls resources from a directory of your choice. Where possible, files get memory-mapped directly into the library that uses them, which should keep the overhead of this library as low as possible.

Note that you need to install OpenGL::Sandbox::V1::FTGLFont in order to get font support, currently. Other font providers might be added later.



Standard Moo constructor. All attributes may be initialized here.


Return a global instance which uses the current directory as "path".


Call this method to remove all current references to any resource. If this was the last reference to those resources, it will also garbage collect any OpenGL resources that had been allocated. The next access to any font or texture will re-load the resource from disk. Any manually-created named resources (that didn't come from disk or config) must be re-created.


Resouce Paths

The default file layout assumed by this module is a tree that looks like

  ./tex/          # textures
  ./tex/default   # file or symlink for default texture.  Required.
  ./font/         # fonts compatible with libfreetype
  ./font/default  # file or symlink for default font.  Required.
  ./shader/       # GLSL shaders with extension '.glsl', '.frag', or '.vert'
  ./data/         # raw data to be loaded into Buffer Objects

You can override these implied sub-paths with the following attributes:


Root path for all other path fragments


(alias for texture_path)


A plain string is interpreted as relative to path; an absolute path or path beginning with "." is used as-is. An empty string means it is identical to path.

  path => '/opt/myapp/resources',  # absolute path
  tex_path => 'tex',               # resolves as "/opt/myapp/resources/tex"
  tex_path => '',                  # resolves as "/opt/myapp/resources"
  tex_path => './tex',             # resolves as getcwd()."/tex"
  tex_path => '/tmp/foo',          # absolute path

Per-Resource Config

For each type of resource managed by this object, there is a config_* attribute which takes a hashref of configuration. Each named resource is configured by the matching entry in this hash at the time it is first used. Each config hash may also contain an element '*' which applies default configuration to every resource of this type.

  texture_config => {
    'ResourceName' => ...,
    '*' => ...

The values of the config are usually hashrefs of constructor arguments that get shallow-merged with arguments you pass to new_*, but may also be plain scalars indicating that this resource is an alias for some other name.

  'Resource1' => { ... },     # default constructor arguments for Resource1
  'Resource2' => 'Resource1', # Resource2 is an alias for Resurce1 

Several resource types also expect an entry for 'default', which gets returned on any request for a missing resource.

The namespace of each type of resource is independent. i.e. it is fine to have both a texture named "Foo" and a buffer named "Foo".


Configuration for "new_texture", constructing OpenGL::Sandbox::Texture.

Example texture_config:

    '*'     => { wrap_s => GL_CLAMP,  wrap_t => GL_CLAMP  }, # default settings
    default => { filename => 'foo.png' },                    # texture named "default"
    tile1   => { wrap_s => GL_REPEAT, wrap_t => GL_REPEAT },
    blocky  => { mag_filter => GL_NEAREST },
    alias1  => 'tile1',

Existence of images in the texture directory implies default entries in this config. For example, if you have


it has the implied effect of

    a => { filename => 'a.png' },
    b => { filename => 'b.rgb' },
    c => { filename => 'c.bgr' },

in addition to whatever other settings you supplied for that name.


Alias for texture_config


If you have texture files with the same base name and different extensions (such as original image formats and derived ".png" or ".rgb") this resolves which image file you want to load automatically for tex("basename"). Default is to load ".bgr", else ".rgb", else ".png"


Configuration for "new_buffer", constructing OpenGL::Sandbox::Buffer.

    '*'           => { type => GL_VERTEX_ARRAY },
    triangle_data => { data => pack('f*', 1,1, 2,1, 2,-1, ...) }

Buffer filenames can also be implied by a file in the "data_path" directory, per the same rules described in "texture_config".


Configuration for "new_vertex_array", constructing OpenGL::Sandbox::VertexArray.

    my_triangles => {
      buffer => 'triangle_data',
      attributes => { pos => { size => 2, type => GL_FLOAT } }

Vertex Arrays must be configured; there is currently not a file format for them.


Alias for vertex_array_config


Configuration for "new_shader", constructing OpenGL::Sandbox::Shader.

    '*'          => { type => GL_FRAGMENT_SHADER },
    aurora       => { filename => 'aurora.frag' },
    vpassthrough => { filename => 'vtx-pass.vert', type => GL_VERTEX_SHADER },

Shaders are also implied by the presence of a file in the "shader_path" directory, per the same rules described in "texture_config".


Configuration for "new_program", constructing OpenGL::Sandbox::Program.

    '*'    => { shaders => { vertex => 'vpassthrough', fragment => 'aurora' } },
    'demo' => { attr => { ... }, shaders => { vertex => 'special_vshader' } },

Programs are also implied by the presence shaders of the same name prefix. i.e. if you have shaders named "a.frag" and "a.vert", then it implies the existence of a program named "a" composed of those shaders.


Configures OpenGL::Sandbox::V1::FTGLFont. (distributed separately)

    '*'     => { face_size => 48 }, # default settings get applied to all configs
    3d      => { face_size => 64, type => 'FTExtrudeFont' },
    default => { face_size => 32, filename => 'myfont1' }, # font named 'default'
    myfont2 => 'myfont1',  # alias

Fonts are also implied by the presence of a file in the "font_path" directory, per the same rules described in "texture_config".



  my $tex= $res->texture( $name );
  my $tex= $res->tex( $name );     # handy alias
  my $tex= $res->load_texture( $name, %options ); # load from file
  my $tex= $res->new_texture( $name, %options );  # file not needed

Get a texture object. Textures can be configured, or implied by presence of image files in "tex_path", or both.


Return named texture, or load one with "load_texture".

The texture method has a feature that if you request a non-existent texture, it will return the texture named 'default' rather than throwing an exception. This operates on the assumption that you'd rather see a big visual cue about which texute is missing than to have your program crash from an exception. You still get the exception if you don't have a texture named 'default'.


Alias for texture


Load a texture, or throw an exception if there is no image file by that name.

It first checks for a file of no extension in "tex_path", which may be an image file, special "rgb" or "bgr" texture file, or symlink/hardlink to another file. Failing that, it checks for a file of that name with any file extension, and attempts to load them in whatever order they were returned.


Create a new texture object regardless of whether the filename exists. If the texture of this name was already created, it dies.

Buffer Objects

  my $buffer= $res->buffer( $name );
  my $buffer= $res->new_buffer( $name, %options );

Get a Buffer Object, either configured in buffer_config or loaded from data_path. Buffer objects require OpenGL version 2.0 or above.


Return an existing buffer object, or create one from "buffer_config". If the $name is not configured, this dies.


This creates a new buffer object by combining %options with any (optional) configuration for this name in "buffer_config". This dies if $name was already created.

Vertex Arrays

  my $vertex_array= $res->vertex_array( $name );
  my $vertex_array= $res->vao( $name );          # handy alias
  my $vertex_array= $res->new_vao( $name, %options );

Return an existing or configured Vertex Array. The configurations may reference Buffer objects by name, and these will be translated to the actual perl object with calls to "buffer" before constructing the vertex array.


Return an existing VAO, or create one from "vao_config". If the $name is not configured, this dies.


Create a new Vertex Array Object by combining %options with any (optional) configuration for this name in "vao_config". This dies if $name was already created.


  my $shader= $res->shader( $name );
  my $shader= $res->new_shader( $name, %options );

Returns a named shader. A $name ending with .frag or .vert will imply the relevant GL shader type, unless you specifically passed it in %options or configured it in "shader_config".

Shader and Program objects require OpenGL version 2.0 or above.


Return an existing or configured shader.


Create a new named shader from the options, including any configuration in "shader_config". The shader must not have previously been created.


  my $prog= $res->program( $name );
  my $prog= $res->new_program( $name, %options );

Return a named shader program. If the combined %options and "program_config" do not specify shaders, this will look through the shader/ directory for every shader that begins with this name. For example, if the directory contains:


Then this will augment the configuration with

   shaders => { vert => 'foo.vert', frag => 'foo.frag' }

Shader and Program objects require OpenGL version 2.0 or above.


Return a configured or existing or implied (by shader names) program object.


Create and return a new named program, with the given constructor options, which get combined with any in "program_config".


  $font= $res->font( $name );
  $font= $res->load_font( $name, %config );

Font support comes from a separate distribution, and these methods with attempt to load it on demand. Currently, the only font provider is OpenGL::Sandbox::V1::FTGLFont which is tied to OpenGL 1.x.


Retrieve a named font, either confgured in font_config, previously created, or implied by the presence of a file in "font_path".

If the font cannot be loaded, this logs a warning and returns the 'default' font rather than throwing an exception or returning undef. If there is no font named 'default', it dies instead.


Load a font by name. By default, a font file of the same name is loaded as a TextureFont and rendered at 24px. If multiple named fonts reference the same file (including hardlink checks), it will only be mapped into memory once.

Any configuration options specified here are combined with any defaults specified in "font_config".

If the font can't be loaded, this throws an exception. If the named font has already been loaded, this will return the existing font, even if the options have changed.


Michael Conrad <>


This software is copyright (c) 2019 by Michael Conrad.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.