OpenGL

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

OpenGL

Сообщение AlexPavel » 02.01.2010 22:49:04

Привет всем.
Как реализовать, используя OpenGL, вывод текста, используя шрифт?
Это необходимо для подписи осей координат, вывода шкалы(для МКЭ) и т.п. :?:
AlexPavel
новенький
 
Сообщения: 12
Зарегистрирован: 28.12.2009 20:31:43

Re: OpenGL

Сообщение скалогрыз » 03.01.2010 00:12:55

самый примитивный способ: glutStrokeCharacter (только для символов #32..#127)

если использовать системный шрифт, то нужно использовать системные (wgl* - Windows, glx* - XWindow) функции загрузки шрифтов и их рендеринга.

ещё вариант, используя, например TBitmap рендерить текст в буфер, а потом этот буфер использовать в качестве текстуры в OpenGL. можно это делать не используя LCL, а скажем SDL (sdl_ttf)... или другие кроссплатформенные графические библиотеки.

ещё лучше - геймерскйи вариант: подготовить картинки, с надписями, которые будут использоваться как текстуры. Единственное отличие (от использования tbitmap), что они отрисованы заранее, а не во время исполнения программы.

отрисовывать лучше именно через текстуры (или glutStrokeCharacter), потому что операция glWritePixels жутко тормозная!


вот хороший сайт, где многие вещи разжёваны, и куча примеров (и статей) на delphi: http://gamedev.ru
скалогрыз
долгожитель
 
Сообщения: 1803
Зарегистрирован: 03.09.2008 02:36:48

Re: OpenGL

Сообщение AlexPavel » 03.01.2010 01:54:13

Если возможно, представьте код, реализующий вывод текста с использованием системного шрифта. Применение текстуры не подходит, т.к. выводимая информация меняется.
AlexPavel
новенький
 
Сообщения: 12
Зарегистрирован: 28.12.2009 20:31:43

Re: OpenGL

Сообщение *vmr » 03.01.2010 02:46:37

Вот, выдрал код из проекта пятилетней давности...

Создание фонта:
Код: Выделить всё
      Base := glGenLists(256);  // Выделим место для 256 символов
      font := CreateFont(  height,0,0,0,b,i,0,0, ANSI_CHARSET,OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS,
                           ANTIALIASED_QUALITY, FF_DONTCARE or DEFAULT_PITCH,PChar(name_));

      old := SelectObject(Screen.DC, font);        // Выбрать шрифт, созданный нами

      wglUseFontBitmaps(Screen.DC, 0, 255, Base); // Построить 96 символов начиная с пробела
      SelectObject(Screen.DC, old); 
      DeleteObject(font);


Юзаем где-то так:
Код: Выделить всё
       glPushMatrix;
       glLoadIdentity;
       glRasterPos2F(x,y)

       glPushAttrib(GL_LIST_BIT);
       glListBase(Base);          // Задать базу символа
       glCallLists(length(str), GL_UNSIGNED_BYTE, @str[1]); // Текст списками отображения
       glPopAttrib;
       glPopMatrix;
Аватара пользователя
*vmr
постоялец
 
Сообщения: 168
Зарегистрирован: 08.01.2007 01:46:07
Откуда: Киев

Re: OpenGL

Сообщение скалогрыз » 03.01.2010 03:07:27

AlexPavel писал(а):Если возможно, представьте код, реализующий вывод текста с использованием системного шрифта. Применение текстуры не подходит, т.к. выводимая информация меняется.

возможно... хотя, ничто не мешает изменять содержимое текстуры :) glTexSubImage2D
либо пересоздать текстуру с новым содержимым.

кодом делиться не буду, ибо проперитарщина (да и я жаден) :twisted:
скалогрыз
долгожитель
 
Сообщения: 1803
Зарегистрирован: 03.09.2008 02:36:48

Re: OpenGL

Сообщение @lex » 18.04.2022 11:38:37

Добрый день. Столкнулся с обозначенной задачей при реализации своего проекта. Все найденные примеры из сети как-то сходу не заработали, поэтому написал свой метод. Не претендую на оптимальность решений и высокую скорость работы, но в рамках объекта на форме, использующего только 2D, работает очень даже неплохо. Если не присматриваться, то текст почти не отличим от того, что выводится на обычных Label-ах. Оставлю тут, может кому пригодится.
На форме используются TImg: TImage (размер 16 на 16, можно невидимый) и ViewPanel: TOpenGLControl. Перед первым выводом текста вызываем GLPrepareFont.
Используются только стандартные библиотеки OpenGL Lazarus. Проверялось только в Windows x86.
Код: Выделить всё
unit f_main;

{$mode objfpc}{$H+}

interface

uses
  ... OpenGLContext, GL, LazUTF8;

type

  { TMainForm }

  TMainForm = class(TForm)
    ...
    TImg: TImage;
    ViewPanel: TOpenGLControl;
    ...
  private
    ...
    function VPGLX(X: integer): double;
    function VPGLY(Y: integer): double;
    procedure GLPrepareFont;
    procedure MakeCharTexture(C: byte; var tmem: pbyte);
    procedure GLWriteText(Txt: string; X,Y: integer);
    ...
  end;

var
  MainForm: TMainForm;
  FontHeight, CharWidth: word;
  TTID: array [0..255] of GLuint;
  TTData: array [0..255] of ^Byte;
  TTW: array [0..255] of byte;

implementation

...

function TMainForm.VPGLX(X: integer): double;
begin //Пересчёт координаты X
VPGLX:=(X*2 / ViewPanel.ClientWidth) - 1;
end;

function TMainForm.VPGLY(Y: integer): double;
begin //Пересчёт координаты Y
VPGLY:=1 - (Y*2 / ViewPanel.ClientHeight);
end;

procedure TMainForm.MakeCharTexture(C: byte; var tmem: pbyte);
var //Создание текстуры для отдельного символа
x: integer;
b: byte;
s: string;
begin
s:=WinCPToUTF8(chr(C));
//Запоминаем реальную ширину символа
TTW[c]:=TImg.Canvas.TextWidth(s);
if (TTW[c] > CharWidth) then TTW[c]:=CharWidth;
//Вывод символа в TImage
TImg.Picture.Bitmap.Canvas.Clear;
TImg.Picture.Bitmap.Canvas.Brush.Color:=clWhite;
TImg.Picture.Bitmap.Canvas.FillRect(Rect(0,0,CharWidth,FontHeight));
TImg.Picture.Bitmap.Canvas.Font.Color:=clBlack; //Цвет шрифта
TImg.Picture.Bitmap.Canvas.TextOut(0,0,s);
Application.ProcessMessages;
//Копируем изображение символа в текстуру
GetMem(tmem,CharWidth*FontHeight*4);
tmem:=TImg.Picture.Bitmap.RawImage.Data;
for x:=0 to (CharWidth*FontHeight-1) do
  begin
   {$IFDEF WINDOWS}
   //Расставляем цвета на свои места в Windows
   b:=tmem[x*4];
   tmem[x*4]:=tmem[x*4+2];
   tmem[x*4+2]:=b;
   {$ENDIF}
   //Прописываем альфу на основе красного цвета
   if (tmem[x*4]=255) then tmem[x*4+3]:=0 else tmem[x*4+3]:=255;
  end;
end;

procedure TMainForm.GLPrepareFont;
var //Подготовка шрифта. Вызывать один раз до первого вывода текста, например при FormShow
b: integer;
begin
//Задаём размер шрифта
FontHeight:=16;
CharWidth:=16;
TImg.Canvas.Font.Height:=FontHeight;
TImg.Picture.Bitmap.PixelFormat:=pf32bit;
TImg.Picture.Bitmap.Height:=FontHeight;
TImg.Picture.Bitmap.Width:=CharWidth;
ViewPanel.Invalidate;
//Подготовка текстур
glEnable(GL_TEXTURE_2D);
glGenTextures(256, @TTID[0]);
for b:=32 to 255 do
  begin //Цикл создания текстур
   {if (b mod 5 = 0) then
    StatusBar1.SimpleText:='Подготовка шрифта OpenGL... '+inttostr(b*100 div 255)+' %'; }
   MakeCharTexture(b,TTData[b]);
   glBindTexture(GL_TEXTURE_2D, TTID[b]);
   glTexImage2D(GL_TEXTURE_2D, 0, 4, CharWidth, FontHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, TTData[b]);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  end;
end;

procedure TMainForm.GLWriteText(Txt: string; X,Y: integer);
var //Вывод строки. Координаты задаём целыми числами, как при работе с обычным Canvas
n,i: integer;
c: byte;
s: ansistring;
begin
i:=X;
glColor3b(127,127,127);
s:=UTF8ToWinCP(Txt);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
for n:=1 to length(s) do
  begin
   c:=ord(s[n]);
   if (c<32) then continue;
   glEnable(GL_TEXTURE_2D);
   glBindTexture(GL_TEXTURE_2D, TTID[c]);
   glBegin(GL_QUADS);
   glTexCoord2f(0, 0);
   glVertex2d(VPGLX(i),VPGLY(Y));
   glTexCoord2f(0, 1);
   glVertex2d(VPGLX(i),VPGLY(Y+FontHeight));
   glTexCoord2f(TTW[c]/CharWidth, 1);
   glVertex2d(VPGLX(i+TTW[c]),VPGLY(Y+FontHeight));
   glTexCoord2f(TTW[c]/CharWidth, 0);
   glVertex2d(VPGLX(i+TTW[c]),VPGLY(Y));
   i:=i+TTW[c];
   glEnd;
   glDisable(GL_TEXTURE_2D);
  end;
glDisable(GL_BLEND);
end;

...
//Пример оспользования
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
...
glBegin(...); ... glEnd;
GLWriteText('Text Текст',ViewPanel.ClientWidth div 2, ViewPanel.ClientHeight div 2);
...
ViewPanel.SwapBuffers;
...

end.
@lex
постоялец
 
Сообщения: 180
Зарегистрирован: 19.06.2006 13:16:29
Откуда: Невинномысск

Re: OpenGL

Сообщение Alex2013 » 18.04.2022 12:59:24

Загляни сюда :arrow: OpenGl Рисуем в Фоне, возможно ли?
Там решали похожую здачу .
Использование обычного TBitmap для "фоновой отрисовки" через OpenGl (с 3D тоже работает )
Зы
Что до вывода текста то его можно или нарисовать на битмапе с уже нарисованной OpenGl картинкой обычным путём (через канвас) или сделать "табличку из текстуры" ( удобно для синхронного масштабирования или если нужно вращать надпись в 3д ), а что касается средств работы с текстом из самого OpenGl то они показались мне довольно не надежными (Есть проблемы с шрифтами + не совместимость с счастью "расширенных библиотек" )
Alex2013
долгожитель
 
Сообщения: 2924
Зарегистрирован: 03.04.2013 11:59:44


Вернуться в Lazarus

Кто сейчас на конференции

Сейчас этот форум просматривают: Alex2013 и гости: 29

Рейтинг@Mail.ru