The Perl Advent Calendar needs more articles for 2022. Submit your idea today!

NAME

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

VERSION

version 0.120

SYNOPSIS

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

DESCRIPTION

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.

METHODS

new

Standard Moo constructor. All attributes may be initialized here.

default_instance

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

clear_cache

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.

CONFIGURATION

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:

path

Root path for all other path fragments

texture_path
tex_path

(alias for texture_path)

shader_path
data_path
font_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".

texture_config

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

  tex/a.png
  tex/b.rgb
  tex/c.bgr

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.

tex_config

Alias for texture_config

tex_fmt_priority

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"

buffer_config

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".

vertex_array_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.

vao_config

Alias for vertex_array_config

shader_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".

program_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.

font_config

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".

RESOURCE ACCESS

Textures

  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.

texture

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'.

tex

Alias for texture

load_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.

new_texture

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.

buffer

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

new_buffer

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.

vao
vertex_array

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

new_vao
new_vertex_array

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.

Shaders

  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.

shader

Return an existing or configured shader.

new_shader

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

Programs

  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:

   shader/foo.vert
   shader/foo.frag

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.

program

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

new_program

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

Fonts

  $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.

font

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.

new_font

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.

AUTHOR

Michael Conrad <mike@nrdvana.net>

COPYRIGHT AND LICENSE

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.