123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178 |
- #include "client/FontRenderer.h"
- #include "io/ImageReader.h"
- #include "rendering/Shader.h"
- #include "rendering/Texture.h"
- #include "rendering/VertexBuffer.h"
- #include "utils/Logger.h"
- static constexpr float FONT_WIDTH = 8.0f;
- static constexpr float FONT_HEIGHT = 8.0f;
- static constexpr float FONT_STEP = 1.0f / 128.0f;
- static Shader shader;
- static VertexBuffer buffer;
- static Texture texture;
- static Buffer data{50};
- static Color4 color;
- struct Symbol {
- int offsetX = 8;
- int width = 0;
- };
- static Array<Symbol, 256> symbols;
- bool FontRenderer::init() {
- Error e = shader.compile("resources/shader/fontTest.vs",
- "resources/shader/fontTest.fs");
- if(e.has()) {
- LOG_ERROR(e.message);
- return true;
- }
- ImageReader::Image image;
- const char* path = "resources/font8x8.png";
- e = ImageReader::load(image, path);
- if(e.has()) {
- LOG_ERROR(e.message);
- return true;
- }
- if(image.channels < 1 || image.channels > 4 || image.bitdepth != 8 ||
- image.width != 128 || image.height != 128) {
- LOG_ERROR("font must have 1-4 channels, 8 bit per channel and a size "
- "of 128x128");
- return true;
- }
- texture.init(Texture::Format::color8(image.channels), 0);
- int end = image.width * image.height;
- for(int i = 0; i < end; i++) {
- int c = image.data[i * image.channels];
- if(c != 255) {
- continue;
- }
- int px = i % image.width;
- int py = i / image.width;
- int index = (py / 8) * 16 + (px / 8);
- symbols[index].offsetX = std::min(symbols[index].offsetX, px % 8);
- symbols[index].width = std::max(symbols[index].width, px % 8);
- }
- texture.setData(image.width, image.height, image.data);
- for(Symbol& s : symbols) {
- s.width = std::max(s.width - s.offsetX + 2, 0);
- }
- symbols[' '].offsetX = 0;
- symbols[' '].width = 4;
- buffer.init(VertexBuffer::Attributes().addFloat(3).addFloat(2).addColor4());
- return false;
- }
- void FontRenderer::bind() {
- shader.use();
- texture.bindTo(0);
- }
- void FontRenderer::setProjection(const Matrix& m) {
- shader.setMatrix("proj", m);
- }
- void FontRenderer::setView(const Matrix& m) {
- shader.setMatrix("view", m);
- }
- void FontRenderer::setModel(const Matrix& m) {
- shader.setMatrix("model", m);
- }
- void FontRenderer::draw(const char* text, int alpha) {
- data.clear();
- color = Color4(255, 255, 255, alpha);
- int index = 0;
- Vector3 pos;
- int vertices = 0;
- while(text[index] != '\0') {
- int i = text[index];
- if(i < 0 && text[index + 1] != '\0') {
- index++;
- i = ((i & 0x1F) << 6) | (text[index] & 0x3F);
- }
- if(i < 0 || i >= 256) {
- continue;
- }
- Vector3 right = pos + Vector3(symbols[i].width, 0.0f, 0.0f);
- Vector3 down = pos + Vector3(0.0f, FONT_HEIGHT, 0.0f);
- Vector3 downRight = pos + Vector3(symbols[i].width, FONT_HEIGHT, 0.0f);
- Vector2 tPos((FONT_WIDTH * (i % 16) + symbols[i].offsetX) * FONT_STEP,
- FONT_HEIGHT * (i / 16) * FONT_STEP);
- Vector2 tRight = tPos + Vector2(symbols[i].width * FONT_STEP, 0.0f);
- Vector2 tDown = tPos + Vector2(0.0f, FONT_HEIGHT * FONT_STEP);
- Vector2 tDownRight = tPos + Vector2(symbols[i].width * FONT_STEP,
- FONT_HEIGHT * FONT_STEP);
- Color4 dark =
- Color4(color[0] / 2, color[1] / 2, color[2] / 2, color[3]);
- Vector3 shift(0.25f, 0.25f, 0.0f);
- data.add(shift + pos).add(tPos).add(dark);
- data.add(shift + down).add(tDown).add(dark);
- data.add(shift + right).add(tRight).add(dark);
- data.add(shift + down).add(tDown).add(dark);
- data.add(shift + right).add(tRight).add(dark);
- data.add(shift + downRight).add(tDownRight).add(dark);
- data.add(pos).add(tPos).add(color);
- data.add(down).add(tDown).add(color);
- data.add(right).add(tRight).add(color);
- data.add(down).add(tDown).add(color);
- data.add(right).add(tRight).add(color);
- data.add(downRight).add(tDownRight).add(color);
- pos += Vector3(symbols[i].width, 0.0f, 0.0f);
- vertices += 12;
- index++;
- }
- buffer.setData(data, GL::DYNAMIC_DRAW);
- buffer.draw(vertices);
- }
- float FontRenderer::getWidth(const char* text, int max) {
- int index = 0;
- float width = 0.0f;
- while(text[index] != '\0' && (max < 0 || index < max)) {
- int i = text[index];
- if(i < 0 && text[index + 1] != '\0') {
- index++;
- i = ((i & 0x1F) << 6) | (text[index] & 0x3F);
- }
- if(i < 0 || i >= 256) {
- continue;
- }
- width += symbols[i].width;
- index++;
- }
- return width;
- }
- void FontRenderer::draw(const Vector2& size, Color4 c) {
- data.clear();
- Vector3 pos;
- Vector3 right = pos + Vector3(size[0], 0.0f, 0.0f);
- Vector3 down = pos + Vector3(0.0f, size[1], 0.0f);
- Vector3 downRight = pos + Vector3(size[0], size[1], 0.0f);
- Vector2 tPos;
- Vector2 tRight(FONT_STEP, 0.0f);
- Vector2 tDown(0.0f, FONT_STEP);
- Vector2 tDownRight(FONT_STEP, FONT_STEP);
- data.add(pos).add(tPos).add(c);
- data.add(down).add(tDown).add(c);
- data.add(right).add(tRight).add(c);
- data.add(down).add(tDown).add(c);
- data.add(right).add(tRight).add(c);
- data.add(downRight).add(tDownRight).add(c);
- buffer.setData(data, GL::DYNAMIC_DRAW);
- buffer.draw(6);
- }
|