AGL
A graphics library
agl::Mesh Class Referenceabstract

Base class for meshes. More...

#include <mesh.h>

Public Member Functions

virtual void render () const =0
 Draw this mesh. More...
 
GLuint vao () const
 Return the vertex array object corresponding to this mesh.
 
bool hasUV () const
 Return whether this mesh has UV coordinates defined.
 
bool isDynamic () const
 Query whether or not this is a dynamic mesh. More...
 

Protected Types

enum  VertexAttribute {
  INDEX = 0, POSITION, NORMAL, UV,
  TANGENT, NUM_ATTRIBUTES
}
 

Protected Member Functions

int numVertices () const
 Get the number of vertices.
 
void setVertexData (VertexAttribute type, int vertexId, const glm::vec4 &data)
 Set vertex properties. More...
 
glm::vec4 vertexData (VertexAttribute type, int vertexId) const
 Get vertex properties. More...
 
virtual void setIsDynamic (bool on)
 Set whether or not this is a dynamic mesh. More...
 
virtual void init ()=0
 Override init to specifiy vertex data for the mesh. More...
 
void initBuffers (std::vector< GLfloat > *points, std::vector< GLfloat > *normals, std::vector< GLfloat > *texCoords=nullptr, std::vector< GLfloat > *tangents=nullptr)
 Call initBuffers from init() to set the data for this mesh. More...
 
virtual void deleteBuffers ()
 

Protected Attributes

GLuint _nVerts = 0
 
GLuint _vao = 0
 
bool _hasUV = false
 
bool _isDynamic = false
 
bool _initialized = false
 
std::vector< GLuint > _buffers
 
std::vector< GLfloat > _data [5]
 

Detailed Description

Base class for meshes.

See also
TriangleMesh
PointMesh
LineMesh

Member Function Documentation

◆ init()

virtual void agl::Mesh::init ( )
protectedpure virtual

Override init to specifiy vertex data for the mesh.

init() will be called automatically the first time render() is called. Overridden implementations of init() should call initBuffers.

See also
initBuffers(std::vector<GLuint>*, std::vector<GLfloat>*, std::vector<GLfloat>*, std::vector<GLfloat>*, std::vector<GLfloat>*)

Implemented in agl::Torus, agl::Teapot, agl::Cylinder, agl::Plane, agl::Capsule, agl::Cube, agl::Pyramid, and agl::Sphere.

◆ initBuffers()

void agl::Mesh::initBuffers ( std::vector< GLfloat > *  points,
std::vector< GLfloat > *  normals,
std::vector< GLfloat > *  texCoords = nullptr,
std::vector< GLfloat > *  tangents = nullptr 
)
protected

Call initBuffers from init() to set the data for this mesh.

See also
init()
setIsDynamic(bool)

◆ isDynamic()

bool agl::Mesh::isDynamic ( ) const
inline

Query whether or not this is a dynamic mesh.

Dynamic meshes can change vertex quantities (e.g. position, normal, etc.) at runtime. Dynamic meshes require more memory and are generally slower. Meshes are static (e.g. assumed not to change) by default.

To create a dynamic mesh, subclass this class and set _isDynamic to true in the constructor.

// Copyright 2020, Savvy Sine, Aline Normoyle

#include "agl/window.h"
#include "agl/mesh/plane.h"

using glm::vec2;
using glm::vec4;
using glm::vec3;

class UndulateMesh : public agl::Plane {
 public:
  UndulateMesh(int xsize, int ysize) : Plane(1, 1, xsize, ysize) {
    setIsDynamic(true);
    init();  // initialize the mesh rather than wait for first frame
  }

  void update(float elapsedTime) {
    for (int i = 0; i < numVertices(); i++) {
      vec3 p = vec3(vertexData(POSITION, i));
      setVertexData(POSITION, i, vec4(position(p, elapsedTime), 0));
      setVertexData(NORMAL, i, vec4(normal(p, elapsedTime), 0));
    }
  }

  vec3 position(const vec3& p, float t) {
    float angle = t;
    float frequency = 7.0;
    float amplitude = 0.05;

    float heightFn = (angle + frequency * p[0] * frequency * p[2]);
    float y = amplitude * sin(heightFn);
    return vec3(p.x, y, p.z);
  }

  vec3 normal(const vec3& p, float t) {
    float eps = 0.001;
    vec3 x = position(p+vec3(eps, 0, 0), t) - position(p-vec3(eps, 0, 0), t);
    vec3 z = position(p+vec3(0, 0, eps), t) - position(p-vec3(0, 0, eps), t);
    vec3 y = glm::cross(z, x);
    return normalize(y);
  }
};

class MyWindow : public agl::Window {
 public:
  void setup() {
    perspective(glm::radians(30.0), 1, 0.1, 100);
    renderer.setUniform("Material.specular", vec3(1.0, 0.2, 0.8));
    renderer.setUniform("Material.ambient", vec3(0.3, 0.0, 0.2));
  }

  void draw() {
    _mesh.update(elapsedTime());
    renderer.rotate(kPI * 0.2, vec3(1, 0, 0));
    renderer.mesh(_mesh);
  }

  UndulateMesh _mesh = UndulateMesh(100, 100);
};

int main() {
  MyWindow window;
  window.run();
}
See also
setIsDynamic(bool)

◆ render()

virtual void agl::Mesh::render ( ) const
pure virtual

Draw this mesh.

Typically, users do not need to call this function. It is called from Renderer.

See also
Renderer::mesh(const Mesh&)
TriangleMesh::render()
PointMesh::render()
LineMesh::render()

Implemented in agl::LineMesh, agl::PointMesh, and agl::TriangleMesh.

◆ setIsDynamic()

void agl::Mesh::setIsDynamic ( bool  on)
protectedvirtual

Set whether or not this is a dynamic mesh.

Dynamic meshes can change vertex quantities (e.g. position, normal, etc.) at runtime. Dynamic meshes require more memory and are generally slower. Meshes are static (e.g. assumed not to change) by default.

To create a dynamic mesh, subclass this class and call setIsDynamic(true) in the constructor. setIsDynamic must be called before the mesh is initialized and cannot be changed afterwards.

// Copyright 2020, Savvy Sine, Aline Normoyle

#include "agl/window.h"
#include "agl/mesh/plane.h"

using glm::vec2;
using glm::vec4;
using glm::vec3;

class UndulateMesh : public agl::Plane {
 public:
  UndulateMesh(int xsize, int ysize) : Plane(1, 1, xsize, ysize) {
    setIsDynamic(true);
    init();  // initialize the mesh rather than wait for first frame
  }

  void update(float elapsedTime) {
    for (int i = 0; i < numVertices(); i++) {
      vec3 p = vec3(vertexData(POSITION, i));
      setVertexData(POSITION, i, vec4(position(p, elapsedTime), 0));
      setVertexData(NORMAL, i, vec4(normal(p, elapsedTime), 0));
    }
  }

  vec3 position(const vec3& p, float t) {
    float angle = t;
    float frequency = 7.0;
    float amplitude = 0.05;

    float heightFn = (angle + frequency * p[0] * frequency * p[2]);
    float y = amplitude * sin(heightFn);
    return vec3(p.x, y, p.z);
  }

  vec3 normal(const vec3& p, float t) {
    float eps = 0.001;
    vec3 x = position(p+vec3(eps, 0, 0), t) - position(p-vec3(eps, 0, 0), t);
    vec3 z = position(p+vec3(0, 0, eps), t) - position(p-vec3(0, 0, eps), t);
    vec3 y = glm::cross(z, x);
    return normalize(y);
  }
};

class MyWindow : public agl::Window {
 public:
  void setup() {
    perspective(glm::radians(30.0), 1, 0.1, 100);
    renderer.setUniform("Material.specular", vec3(1.0, 0.2, 0.8));
    renderer.setUniform("Material.ambient", vec3(0.3, 0.0, 0.2));
  }

  void draw() {
    _mesh.update(elapsedTime());
    renderer.rotate(kPI * 0.2, vec3(1, 0, 0));
    renderer.mesh(_mesh);
  }

  UndulateMesh _mesh = UndulateMesh(100, 100);
};

int main() {
  MyWindow window;
  window.run();
}
See also
isDynamic()

◆ setVertexData()

void agl::Mesh::setVertexData ( VertexAttribute  type,
int  vertexId,
const glm::vec4 &  data 
)
protected

Set vertex properties.

Parameters
typeA supported vertex attribute, such as POSITION, NORMAL, etc
vertexIdThe id of the vertex (should be between 0 and numVertices)
dataThe data to set

This function only works for dynamic meshes. This function takes a vec4 but depending on the vertex attribute only a subset of the given values will be used, depending on the data set during initialization. For example, texture coordinates typically only need two coordinates and so only the first xy values of data will be used.

// Copyright 2020, Savvy Sine, Aline Normoyle

#include "agl/window.h"
#include "agl/mesh/plane.h"

using glm::vec2;
using glm::vec4;
using glm::vec3;

class UndulateMesh : public agl::Plane {
 public:
  UndulateMesh(int xsize, int ysize) : Plane(1, 1, xsize, ysize) {
    setIsDynamic(true);
    init();  // initialize the mesh rather than wait for first frame
  }

  void update(float elapsedTime) {
    for (int i = 0; i < numVertices(); i++) {
      vec3 p = vec3(vertexData(POSITION, i));
      setVertexData(POSITION, i, vec4(position(p, elapsedTime), 0));
      setVertexData(NORMAL, i, vec4(normal(p, elapsedTime), 0));
    }
  }

  vec3 position(const vec3& p, float t) {
    float angle = t;
    float frequency = 7.0;
    float amplitude = 0.05;

    float heightFn = (angle + frequency * p[0] * frequency * p[2]);
    float y = amplitude * sin(heightFn);
    return vec3(p.x, y, p.z);
  }

  vec3 normal(const vec3& p, float t) {
    float eps = 0.001;
    vec3 x = position(p+vec3(eps, 0, 0), t) - position(p-vec3(eps, 0, 0), t);
    vec3 z = position(p+vec3(0, 0, eps), t) - position(p-vec3(0, 0, eps), t);
    vec3 y = glm::cross(z, x);
    return normalize(y);
  }
};

class MyWindow : public agl::Window {
 public:
  void setup() {
    perspective(glm::radians(30.0), 1, 0.1, 100);
    renderer.setUniform("Material.specular", vec3(1.0, 0.2, 0.8));
    renderer.setUniform("Material.ambient", vec3(0.3, 0.0, 0.2));
  }

  void draw() {
    _mesh.update(elapsedTime());
    renderer.rotate(kPI * 0.2, vec3(1, 0, 0));
    renderer.mesh(_mesh);
  }

  UndulateMesh _mesh = UndulateMesh(100, 100);
};

int main() {
  MyWindow window;
  window.run();
}
See also
numVertices()
vertexAttribute()
setIsDynamic()

◆ vertexData()

vec4 agl::Mesh::vertexData ( VertexAttribute  type,
int  vertexId 
) const
protected

Get vertex properties.

Parameters
typeA supported vertex attribute, such as POSITION, NORMAL, etc
vertexIdThe id of the vertex (should be between 0 and numVertices)
Returns
The data for the given vertex if the mesh is dynamic, and vec4(0) otherwise

This function only works for dynamic meshes. This function takes a vec4 but depending on the vertex attribute only a subset of the given values will be used, depending on the data set during initialization. For example, texture coordinates typically only need two coordinates and so only the first xy values of data will be used.

// Copyright 2020, Savvy Sine, Aline Normoyle

#include "agl/window.h"
#include "agl/mesh/plane.h"

using glm::vec2;
using glm::vec4;
using glm::vec3;

class UndulateMesh : public agl::Plane {
 public:
  UndulateMesh(int xsize, int ysize) : Plane(1, 1, xsize, ysize) {
    setIsDynamic(true);
    init();  // initialize the mesh rather than wait for first frame
  }

  void update(float elapsedTime) {
    for (int i = 0; i < numVertices(); i++) {
      vec3 p = vec3(vertexData(POSITION, i));
      setVertexData(POSITION, i, vec4(position(p, elapsedTime), 0));
      setVertexData(NORMAL, i, vec4(normal(p, elapsedTime), 0));
    }
  }

  vec3 position(const vec3& p, float t) {
    float angle = t;
    float frequency = 7.0;
    float amplitude = 0.05;

    float heightFn = (angle + frequency * p[0] * frequency * p[2]);
    float y = amplitude * sin(heightFn);
    return vec3(p.x, y, p.z);
  }

  vec3 normal(const vec3& p, float t) {
    float eps = 0.001;
    vec3 x = position(p+vec3(eps, 0, 0), t) - position(p-vec3(eps, 0, 0), t);
    vec3 z = position(p+vec3(0, 0, eps), t) - position(p-vec3(0, 0, eps), t);
    vec3 y = glm::cross(z, x);
    return normalize(y);
  }
};

class MyWindow : public agl::Window {
 public:
  void setup() {
    perspective(glm::radians(30.0), 1, 0.1, 100);
    renderer.setUniform("Material.specular", vec3(1.0, 0.2, 0.8));
    renderer.setUniform("Material.ambient", vec3(0.3, 0.0, 0.2));
  }

  void draw() {
    _mesh.update(elapsedTime());
    renderer.rotate(kPI * 0.2, vec3(1, 0, 0));
    renderer.mesh(_mesh);
  }

  UndulateMesh _mesh = UndulateMesh(100, 100);
};

int main() {
  MyWindow window;
  window.run();
}
See also
numVertices()
setVertexAttribute()
setIsDynamic()

The documentation for this class was generated from the following files: