/
FaDaQ
/
ModernGL-Demo
Обзор
Документация
Войти
/
FaDaQ
/
ModernGL-Demo
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
label.py
189 строк
6 KB
FaDaQ
create: camera.py, cube.py, instanced_draw.py, label.py, settings.json, transform.py, fluid.png, grass.png, meteor.png, planks.png, stone.jpg
02 июн 2026, 14:37
Верифицирован
02 июн 2026, 14:37
db0a0b4
Код
Авторство
О чём код?
import moderngl as mgl import pygame as pg import numpy as np from pyglm import glm class Label2D: # Базовый размер шрифта для рендеринга в текстуру (чем больше, тем четче при увеличении) BASE_RENDER_SIZE = 24 def __init__(self, gl_context: mgl.Context, text: str, font_family: str = "Arial", font_size: int = 24, font_color: tuple | list = (255, 255, 255)): self.position = glm.vec2(0, 0) self.rotation: float = 0.0 self.pivot = glm.vec2(0.5, 0.5) self.gl = gl_context self.__text = text self.__font_size = font_size self.__font_color = font_color self.__font_family = font_family # Шрифт всегда создается одного большого размера self.__pg_font = pg.font.SysFont(font_family, self.BASE_RENDER_SIZE) self.__texture: mgl.Texture = None self.__update_text() if not self.__shader: self.__shader = self.gl.program( vertex_shader= """ #version 460 core in vec2 inPos; in vec2 inUV; out vec2 UV; uniform mat4 projection; uniform mat4 model; void main() { gl_Position = projection * model * vec4(inPos, 0.0, 1.0); UV = inUV; } """, fragment_shader= """ #version 460 core in vec2 UV; out vec4 fragColor; uniform sampler2D aTexture; void main() { fragColor = texture(aTexture, UV); } """ ) vbo = self.gl.buffer( np.ascontiguousarray(np.array( [ -0.5, -0.5, 0.0, 0.0, -0.5, 0.5, 0.0, 1.0, 0.5, 0.5, 1.0, 1.0, 0.5, -0.5, 1.0, 0.0 ], dtype=np.float32 )) ) ibo = self.gl.buffer(np.array([0, 1, 2, 0, 3, 2], dtype=np.uint32)) self.__vao = self.gl.vertex_array( self.__shader, [ (vbo, "2f 2f", "inPos", "inUV") ], index_buffer=ibo ) @property def text(self): return self.__text @text.setter def text(self, value: str): self.__text = value self.__update_text() @property def font_size(self): return self.__font_size @font_size.setter def font_size(self, value: int): self.__font_size = value # Текстурку пересоздавать не нужно, она у нас универсальная! @property def font_color(self): return self.__font_color @font_color.setter def font_color(self, value: tuple[int, int, int, int] | tuple[int, int, int]): self.__font_color = value self.__update_text() @property def font_family(self): return self.__font_family @font_family.setter def font_family(self, value): self.__font_family = value self.__pg_font = pg.font.SysFont(value, self.BASE_RENDER_SIZE) self.__update_text() def draw(self): viewport = self.gl.viewport # Реальные размеры текстуры (она большая, например 170px высотой) tex_w = self.__texture.width tex_h = self.__texture.height # Коэффициент масштабирования: какой размер мы хотим видеть / какой размер у текстуры scale_factor = self.__font_size / self.BASE_RENDER_SIZE # Итоговый размер квада на экране в пикселях target_w = tex_w * scale_factor target_h = tex_h * scale_factor model = glm.mat4(1) # 1. Позиция model = glm.translate(model, glm.vec3(round(self.position.x), round(self.position.y), 0.0)) # 2. Вращение model = glm.rotate(model, glm.radians(self.rotation), glm.vec3(0, 0, 1)) # 3. Учет Pivot # Сдвигаем так, чтобы pivot оказался в (0,0) локальных координат перед масштабированием offset_x = -self.pivot.x * target_w offset_y = -self.pivot.y * target_h model = glm.translate(model, glm.vec3(offset_x, offset_y, 0.0)) # 4. Масштабирование до нужного размера # Умножаем на 2, т.к. VBO от -0.5 до 0.5 (единичный квадрат) model = glm.scale(model, glm.vec3(target_w * 2, target_h * 2, 1.0)) model = glm.transpose(model) ortho = glm.transpose(glm.ortho(0, viewport[2], viewport[3], 0)) if "projection" in self.__shader: self.__shader["projection"].write(np.ascontiguousarray(np.array(ortho, dtype=np.float32))) if "model" in self.__shader: self.__shader["model"].write(np.ascontiguousarray(np.array(model, dtype=np.float32))) self.gl.enable(mgl.BLEND) self.gl.blend_func = mgl.SRC_ALPHA, mgl.ONE_MINUS_SRC_ALPHA self.__texture.use(1) self.__shader["aTexture"] = 1 self.__vao.render(mgl.TRIANGLES) self.gl.disable(mgl.BLEND) def __update_text(self): if not self.text: size = (1, 1) else: size = self.__pg_font.size(self.text) pg_label = pg.Surface(size, pg.SRCALPHA) if self.text: text_surf = self.__pg_font.render(self.text, True, self.__font_color) pg_label.blit(text_surf, (0, 0)) self.__texture = self.gl.texture(pg_label.get_size(), 4, pg.image.tobytes(pg_label, "RGBA")) self.__texture.repeat_x = False self.__texture.repeat_y = False # LINEAR важен здесь, чтобы при нецелочисленном масштабировании текст не "дрожал" self.__texture.filter = (mgl.LINEAR, mgl.LINEAR) __shader = None