Skip to content

Utility Classes

Nick McDonald edited this page May 17, 2020 · 14 revisions

TinyEngine - Utility Classes

Utility classes wrap boilerplate OpenGL behavior. The classes are extremely small, so it is worth reading through their code to understand what they do and how they can be modified for your specific needs. Otherwise, their default constructors are usually sufficient! These classes have a destructor included that deletes all the data inside, so you don't have to.

Texture

Wraps OpenGL textures. Lets you create blank textures of a size, load from images or generate from raw data.

  //Construction
  Texture tex;                                     //Empty OpenGL Texture
  Texture tex(1200, 800);                          //Size-Based (empty)
  Texture tex(image::load("filename.png"));        //Using Surface Data
  Texture tex(image::make(size, data, algorithm)); //Using raw data + algorithm

Texture contains a subclass cubetexture, which does the same stuff except as a cube map.

Shader

Wraps OpenGL shaders. Lets you define all input properties, and load files for the shader pipeline.

  //Construction
  Shader shader({"vertex.vs", "fragment.fs"}, {"all", "shader", "input", "properties"});
  Shader shader({"vertex.vs", "geometry.gs", "fragment.fs"}, {"all", "shader", "input", "properties"});

  //Activation
  shader.use();
  
  //Uniform Setting (fully templated - automatic handling of type)
  shader.uniform(string name, int value);
  shader.uniform(string name, glm::vec3 vec);
  shader.uniform(string name, glm::mat4 mat);
  shader.texture("exampleTexture", tex.texture);

  //... etc

Model

Wraps VAO and VBOs for rendering. Requires a custom construction function that manipulates the position, normal, color and index data.

  //Construction
  Model model(algorithm); //User-defined construction algorithm
  
  //Reconstruct model (and update the buffers)
  model.construct(algorithm);
  
  //Rendering
  model.render(GL_TRIANGLES); //lets you choose how to render

Algorithm is passed as a functional or lambda, that needs to capture the data that the model will be constructed from. Construction process is just pushing vertices into the corresponding vectors.

  //Example Model Construction
  std::function<void(Model* m)> algorithm = [&](Model* h){
     //basic triangle...
     h->positions.push_back(0.0);
     h->positions.push_back(0.0);
     h->positions.push_back(0.0);
     h->positions.push_back(0.5);
     h->positions.push_back(0.0);
     h->positions.push_back(1.0);

     h->indices.push_back(0);
     h->indices.push_back(1);
     h->indices.push_back(2);

     //add normal or color data...
     //...and so on
  }

See example programs for some examples on how models are constructed.

Models are derived from a base-class "Primitive", which has a few pre-made classes that contain the buffers for e.g. rendering billboards to screen, or sprites / particles in 3D space.

  Square2D board;  //2D vertex data (for e.g. drawing billboards)
  Square3D sprite; //3D vertex data (for e.g. drawing textures on a flat board in 3D space)
  Cube cube;       //Cube vertex data

These also have render methods.

Target

The target utility class wraps FBOs so that you can render directly for textures. It has two sub-classes "Billboard" and "Cubemap", that give easier construction of the render targets.

  //Construction
  Target target(1200, 800);
  Texture tex(1200, 800);
  target.bind(tex);

  //Easier Binding
  Billboard billboard(1200, 800);
  Cubemap cubemap(1200, 800);

Optionally, you can specify in the constructor whether you want to include a depth-buffer or ignore the color buffer (read target.cpp for more info).

  //Targeting
  billboard.target();
  billboard.target(glm::vec3 clearcolor);

When using the target base class, the bound texture is rendered to. When using the derived classes, they have a member "texture" and "depth" for the respective buffers.

To target the main window again, call:

  Tiny::view.target(glm::vec3 clearcolor);

Particle

This is a simple class that lets you push matrices onto a vector, update the buffer and then do an instanced render of any class related to the model class.

  //Construction
  Particle particles(&model); //using a pointer to the model we want to instance-render
  
  //Adding matrices
  particles.models.push_back(glm::mat4(1.0); //do this as many times as you like

  //Update the buffers
  particles.update();

  //Instanced render!
  particles.render(GL_TRIANGLES);

Clone this wiki locally