Я пытаюсь отобразить двунаправленный текст , используя fribidi + harfbuzz + freetype . Код, который дал мне наилучший возможный результат, здесь, наряду с изображением результата.
Проблема очевидна на изображении: некоторые буквы появляются как квадраты.
Как я могу решить проблему?
Я использую все библиотеки от MSYS2.#include
#include
#include
#include
#include
#include
#include
#include
#include FT_FREETYPE_H
#include
#include
#include // Include the FriBidi header
#include
#include
#include
// Window settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;
// Struct to hold information about a rendered glyph
struct Character {
unsigned int TextureID;
glm::ivec2 Size;
glm::ivec2 Bearing;
};
// A cache to store loaded characters to avoid reloading them every frame
std::map CharactersCache;
unsigned int textVAO, textVBO;
// Shaders for rendering text
const char* textVertexShaderSource = "#version 330 core\nlayout (location = 0) in vec4 vertex; out vec2 TexCoords; uniform mat4 projection; void main() { gl_Position = projection * vec4(vertex.xy, 0.0, 1.0); TexCoords = vertex.zw; }";
const char* textFragmentShaderSource = "#version 330 core\nin vec2 TexCoords; out vec4 color; uniform sampler2D text; uniform vec3 textColor; void main() { vec4 sampled = vec4(1.0, 1.0, 1.0, texture(text, TexCoords).r); color = vec4(textColor, 1.0) * sampled; }";
// The final rendering function
void RenderShapedText(unsigned int shader, FT_Face face, hb_buffer_t *hb_buf, float x, float y, glm::vec3 color);
int main()
{
// --- Initialize GLFW and GLAD ---
if (!glfwInit()) { return -1; }
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "Correct Bilingual Text Rendering", NULL, NULL);
if (window == NULL) { glfwTerminate(); return -1; }
glfwMakeContextCurrent(window);
if (!gladLoadGLLoader((GLloadproc)glfwGetProcAddress)) { return -1; }
glViewport(0, 0, SCR_WIDTH, SCR_HEIGHT);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// --- Build the text shader program ---
unsigned int textShaderProgram;
{
unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vertexShader, 1, &textVertexShaderSource, NULL); glCompileShader(vertexShader);
unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fragmentShader, 1, &textFragmentShaderSource, NULL); glCompileShader(fragmentShader);
textShaderProgram = glCreateProgram(); glAttachShader(textShaderProgram, vertexShader); glAttachShader(textShaderProgram, fragmentShader); glLinkProgram(textShaderProgram);
glDeleteShader(vertexShader); glDeleteShader(fragmentShader);
}
glm::mat4 projection = glm::ortho(0.0f, static_cast(SCR_WIDTH), 0.0f, static_cast(SCR_HEIGHT));
glUseProgram(textShaderProgram);
glUniformMatrix4fv(glGetUniformLocation(textShaderProgram, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
// --- Initialize FreeType and HarfBuzz ---
FT_Library ft; if (FT_Init_FreeType(&ft)) { return -1; }
FT_Face face; if (FT_New_Face(ft, "fonts/Cairo-Regular.ttf", 0, &face)) { return -1; }
FT_Set_Pixel_Sizes(face, 0, 36);
hb_font_t *hb_font = hb_ft_font_create(face, NULL);
// ====================== BiDi Analysis and Reordering using FriBidi ======================
const char *text = "مرحبا انا استخدم freetype";
const FriBidiStrIndex byte_len = strlen(text);
// 1. Decode the UTF-8 string into Unicode Codepoints (Logical Order)
std::vector logical_str(byte_len);
// Fix 1: Capture the actual number of codepoints, which is different from the byte length.
const FriBidiStrIndex codepoint_len = fribidi_charset_to_unicode(FRIBIDI_CHAR_SET_UTF8, text, byte_len, logical_str.data());
// 2. Analyze the text to determine paragraph direction and embedding levels
FriBidiParType par_type = FRIBIDI_PAR_ON; // ON = Auto-detect paragraph direction
// Fix 2: Use the correct codepoint length for containers
std::vector levels(codepoint_len);
fribidi_get_par_embedding_levels_ex(logical_str.data(), NULL, codepoint_len, &par_type, levels.data());
// 3. Reorder: Convert the text from Logical Order to Visual Order
std::vector visual_str(codepoint_len);
fribidi_log2vis(logical_str.data(), codepoint_len, &par_type, visual_str.data(), NULL, NULL, NULL);
// ====================================================================================
// ====================== Shape the visually ordered text using HarfBuzz ======================
hb_buffer_t* hb_buf = hb_buffer_create();
// Use add_codepoints because we are now dealing with Unicode codepoints directly
// Fix 3: Use the correct codepoint length when adding characters to the buffer
hb_buffer_add_codepoints(hb_buf, visual_str.data(), codepoint_len, 0, codepoint_len);
// Since the text is now visually ordered, we always process it Left-to-Right
hb_buffer_set_direction(hb_buf, HB_DIRECTION_LTR);
hb_buffer_guess_segment_properties(hb_buf); // Let HarfBuzz guess script/language for shaping
hb_shape(hb_font, hb_buf, NULL, 0);
// ===================================================================================
// --- Calculate text width for alignment ---
float text_width = 0;
unsigned int glyph_count;
hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(hb_buf, &glyph_count);
for (unsigned int i = 0; i < glyph_count; ++i) {
text_width += glyph_pos.x_advance / 64.0f;
}
// --- Setup OpenGL objects for text rendering ---
glGenVertexArrays(1, &textVAO); glGenBuffers(1, &textVBO);
glBindVertexArray(textVAO); glBindBuffer(GL_ARRAY_BUFFER, textVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6 * 4, NULL, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(0); glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);
glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0);
// --- Render Loop ---
while (!glfwWindowShouldClose(window))
{
glClearColor(0.9f, 0.9f, 0.9f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
// Since the entire text is now visually LTR, we always align to the left for centering
float start_x = (SCR_WIDTH / 2.0f) - (text_width / 2.0f);
float text_y = 300.0f;
RenderShapedText(textShaderProgram, face, hb_buf, start_x, text_y, glm::vec3(0.1, 0.1, 0.1));
glfwSwapBuffers(window);
glfwPollEvents();
}
// --- Cleanup Resources ---
hb_buffer_destroy(hb_buf);
hb_font_destroy(hb_font);
FT_Done_Face(face);
FT_Done_FreeType(ft);
glfwTerminate();
return 0;
}
void RenderShapedText(unsigned int shader, FT_Face face, hb_buffer_t *hb_buf, float x, float y, glm::vec3 color)
{
glUseProgram(shader);
glUniform3f(glGetUniformLocation(shader, "textColor"), color.x, color.y, color.z);
glActiveTexture(GL_TEXTURE0);
glBindVertexArray(textVAO);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
unsigned int glyph_count;
hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos(hb_buf, &glyph_count);
hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(hb_buf, &glyph_count);
float cursor_x = x;
for (unsigned int i = 0; i < glyph_count; i++) {
unsigned int glyph_index = glyph_info.codepoint;
// Check if we have already loaded this glyph
if (CharactersCache.find(glyph_index) == CharactersCache.end()) {
// Load and render the glyph using FreeType
if (FT_Load_Glyph(face, glyph_index, FT_LOAD_RENDER)) continue;
// Generate texture for the glyph
unsigned int texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, face->glyph->bitmap.width, face->glyph->bitmap.rows, 0, GL_RED, GL_UNSIGNED_BYTE, face->glyph->bitmap.buffer);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Store character for later use
Character character = { texture, glm::ivec2(face->glyph->bitmap.width, face->glyph->bitmap.rows), glm::ivec2(face->glyph->bitmap_left, face->glyph->bitmap_top) };
CharactersCache.insert({glyph_index, character});
}
Character ch = CharactersCache[glyph_index];
// Calculate glyph position using HarfBuzz's precise metrics
float x_pos = cursor_x + (glyph_pos.x_offset / 64.0f);
float y_pos = y + (glyph_pos.y_offset / 64.0f);
// Adjust position based on FreeType's bearing values
x_pos += ch.Bearing.x;
y_pos -= (ch.Size.y - ch.Bearing.y);
float w = ch.Size.x;
float h = ch.Size.y;
// Define vertices for the quad that will hold the glyph
float vertices[6][4] = {
{ x_pos, y_pos + h, 0.0f, 0.0f }, { x_pos, y_pos, 0.0f, 1.0f }, { x_pos + w, y_pos, 1.0f, 1.0f },
{ x_pos, y_pos + h, 0.0f, 0.0f }, { x_pos + w, y_pos, 1.0f, 1.0f }, { x_pos + w, y_pos + h, 1.0f, 0.0f }
};
// Render the glyph texture over the quad
if(ch.TextureID != 0) {
glBindTexture(GL_TEXTURE_2D, ch.TextureID);
glBindBuffer(GL_ARRAY_BUFFER, textVBO);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glDrawArrays(GL_TRIANGLES, 0, 6);
}
// Advance the cursor for the next glyph
cursor_x += (glyph_pos.x_advance / 64.0f);
}
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
}
Построить файл:
cmake_minimum_required(VERSION 3.10)
project(freetype_test)
# Set C++ standards
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
# Set MSYS2 path
set(MSYS2_MINGW_PREFIX "D:/MSYS2/mingw64")
set(CMAKE_PREFIX_PATH ${MSYS2_MINGW_PREFIX})
# Find GLFW package
find_package(glfw3 REQUIRED)
# Create the application
add_executable(app
src/main.cpp
src/glad.cpp
)
# Add include directories
target_include_directories(app PRIVATE
include # glad.h
${MSYS2_MINGW_PREFIX}/include
${MSYS2_MINGW_PREFIX}/include/freetype2
${MSYS2_MINGW_PREFIX}/include/harfbuzz
${MSYS2_MINGW_PREFIX}/include/fribidi
)
# Link libraries
target_link_libraries(app PRIVATE
freetype
harfbuzz
fribidi
glfw3
opengl32
gdi32
)
# Copy fonts folder to build directory
add_custom_command(
TARGET app POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_SOURCE_DIR}/fonts ${CMAKE_BINARY_DIR}/fonts
)
< /code>
Структура проекта: < /p>
project/
--build/
--fonts/
--Cairo-Regular.ttf
--src/
--main.cpp
--glad.cpp
--include
--glm/
--glad/
--glad.h
--CMakelists.txt
Подробнее здесь: https://stackoverflow.com/questions/797 ... ng-fribidi
Двунаправленный текст рендеринг с использованием fribidi ⇐ C++
Программы на C++. Форум разработчиков
-
Anonymous
1756824288
Anonymous
Я пытаюсь отобразить [b] двунаправленный текст [/b], используя fribidi + harfbuzz + freetype . Код, который дал мне наилучший возможный результат, здесь, наряду с изображением результата.
Проблема очевидна на изображении: некоторые буквы появляются как квадраты.
Как я могу решить проблему?
Я использую все библиотеки от MSYS2.#include
#include
#include
#include
#include
#include
#include
#include
#include FT_FREETYPE_H
#include
#include
#include // Include the FriBidi header
#include
#include
#include
// Window settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;
// Struct to hold information about a rendered glyph
struct Character {
unsigned int TextureID;
glm::ivec2 Size;
glm::ivec2 Bearing;
};
// A cache to store loaded characters to avoid reloading them every frame
std::map CharactersCache;
unsigned int textVAO, textVBO;
// Shaders for rendering text
const char* textVertexShaderSource = "#version 330 core\nlayout (location = 0) in vec4 vertex; out vec2 TexCoords; uniform mat4 projection; void main() { gl_Position = projection * vec4(vertex.xy, 0.0, 1.0); TexCoords = vertex.zw; }";
const char* textFragmentShaderSource = "#version 330 core\nin vec2 TexCoords; out vec4 color; uniform sampler2D text; uniform vec3 textColor; void main() { vec4 sampled = vec4(1.0, 1.0, 1.0, texture(text, TexCoords).r); color = vec4(textColor, 1.0) * sampled; }";
// The final rendering function
void RenderShapedText(unsigned int shader, FT_Face face, hb_buffer_t *hb_buf, float x, float y, glm::vec3 color);
int main()
{
// --- Initialize GLFW and GLAD ---
if (!glfwInit()) { return -1; }
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "Correct Bilingual Text Rendering", NULL, NULL);
if (window == NULL) { glfwTerminate(); return -1; }
glfwMakeContextCurrent(window);
if (!gladLoadGLLoader((GLloadproc)glfwGetProcAddress)) { return -1; }
glViewport(0, 0, SCR_WIDTH, SCR_HEIGHT);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// --- Build the text shader program ---
unsigned int textShaderProgram;
{
unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vertexShader, 1, &textVertexShaderSource, NULL); glCompileShader(vertexShader);
unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fragmentShader, 1, &textFragmentShaderSource, NULL); glCompileShader(fragmentShader);
textShaderProgram = glCreateProgram(); glAttachShader(textShaderProgram, vertexShader); glAttachShader(textShaderProgram, fragmentShader); glLinkProgram(textShaderProgram);
glDeleteShader(vertexShader); glDeleteShader(fragmentShader);
}
glm::mat4 projection = glm::ortho(0.0f, static_cast(SCR_WIDTH), 0.0f, static_cast(SCR_HEIGHT));
glUseProgram(textShaderProgram);
glUniformMatrix4fv(glGetUniformLocation(textShaderProgram, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
// --- Initialize FreeType and HarfBuzz ---
FT_Library ft; if (FT_Init_FreeType(&ft)) { return -1; }
FT_Face face; if (FT_New_Face(ft, "fonts/Cairo-Regular.ttf", 0, &face)) { return -1; }
FT_Set_Pixel_Sizes(face, 0, 36);
hb_font_t *hb_font = hb_ft_font_create(face, NULL);
// ====================== BiDi Analysis and Reordering using FriBidi ======================
const char *text = "مرحبا انا استخدم freetype";
const FriBidiStrIndex byte_len = strlen(text);
// 1. Decode the UTF-8 string into Unicode Codepoints (Logical Order)
std::vector logical_str(byte_len);
// Fix 1: Capture the actual number of codepoints, which is different from the byte length.
const FriBidiStrIndex codepoint_len = fribidi_charset_to_unicode(FRIBIDI_CHAR_SET_UTF8, text, byte_len, logical_str.data());
// 2. Analyze the text to determine paragraph direction and embedding levels
FriBidiParType par_type = FRIBIDI_PAR_ON; // ON = Auto-detect paragraph direction
// Fix 2: Use the correct codepoint length for containers
std::vector levels(codepoint_len);
fribidi_get_par_embedding_levels_ex(logical_str.data(), NULL, codepoint_len, &par_type, levels.data());
// 3. Reorder: Convert the text from Logical Order to Visual Order
std::vector visual_str(codepoint_len);
fribidi_log2vis(logical_str.data(), codepoint_len, &par_type, visual_str.data(), NULL, NULL, NULL);
// ====================================================================================
// ====================== Shape the visually ordered text using HarfBuzz ======================
hb_buffer_t* hb_buf = hb_buffer_create();
// Use add_codepoints because we are now dealing with Unicode codepoints directly
// Fix 3: Use the correct codepoint length when adding characters to the buffer
hb_buffer_add_codepoints(hb_buf, visual_str.data(), codepoint_len, 0, codepoint_len);
// Since the text is now visually ordered, we always process it Left-to-Right
hb_buffer_set_direction(hb_buf, HB_DIRECTION_LTR);
hb_buffer_guess_segment_properties(hb_buf); // Let HarfBuzz guess script/language for shaping
hb_shape(hb_font, hb_buf, NULL, 0);
// ===================================================================================
// --- Calculate text width for alignment ---
float text_width = 0;
unsigned int glyph_count;
hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(hb_buf, &glyph_count);
for (unsigned int i = 0; i < glyph_count; ++i) {
text_width += glyph_pos[i].x_advance / 64.0f;
}
// --- Setup OpenGL objects for text rendering ---
glGenVertexArrays(1, &textVAO); glGenBuffers(1, &textVBO);
glBindVertexArray(textVAO); glBindBuffer(GL_ARRAY_BUFFER, textVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6 * 4, NULL, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(0); glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);
glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0);
// --- Render Loop ---
while (!glfwWindowShouldClose(window))
{
glClearColor(0.9f, 0.9f, 0.9f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
// Since the entire text is now visually LTR, we always align to the left for centering
float start_x = (SCR_WIDTH / 2.0f) - (text_width / 2.0f);
float text_y = 300.0f;
RenderShapedText(textShaderProgram, face, hb_buf, start_x, text_y, glm::vec3(0.1, 0.1, 0.1));
glfwSwapBuffers(window);
glfwPollEvents();
}
// --- Cleanup Resources ---
hb_buffer_destroy(hb_buf);
hb_font_destroy(hb_font);
FT_Done_Face(face);
FT_Done_FreeType(ft);
glfwTerminate();
return 0;
}
void RenderShapedText(unsigned int shader, FT_Face face, hb_buffer_t *hb_buf, float x, float y, glm::vec3 color)
{
glUseProgram(shader);
glUniform3f(glGetUniformLocation(shader, "textColor"), color.x, color.y, color.z);
glActiveTexture(GL_TEXTURE0);
glBindVertexArray(textVAO);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
unsigned int glyph_count;
hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos(hb_buf, &glyph_count);
hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(hb_buf, &glyph_count);
float cursor_x = x;
for (unsigned int i = 0; i < glyph_count; i++) {
unsigned int glyph_index = glyph_info[i].codepoint;
// Check if we have already loaded this glyph
if (CharactersCache.find(glyph_index) == CharactersCache.end()) {
// Load and render the glyph using FreeType
if (FT_Load_Glyph(face, glyph_index, FT_LOAD_RENDER)) continue;
// Generate texture for the glyph
unsigned int texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, face->glyph->bitmap.width, face->glyph->bitmap.rows, 0, GL_RED, GL_UNSIGNED_BYTE, face->glyph->bitmap.buffer);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Store character for later use
Character character = { texture, glm::ivec2(face->glyph->bitmap.width, face->glyph->bitmap.rows), glm::ivec2(face->glyph->bitmap_left, face->glyph->bitmap_top) };
CharactersCache.insert({glyph_index, character});
}
Character ch = CharactersCache[glyph_index];
// Calculate glyph position using HarfBuzz's precise metrics
float x_pos = cursor_x + (glyph_pos[i].x_offset / 64.0f);
float y_pos = y + (glyph_pos[i].y_offset / 64.0f);
// Adjust position based on FreeType's bearing values
x_pos += ch.Bearing.x;
y_pos -= (ch.Size.y - ch.Bearing.y);
float w = ch.Size.x;
float h = ch.Size.y;
// Define vertices for the quad that will hold the glyph
float vertices[6][4] = {
{ x_pos, y_pos + h, 0.0f, 0.0f }, { x_pos, y_pos, 0.0f, 1.0f }, { x_pos + w, y_pos, 1.0f, 1.0f },
{ x_pos, y_pos + h, 0.0f, 0.0f }, { x_pos + w, y_pos, 1.0f, 1.0f }, { x_pos + w, y_pos + h, 1.0f, 0.0f }
};
// Render the glyph texture over the quad
if(ch.TextureID != 0) {
glBindTexture(GL_TEXTURE_2D, ch.TextureID);
glBindBuffer(GL_ARRAY_BUFFER, textVBO);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glDrawArrays(GL_TRIANGLES, 0, 6);
}
// Advance the cursor for the next glyph
cursor_x += (glyph_pos[i].x_advance / 64.0f);
}
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
}
Построить файл:
cmake_minimum_required(VERSION 3.10)
project(freetype_test)
# Set C++ standards
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
# Set MSYS2 path
set(MSYS2_MINGW_PREFIX "D:/MSYS2/mingw64")
set(CMAKE_PREFIX_PATH ${MSYS2_MINGW_PREFIX})
# Find GLFW package
find_package(glfw3 REQUIRED)
# Create the application
add_executable(app
src/main.cpp
src/glad.cpp
)
# Add include directories
target_include_directories(app PRIVATE
include # glad.h
${MSYS2_MINGW_PREFIX}/include
${MSYS2_MINGW_PREFIX}/include/freetype2
${MSYS2_MINGW_PREFIX}/include/harfbuzz
${MSYS2_MINGW_PREFIX}/include/fribidi
)
# Link libraries
target_link_libraries(app PRIVATE
freetype
harfbuzz
fribidi
glfw3
opengl32
gdi32
)
# Copy fonts folder to build directory
add_custom_command(
TARGET app POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_SOURCE_DIR}/fonts ${CMAKE_BINARY_DIR}/fonts
)
< /code>
Структура проекта: < /p>
project/
--build/
--fonts/
--Cairo-Regular.ttf
--src/
--main.cpp
--glad.cpp
--include
--glm/
--glad/
--glad.h
--CMakelists.txt
Подробнее здесь: [url]https://stackoverflow.com/questions/79753625/bidirectional-text-rendering-using-fribidi[/url]
Ответить
1 сообщение
• Страница 1 из 1
Перейти
- Кемерово-IT
- ↳ Javascript
- ↳ C#
- ↳ JAVA
- ↳ Elasticsearch aggregation
- ↳ Python
- ↳ Php
- ↳ Android
- ↳ Html
- ↳ Jquery
- ↳ C++
- ↳ IOS
- ↳ CSS
- ↳ Excel
- ↳ Linux
- ↳ Apache
- ↳ MySql
- Детский мир
- Для души
- ↳ Музыкальные инструменты даром
- ↳ Печатная продукция даром
- Внешняя красота и здоровье
- ↳ Одежда и обувь для взрослых даром
- ↳ Товары для здоровья
- ↳ Физкультура и спорт
- Техника - даром!
- ↳ Автомобилистам
- ↳ Компьютерная техника
- ↳ Плиты: газовые и электрические
- ↳ Холодильники
- ↳ Стиральные машины
- ↳ Телевизоры
- ↳ Телефоны, смартфоны, плашеты
- ↳ Швейные машинки
- ↳ Прочая электроника и техника
- ↳ Фототехника
- Ремонт и интерьер
- ↳ Стройматериалы, инструмент
- ↳ Мебель и предметы интерьера даром
- ↳ Cантехника
- Другие темы
- ↳ Разное даром
- ↳ Давай меняться!
- ↳ Отдам\возьму за копеечку
- ↳ Работа и подработка в Кемерове
- ↳ Давай с тобой поговорим...
Мобильная версия