Я пытаюсь сгенерировать все растровые изображения для персонажей из ' '
в '~'
и добавьте их к одной длинной текстуре. Я намерен расположить их в текстуре с фиксированной шириной, но сейчас я просто хотел убедиться, что концепция будет работать.
Но у меня проблемы. Вместо того, чтобы получить ожидаемую текстуру, я просто получаю следующее для шрифта 16px:
Мне кажется, что я копирую это неправильно, но независимо от того, что я делаю, у меня всегда получается один и тот же результат.
Наконец, код:
Font.h
#ifndef _FONT_H_
#define _FONT_H_
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <GL/gl.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include "vector2.h"#include "math_helper.h"
class Font {
public:
Font(const std::string font_path, int size);
~Font();
int get_texture() const { return texture_; }
private:
unsigned int width_, height_, texture_;
static FT_Library LIBRARY;
static const char START_CHAR = ' ';
static const char END_CHAR = '~';
static void initialize_library();
};
#endif
Font.cpp
#include "font.h"
FT_Library Font::LIBRARY = NULL;
Font::Font(const std::string font_path, int size)
: width_(64), height_(2), texture_(0) {
initialize_library();
FT_Face face = NULL;
int error = FT_New_Face(Font::LIBRARY, font_path.c_str(), 0, &face);
if(error == FT_Err_Unknown_File_Format) {
std::cout << "Error: Unknown file format for font \"" << font_path << "\"" << std::endl;
} else if(error) {
std::cout << "Error: Could not open font \"" << font_path << "\"" << std::endl;
}
error = FT_Set_Pixel_Sizes(face, 0, size);
if(error) {
std::cout << "Error: Could not set pixel size for font \"" << font_path << "\"" << std::endl;
}
int num_chars = (END_CHAR - START_CHAR);
width_ = to_nearest_pow2(num_chars * size);
height_ = to_nearest_pow2(size);
std::vector<unsigned char> buffer(width_ * height_, 0);
Vector2 pen;
for(char c = START_CHAR; c <= END_CHAR; ++c) {
error = FT_Load_Char(face, c, FT_LOAD_RENDER);
if(error) {
std::cout << "Error: Could not load char \"" << c << "\"" << std::endl;
continue;
}
FT_Bitmap bmp = face->glyph->bitmap;
int advance = (face->glyph->advance.x >> 6);
int bitmapWidth = bmp.width; //I have tried pitch, same problem
int bitmapHeight = bmp.rows;
for(int h = 0; h < bitmapHeight; ++h) {
for(int w = 0; w < bitmapWidth; ++w) {
int index = h * bitmapWidth + pen.x;
buffer[index + w] = bmp.buffer[w + bitmapWidth * h];
}
}
pen.x += advance;
}
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glGenTextures(1, &texture_);
glBindTexture(GL_TEXTURE_2D, texture_);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width_, height_, 0, GL_ALPHA, GL_UNSIGNED_BYTE, &buffer[0]);
FT_Done_Face(face);
}
Font::~Font() {
if(texture_ != 0) {
glDeleteTextures(1, &texture_);
}
}
void Font::initialize_library() {
if(Font::LIBRARY == NULL) {
if(FT_Init_FreeType(&Font::LIBRARY) != 0) {
std::cout << "Error: Unable to initialize FreeType Library" << std::endl;
return;
}
}
}
Vector2 — это простая структура с полями x и y, которые при создании инициализируются равными 0.
to_nearest_pow2
определяется как:
template<typename T>
T to_nearest_pow2(const T num) {
T nearest = 2;
while((nearest <<= 1) < num);
return nearest;
}
О, и вот как я рисую это на экране (я использую ортографическую проекцию)
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, test->get_texture());
glBegin(GL_QUADS);
glTexCoord2i(0, 0); glVertex2i(0, 0);
glTexCoord2i(1, 0); glVertex2i(400, 0);
glTexCoord2i(1, 1); glVertex2i(400, 400);
glTexCoord2i(0, 1); glVertex2i(0, 400);
glEnd();
редактировать
Я изменился index
к тому, что было предложено @shouston, и теперь я получаю этот вывод
Измените масштаб выходного изображения на что-то вроде 1000×60, и вы получите сюрприз. Вот то, что paint.net сделал из PNG, который вы прикрепили.
Сначала очевидные вещи. Символы в основном там, но по какой-то причине вы; вы просто делаете их очень маленькими (какое значение size
ты прошел?)
Кроме того, вы не пытаетесь обрабатывать какие-либо метрики символов произвольного типа, поэтому не ожидайте, что все они выстроятся в очередь. еще…
Проблема с индексом в вашем буфере текстур:
int index = h * bitmapWidth + pen.x;
должно быть
int index = h * width_ + pen.x;
т.е. мы умножаем h на полную ширину текстуры, а не на ширину глифа.