aboutsummaryrefslogtreecommitdiffstats
path: root/dev/MinGfx/src/text_shader.cc
diff options
context:
space:
mode:
Diffstat (limited to 'dev/MinGfx/src/text_shader.cc')
-rw-r--r--dev/MinGfx/src/text_shader.cc474
1 files changed, 237 insertions, 237 deletions
diff --git a/dev/MinGfx/src/text_shader.cc b/dev/MinGfx/src/text_shader.cc
index ca99953..60d6e1b 100644
--- a/dev/MinGfx/src/text_shader.cc
+++ b/dev/MinGfx/src/text_shader.cc
@@ -1,238 +1,238 @@
-/*
- Copyright (c) 2017,2018 Regents of the University of Minnesota.
- All Rights Reserved.
- See corresponding header file for details.
- */
-
-#include "text_shader.h"
-
-#include "platform.h"
-#include <fstream>
-
-// disable warnings for this 3rd party code
-#pragma warning (push, 0)
-#define STB_RECT_PACK_IMPLEMENTATION
-#include "stb_rect_pack.h"
-#define STB_TRUETYPE_IMPLEMENTATION
-#include <stb_truetype.h>
-#pragma warning (pop)
-
-
-namespace mingfx {
-
-// Reference implementation: https://github.com/nothings/stb/blob/master/tests/oversample/main.c
-
-
-TextShader::TextShader() : native_font_size_(0.0)
-{
- for (int i = 0; i < 128; i++) {
- chardata_[i] = stbtt_packedchar();
- }
-}
-
-TextShader::~TextShader() {
-}
-
-
-bool TextShader::Init(const std::string &filename, int font_size) {
- // load shader
- shader_.AddVertexShaderFromFile(Platform::FindMinGfxShaderFile("text.vert"));
- shader_.AddFragmentShaderFromFile(Platform::FindMinGfxShaderFile("text.frag"));
- shader_.LinkProgram();
-
- // load font
- native_font_size_ = (float)font_size;
- std::ifstream is(filename.c_str(), std::ifstream::binary);
- if (is) {
- is.seekg(0, is.end);
- int length = (int)is.tellg();
- is.seekg(0, is.beg);
-
- char *ttf_buffer = new char[length];
- is.read(ttf_buffer, length);
- if (is)
- std::cout << "all characters read successfully.";
- else
- std::cout << "error: only " << is.gcount() << " could be read";
- is.close();
-
- // todo: calc an appropriate pow of 2 size given the font_size
- int atlas_width = 1024;
- int atlas_height = 1024;
-
- stbtt_pack_context pc;
- unsigned char *bitmap = new unsigned char[(size_t)atlas_width * atlas_height];
-
- stbtt_PackBegin(&pc, bitmap, atlas_width, atlas_height, 0, 1, NULL);
- stbtt_PackSetOversampling(&pc, 2, 2);
- stbtt_PackFontRange(&pc, (unsigned char*)ttf_buffer, 0, (float)font_size, 32, 95, chardata_+32);
- stbtt_PackEnd(&pc);
-
- // convert to 4-channel since that is all that Texture2D currently supports
- unsigned char *bitmap4D = new unsigned char[(size_t)4 * atlas_width * atlas_height];
- for (int i=0; i < atlas_width * atlas_height; i++) {
- bitmap4D[4*i + 0] = bitmap[i];
- bitmap4D[4*i + 1] = bitmap[i];
- bitmap4D[4*i + 2] = bitmap[i];
- bitmap4D[4*i + 3] = bitmap[i];
- }
-
- atlas_.InitFromBytes(atlas_width, atlas_height, bitmap4D);
-
- delete [] ttf_buffer;
- delete [] bitmap;
- delete [] bitmap4D;
-
- return true;
- }
- else {
- std::cerr << "TextShader: Error font file does not exist: " << filename << std::endl;
- return false;
- }
-
-}
-
-
-void TextShader::Draw3D(const Matrix4 &model, const Matrix4 &view, const Matrix4 &projection,
- const std::string &text, TextFormat format, bool cache)
-{
- MeshData *md = NULL;
- std::map<std::string, MeshData>::iterator it = cache_.find(text);
- if (it != cache_.end()) {
- // use an existing cached mesh
- md = &(it->second);
- }
- else {
- // need to create a new mesh, add a new one to the cache or use the tmp_mesh
- if (cache) {
- MeshData new_md;
- cache_[text] = new_md;
- md = &(cache_[text]);
- }
- else {
- md = &tmp_md_;
- }
-
- // set appropriate vertices and texcoords for this text string
- SetTextMesh(text, md);
- }
-
- Vector3 offset;
- if (format.h_align == HorizAlign::HORIZ_ALIGN_LEFT) {
- offset[0] = 0;
- }
- else if (format.h_align == HorizAlign::HORIZ_ALIGN_CENTER) {
- offset[0] = -0.5f * (md->max[0] - md->min[0]);
- }
- else if (format.h_align == HorizAlign::HORIZ_ALIGN_RIGHT) {
- offset[0] = -(md->max[0] - md->min[0]);
- }
-
- if (format.v_align == VertAlign::VERT_ALIGN_TOP) {
- offset[1] = -md->max[1];
- }
- else if (format.v_align == VertAlign::VERT_ALIGN_CENTER) {
- offset[1] = -0.5f * md->max[1];
- }
- else if (format.v_align == VertAlign::VERT_ALIGN_BASELINE) {
- offset[1] = 0;
- }
- else if (format.v_align == VertAlign::VERT_ALIGN_BOTTOM) {
- offset[1] = -md->min[1];
- }
-
- glDisable(GL_CULL_FACE);
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
- shader_.UseProgram();
- Matrix4 mvp = projection * view * model;
- shader_.SetUniform("mvp_matrix", mvp);
- shader_.SetUniform("scale", format.size / native_font_size_);
- shader_.SetUniform("offset", offset);
- shader_.SetUniform("color", format.color);
- shader_.BindTexture("font_atlas", atlas_);
- md->mesh.Draw();
- shader_.StopProgram();
-
- glEnable(GL_CULL_FACE);
-}
-
-
-void TextShader::SetTextMesh(const std::string &text, MeshData *md) {
- std::vector<Point3> verts;
- std::vector<Point2> uvs;
- std::vector<unsigned int> indices;
-
- const char *c = text.c_str();
- float x = 0.0;
- float y = 0.0;
- while (*c) {
- stbtt_aligned_quad q;
- stbtt_GetPackedQuad(chardata_, atlas_.width(), atlas_.height(), *c++, &x, &y, &q, 0);
-
- // top left
- verts.push_back(Point3(q.x0, -q.y0, 0.0));
- uvs.push_back(Point2(q.s0, q.t0));
- // top right
- verts.push_back(Point3(q.x1, -q.y0, 0.0));
- uvs.push_back(Point2(q.s1, q.t0));
- // bot right
- verts.push_back(Point3(q.x1, -q.y1, 0.0));
- uvs.push_back(Point2(q.s1, q.t1));
- // bot left
- verts.push_back(Point3(q.x0, -q.y1, 0.0));
- uvs.push_back(Point2(q.s0, q.t1));
-
-
- indices.push_back((unsigned int)verts.size()-2);
- indices.push_back((unsigned int)verts.size()-3);
- indices.push_back((unsigned int)verts.size()-4);
-
- indices.push_back((unsigned int)verts.size()-2);
- indices.push_back((unsigned int)verts.size()-4);
- indices.push_back((unsigned int)verts.size()-1);
- }
-
- md->mesh.SetVertices(verts);
- md->mesh.SetTexCoords(0, uvs);
- md->mesh.SetIndices(indices);
-
- md->min = Point2(verts[0][0], verts[0][1]);
- md->max = md->min;
- for (int i=0; i<verts.size(); i++) {
- Point3 p = verts[i];
- if (p[0] < md->min[0]) md->min[0] = p[0];
- if (p[0] > md->max[0]) md->max[0] = p[0];
- if (p[1] < md->min[1]) md->min[1] = p[1];
- if (p[1] > md->max[1]) md->max[1] = p[1];
- }
-}
-
-Vector2 TextShader::TextExtents(const std::string &text, TextFormat format, bool cache) {
- MeshData *md = NULL;
- std::map<std::string, MeshData>::iterator it = cache_.find(text);
- if (it != cache_.end()) {
- // use an existing cached mesh
- md = &(it->second);
- }
- else {
- // need to create a new mesh, add a new one to the cache or use the tmp_mesh
- if (cache) {
- MeshData new_md;
- cache_[text] = new_md;
- md = &(cache_[text]);
- }
- else {
- md = &tmp_md_;
- }
-
- // set appropriate vertices and texcoords for this text string
- SetTextMesh(text, md);
- }
-
- return format.size / native_font_size_ * (md->max - md->min);
-}
-
-
+/*
+ Copyright (c) 2017,2018 Regents of the University of Minnesota.
+ All Rights Reserved.
+ See corresponding header file for details.
+ */
+
+#include "text_shader.h"
+
+#include "platform.h"
+#include <fstream>
+
+// disable warnings for this 3rd party code
+#pragma warning (push, 0)
+#define STB_RECT_PACK_IMPLEMENTATION
+#include "stb_rect_pack.h"
+#define STB_TRUETYPE_IMPLEMENTATION
+#include <stb_truetype.h>
+#pragma warning (pop)
+
+
+namespace mingfx {
+
+// Reference implementation: https://github.com/nothings/stb/blob/master/tests/oversample/main.c
+
+
+TextShader::TextShader() : native_font_size_(0.0)
+{
+ for (int i = 0; i < 128; i++) {
+ chardata_[i] = stbtt_packedchar();
+ }
+}
+
+TextShader::~TextShader() {
+}
+
+
+bool TextShader::Init(const std::string &filename, int font_size) {
+ // load shader
+ shader_.AddVertexShaderFromFile(Platform::FindMinGfxShaderFile("text.vert"));
+ shader_.AddFragmentShaderFromFile(Platform::FindMinGfxShaderFile("text.frag"));
+ shader_.LinkProgram();
+
+ // load font
+ native_font_size_ = (float)font_size;
+ std::ifstream is(filename.c_str(), std::ifstream::binary);
+ if (is) {
+ is.seekg(0, is.end);
+ int length = (int)is.tellg();
+ is.seekg(0, is.beg);
+
+ char *ttf_buffer = new char[length];
+ is.read(ttf_buffer, length);
+ if (is)
+ std::cout << "all characters read successfully.";
+ else
+ std::cout << "error: only " << is.gcount() << " could be read";
+ is.close();
+
+ // todo: calc an appropriate pow of 2 size given the font_size
+ int atlas_width = 1024;
+ int atlas_height = 1024;
+
+ stbtt_pack_context pc;
+ unsigned char *bitmap = new unsigned char[(size_t)atlas_width * atlas_height];
+
+ stbtt_PackBegin(&pc, bitmap, atlas_width, atlas_height, 0, 1, NULL);
+ stbtt_PackSetOversampling(&pc, 2, 2);
+ stbtt_PackFontRange(&pc, (unsigned char*)ttf_buffer, 0, (float)font_size, 32, 95, chardata_+32);
+ stbtt_PackEnd(&pc);
+
+ // convert to 4-channel since that is all that Texture2D currently supports
+ unsigned char *bitmap4D = new unsigned char[(size_t)4 * atlas_width * atlas_height];
+ for (int i=0; i < atlas_width * atlas_height; i++) {
+ bitmap4D[4*i + 0] = bitmap[i];
+ bitmap4D[4*i + 1] = bitmap[i];
+ bitmap4D[4*i + 2] = bitmap[i];
+ bitmap4D[4*i + 3] = bitmap[i];
+ }
+
+ atlas_.InitFromBytes(atlas_width, atlas_height, bitmap4D);
+
+ delete [] ttf_buffer;
+ delete [] bitmap;
+ delete [] bitmap4D;
+
+ return true;
+ }
+ else {
+ std::cerr << "TextShader: Error font file does not exist: " << filename << std::endl;
+ return false;
+ }
+
+}
+
+
+void TextShader::Draw3D(const Matrix4 &model, const Matrix4 &view, const Matrix4 &projection,
+ const std::string &text, TextFormat format, bool cache)
+{
+ MeshData *md = NULL;
+ std::map<std::string, MeshData>::iterator it = cache_.find(text);
+ if (it != cache_.end()) {
+ // use an existing cached mesh
+ md = &(it->second);
+ }
+ else {
+ // need to create a new mesh, add a new one to the cache or use the tmp_mesh
+ if (cache) {
+ MeshData new_md;
+ cache_[text] = new_md;
+ md = &(cache_[text]);
+ }
+ else {
+ md = &tmp_md_;
+ }
+
+ // set appropriate vertices and texcoords for this text string
+ SetTextMesh(text, md);
+ }
+
+ Vector3 offset;
+ if (format.h_align == HorizAlign::HORIZ_ALIGN_LEFT) {
+ offset[0] = 0;
+ }
+ else if (format.h_align == HorizAlign::HORIZ_ALIGN_CENTER) {
+ offset[0] = -0.5f * (md->max[0] - md->min[0]);
+ }
+ else if (format.h_align == HorizAlign::HORIZ_ALIGN_RIGHT) {
+ offset[0] = -(md->max[0] - md->min[0]);
+ }
+
+ if (format.v_align == VertAlign::VERT_ALIGN_TOP) {
+ offset[1] = -md->max[1];
+ }
+ else if (format.v_align == VertAlign::VERT_ALIGN_CENTER) {
+ offset[1] = -0.5f * md->max[1];
+ }
+ else if (format.v_align == VertAlign::VERT_ALIGN_BASELINE) {
+ offset[1] = 0;
+ }
+ else if (format.v_align == VertAlign::VERT_ALIGN_BOTTOM) {
+ offset[1] = -md->min[1];
+ }
+
+ glDisable(GL_CULL_FACE);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ shader_.UseProgram();
+ Matrix4 mvp = projection * view * model;
+ shader_.SetUniform("mvp_matrix", mvp);
+ shader_.SetUniform("scale", format.size / native_font_size_);
+ shader_.SetUniform("offset", offset);
+ shader_.SetUniform("color", format.color);
+ shader_.BindTexture("font_atlas", atlas_);
+ md->mesh.Draw();
+ shader_.StopProgram();
+
+ glEnable(GL_CULL_FACE);
+}
+
+
+void TextShader::SetTextMesh(const std::string &text, MeshData *md) {
+ std::vector<Point3> verts;
+ std::vector<Point2> uvs;
+ std::vector<unsigned int> indices;
+
+ const char *c = text.c_str();
+ float x = 0.0;
+ float y = 0.0;
+ while (*c) {
+ stbtt_aligned_quad q;
+ stbtt_GetPackedQuad(chardata_, atlas_.width(), atlas_.height(), *c++, &x, &y, &q, 0);
+
+ // top left
+ verts.push_back(Point3(q.x0, -q.y0, 0.0));
+ uvs.push_back(Point2(q.s0, q.t0));
+ // top right
+ verts.push_back(Point3(q.x1, -q.y0, 0.0));
+ uvs.push_back(Point2(q.s1, q.t0));
+ // bot right
+ verts.push_back(Point3(q.x1, -q.y1, 0.0));
+ uvs.push_back(Point2(q.s1, q.t1));
+ // bot left
+ verts.push_back(Point3(q.x0, -q.y1, 0.0));
+ uvs.push_back(Point2(q.s0, q.t1));
+
+
+ indices.push_back((unsigned int)verts.size()-2);
+ indices.push_back((unsigned int)verts.size()-3);
+ indices.push_back((unsigned int)verts.size()-4);
+
+ indices.push_back((unsigned int)verts.size()-2);
+ indices.push_back((unsigned int)verts.size()-4);
+ indices.push_back((unsigned int)verts.size()-1);
+ }
+
+ md->mesh.SetVertices(verts);
+ md->mesh.SetTexCoords(0, uvs);
+ md->mesh.SetIndices(indices);
+
+ md->min = Point2(verts[0][0], verts[0][1]);
+ md->max = md->min;
+ for (int i=0; i<verts.size(); i++) {
+ Point3 p = verts[i];
+ if (p[0] < md->min[0]) md->min[0] = p[0];
+ if (p[0] > md->max[0]) md->max[0] = p[0];
+ if (p[1] < md->min[1]) md->min[1] = p[1];
+ if (p[1] > md->max[1]) md->max[1] = p[1];
+ }
+}
+
+Vector2 TextShader::TextExtents(const std::string &text, TextFormat format, bool cache) {
+ MeshData *md = NULL;
+ std::map<std::string, MeshData>::iterator it = cache_.find(text);
+ if (it != cache_.end()) {
+ // use an existing cached mesh
+ md = &(it->second);
+ }
+ else {
+ // need to create a new mesh, add a new one to the cache or use the tmp_mesh
+ if (cache) {
+ MeshData new_md;
+ cache_[text] = new_md;
+ md = &(cache_[text]);
+ }
+ else {
+ md = &tmp_md_;
+ }
+
+ // set appropriate vertices and texcoords for this text string
+ SetTextMesh(text, md);
+ }
+
+ return format.size / native_font_size_ * (md->max - md->min);
+}
+
+
} // end namespace \ No newline at end of file