Skip to content

Commit

Permalink
Begin instancing
Browse files Browse the repository at this point in the history
  • Loading branch information
m-decoster committed Jun 25, 2015
1 parent a71d179 commit faf1b11
Show file tree
Hide file tree
Showing 17 changed files with 362 additions and 8 deletions.
22 changes: 22 additions & 0 deletions 3rd_party/basis33/LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
The MIT License (MIT)

Copyright (c) 2004, 2005 Tristan Grimmer
Copyright (c) 2014 Manchson

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
3 changes: 3 additions & 0 deletions 3rd_party/basis33/NOTES.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
I have used the basis33 font to create a bitmap font for the instancing
example. This bitmap font is distributed in the folder of that example.
The original file is in this folder: basis33.ttf.
Binary file added 3rd_party/basis33/basis33.ttf
Binary file not shown.
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,9 @@ cubemaps:
$(CC) $(INCLUDES) $(CFLAGS) src/examples/07-cubemaps/main.cpp src/examples/07-cubemaps/skybox.cpp $(COMMON) -o bin/07-cubemaps.out $(LIBS)
cp src/examples/07-cubemaps/*.png bin/

instancing:
$(CC) $(INCLUDES) $(CFLAGS) src/examples/08-instancing/main.cpp src/examples/08-instancing/text.cpp src/examples/08-instancing/font.cpp $(COMMON) -o bin/08-instancing.out $(LIBS)
cp src/examples/08-instancing/font.png bin/font.png

clean:
rm bin/*
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,17 @@ These examples have some dependencies:
* [GLM](http://glm.g-truc.net)
* [ASSIMP](http://assimp.sf.net/)

## Third party

These examples use some third party software and assets. For libraries,
see the section about Dependencies above. These are the third party assets
that we use:

* [Basis33](http://www.1001fonts.com/basis33-font.html#license) is a fixed-width font
available under the MIT license.

All of the licenses for third party software and assets are available in the 3rd\_party folder.

## Compiling

### OS X
Expand Down
2 changes: 1 addition & 1 deletion src/examples/02-hello_sprite/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ int main(void)

// Load the texture and bind it to the uniform
int w, h;
GLuint texture = loadImage("image.png", &w, &h, 0); // GL_TEXTURE0
GLuint texture = loadImage("image.png", &w, &h, 0, false); // GL_TEXTURE0
if(!texture)
{
return -1;
Expand Down
2 changes: 1 addition & 1 deletion src/examples/03-hello_cube/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ int main(void)

// Load the texture and bind it to the uniform
int w, h;
GLuint texture = loadImage("image.png", &w, &h, 0); // GL_TEXTURE0
GLuint texture = loadImage("image.png", &w, &h, 0, false); // GL_TEXTURE0
if(!texture)
{
return -1;
Expand Down
2 changes: 1 addition & 1 deletion src/examples/05-hello_mesh/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ int main(void)
}
mat.use();
int w, h;
GLuint texture = loadImage("image.png", &w, &h, 0);
GLuint texture = loadImage("image.png", &w, &h, 0, false);
if(!texture)
{
std::cerr << "Could not load texture" << std::endl;
Expand Down
2 changes: 1 addition & 1 deletion src/examples/06-render_to_texture/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ int main(void)
}
mat.use();
int w, h;
GLuint texture = loadImage("image.png", &w, &h, 0);
GLuint texture = loadImage("image.png", &w, &h, 0, false);
if(!texture)
{
std::cerr << "Could not load texture" << std::endl;
Expand Down
50 changes: 50 additions & 0 deletions src/examples/08-instancing/font.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#include "font.h"
#include "../common/util.h"

Font::Font()
: texture(0), glyphWidth(0), glyphHeight(0)
{
}

Font::~Font()
{
if(texture)
{
glDeleteTextures(1, &texture);
}
}

bool Font::load(const char* fileName, int numChars)
{
texture = loadImage(fileName, &totalWidth, &glyphHeight, 0, true);
glyphWidth = totalWidth / numChars;
return texture != 0;
}

bool Font::bind()
{
if(!texture)
{
std::cerr << "Tried to bind a font that was not correctly loaded" << std::endl;
return false;
}

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
return true;
}

int Font::getGlyphWidth() const
{
return glyphWidth;
}

int Font::getGlyphHeight() const
{
return glyphHeight;
}

int Font::getTotalWidth() const
{
return totalWidth;
}
22 changes: 22 additions & 0 deletions src/examples/08-instancing/font.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#ifndef FONT_HEADER
#define FONT_HEADER

#include "../common/util.h"

class Font
{
public:
Font();
~Font();

bool load(const char* fileName, int numChars);
bool bind();
int getGlyphWidth() const;
int getGlyphHeight() const;
int getTotalWidth() const;
private:
GLuint texture;
int glyphWidth, glyphHeight, totalWidth;
};

#endif
Binary file added src/examples/08-instancing/font.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
58 changes: 58 additions & 0 deletions src/examples/08-instancing/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#include "../common/util.h"
#include "font.h"
#include "text.h"

/* NOTE:
* This example uses font rendering to demonstrate how instancing
* works. Instancing is mostly useful when you want to render a
* very large quantity of objects. This example only renders
* "HELLOWORLD" to the screen, which is hardly an appropriate
* use case for instancing. In your own applications, you should
* always consider if instancing is the correct way to go, or if
* you should consider a dynamic buffer (which we will cover
* in a later example).
*
* The text rendering in this example is very basic. It only renders
* uppercase characters of fixed-width fonts. It is a contrived example
* that allows to show how instancing works. I will add a better example
* later, which can render TrueType fonts with any color and transformation.
*/

int main(void)
{
GLFWwindow* window;

window = init("Instancing", 640, 480);
if(!window)
{
return -1;
}

Font font;
if(!font.load("font.png", 26))
{
return -1;
}
Text text;
if(!text.load(&font))
{
return -1;
}
text.setPosition(0.0f, 0.0f);
text.setString("HELLOWORLD");

glClearColor(0.75f, 0.75f, 0.75f, 1.0f);

while(!glfwWindowShouldClose(window))
{
glClear(GL_COLOR_BUFFER_BIT);

text.render();

glfwSwapBuffers(window);
glfwPollEvents();
}

glfwTerminate();
return 0;
}
157 changes: 157 additions & 0 deletions src/examples/08-instancing/text.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
#include "text.h"
#include "font.h"
#include "../common/shader.h"

#define MAX_STRING_LENGTH 10 // Maximum # characters

const char* VERTEX_SRC = "#version 330 core\n"
"layout(location=0) in vec2 position;"
"uniform int glyphWidth;" // Width of 1 glyph (fixed-width font!)
"uniform int fontWidth;" // Width of the font file
"uniform vec2 texCoords[120];"
"out vec2 fTexcoord;"
"void main()"
"{"
" fTexcoord = texCoords[gl_InstanceID * gl_VertexID];"
" float newX = position.x + gl_InstanceID * glyphWidth;"
" gl_Position = vec4(position, 0.0, 1.0);"
"}";

const char* FRAGMENT_SRC = "#version 330 core\n"
"in vec2 fTexcoord;"
"out vec4 outputColor;"
"uniform sampler2D fontTexture;"
"void main()"
"{"
" outputColor = texture(fontTexture, fTexcoord);"
"}";

Text::Text()
: font(NULL), x(0.0f), y(0.0f), vao(0), program(0)
{
}

Text::~Text()
{
if(vao)
{
glDeleteVertexArrays(1, &vao);
}
if(program)
{
glDeleteProgram(program);
}
}

bool Text::load(Font* fnt)
{
font = fnt;

// Shader
GLuint vertex = createShader(VERTEX_SRC, GL_VERTEX_SHADER);
GLuint fragment = createShader(FRAGMENT_SRC, GL_FRAGMENT_SHADER);
program = createShaderProgram(vertex, fragment);
linkShader(program);
validateShader(program);

glDetachShader(program, vertex);
glDeleteShader(vertex);
glDetachShader(program, fragment);
glDeleteShader(fragment);

// Geometry
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);

GLuint vbo;
glGenBuffers(1, &vbo);

// We create vertices to fit one glyph
float vertices[] =
{
// x y
-0.5f, 0.5f,
0.5f, 0.5f,
0.5f, -0.5f,
0.5f, -0.5f,
-0.5f, -0.5f,
-0.5f, 0.5f
};

glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), 0);

glBindVertexArray(0);

glDeleteBuffers(1, &vbo);

return true;
}

void Text::setPosition(float x_, float y_)
{
x = x_;
y = y_;
}

void Text::setString(const char* str)
{
string = str;
}

static void setTexCoord(int i, float x, float y, GLuint program)
{
glUniform2f(glGetUniformLocation(program, ("texcoords[" + std::to_string(i) + "]").c_str()), x, y);
}

void Text::render()
{
if(!program || !vao || !font)
{
std::cerr << "Tried to render text with invalid program, VAO or font" << std::endl;
return;
}
if(string.length() > MAX_STRING_LENGTH)
{
std::cerr << "String is too long!" << std::endl;
return;
}

glUseProgram(program);
glBindVertexArray(vao);

// Calculate the texture coordinates for each character
// Normally, the font would store this information based on a file
// that was distributed with the font.
// For this example, I have made sure that the indices for the characters
// match the ASCII index
for(int i = 0; i < string.length(); i += 12)
{
char index = string.at(i) - 'A';
float relativeWidth = font->getGlyphWidth() / (float)font->getTotalWidth();
// bottom left
setTexCoord(i, (float)index * relativeWidth, 1.0f, program);
// bottom right
setTexCoord(i + 1, (float)index * relativeWidth + relativeWidth, 1.0f, program);
// top right
setTexCoord(i + 2, (float)index * relativeWidth + relativeWidth, 0.0f, program);
// top right
setTexCoord(i + 3, (float)index * relativeWidth + relativeWidth, 0.0f, program);
// top left
setTexCoord(i + 4, (float)index * relativeWidth, 0.0f, program);
// bottom left
setTexCoord(i + 5, (float)index * relativeWidth, 1.0f, program);
}

font->bind();
glUniform1i(glGetUniformLocation(program, "glyphWidth"), font->getGlyphWidth());
glUniform1i(glGetUniformLocation(program, "fontTexture"), 0);
// Draw TRIANGLES, starting at index 0. There are 6 vertices per glyph, and there are string.length() glyphs
glDrawArraysInstanced(GL_TRIANGLES, 0, 6, string.length());

glBindVertexArray(0);
glUseProgram(0);
}
Loading

0 comments on commit faf1b11

Please sign in to comment.