ПрограммированиеФорумГрафика

OpenGL 3.3+ text...

Страницы: 1 2 Следующая »
#0
21:59, 7 сен 2014

Помогите пожалуйста загрузить шрифт и написать какую-нибудь надпись в окне...
Смотрел примеры freetype, oglft. Честно сказать немного внимание рассеивалось... Ну а на многих сайтах используют старые фичи OGL(а я хотел бы сразу делать под OpenGL 3.3+) + используют GLUT(а я его не использую).

Если же примером не поделитесь... То скажите пожалуйста: что хранится в ttf шрифтах? Хочу попробовать самостоятельно загрузить шрифт.
И как, имея загруженный шрифт, дальше с ним работать для рендера текста?


Знаю, вопрос ну ооочень глупый... Многие из вас скорее всего facepalm ставят из-за моего очередного вопроса... Но я правда целый день пытался поработать с текстом, искал, пробовал... Ну не получается у меня( Я знаю как такое сделать с помощью SDL или SFML, но мне хотелось бы более детально в этом всём разобраться...

#1
22:10, 7 сен 2014

В ttf шрифтах хранится геометрическое представление символов в векторном виде, т.е. в виде отрезков/сплайнов и пр., так что нарисовать их сам ты врядли сможешь. Используй freetype, чтобы он тебе нарисовал нужные символы в нужном размере в текстуру, потом просто накладывай эту текстуру.
Более простым наверно способом будет сразу создать текстуру с нужными символами, может даже какой-нибудь сторонней программой. Недостатком такого подхода является то, что во первых нельзя будет программно менять размеры символов, а так же, что набор символов будет фиксирован (т.е. например латинские + русские буквы и пр.), если у тебя текст хранится в Unicode, и вдруг потребуется написать что-нибудь там на немецком/китайском/японском, то ничего не получится (скажем например это онлайн игра с общим чатом, и какой-то японец решил отписаться). С ttf правда тоже не факт, что он будет содержать символы этих языков, но там все равно свободы больше.

#2
22:13, 7 сен 2014

ud1
> freetype, чтобы он тебе нарисовал нужные символы в нужном размере в текстуру,
> потом просто накладывай эту текстуру.
Я бы с радостью, но не смог разобраться. Вполне может быть, что я читал плохой пример. Что-нибудь посоветуете в качестве примера?

#3
22:22, 7 сен 2014

Примеров не знаю. Как так не смог разобраться? Разберись. Читай доки, вникай.

#4
3:49, 8 сен 2014

Laynos
http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-11-2d-text/

#5
10:46, 8 сен 2014

Для 2D текста мне кажется лучше freetype не найти.
Я тоже долго вкуривал эту тему, но результат того стоил. Идея следующая
( из .Net обвязки)
1. Загружаем шрифт
[DllImport(FT_NATIVE_LIBRARY, CallingConvention = CALLING_CONVENTION), SuppressUnmanagedCodeSecurity]
public static extern int FT_New_Memory_Face(IntPtr /*LibraryRec_*/ library, [In] byte[] file_base, int file_size, int face_index, out IntPtr /*IntPtr FaceRec*/ aface);

2. Установка размера
[DllImport(FT_NATIVE_LIBRARY, CallingConvention = CALLING_CONVENTION), SuppressUnmanagedCodeSecurity]
public static extern int FT_Set_Char_Size(IntPtr /*FaceRec*/ face, int char_width, int char_height, uint horz_resolution, uint vert_resolution);

3. Установка размера пикселя
[DllImport(FT_NATIVE_LIBRARY, CallingConvention = CALLING_CONVENTION), SuppressUnmanagedCodeSecurity]
public static extern int FT_Set_Pixel_Sizes(IntPtr /*FaceRec*/ face, uint pixel_width, uint pixel_height);

4. Загрузка символов в текстуры
list_base = Gl.glGenLists(list_base_size);
Gl.glGenTextures(list_base_size, textures);
for (int c = 0; c < list_base_size; c++)
{
  Compile_Character(face, faceptr, (byte)c);
}

        public void Compile_Character(FT_FaceRec face, System.IntPtr faceptr, int c)
        {

            //We first convert the number index to a character index
            uint index = FT.FT_Get_Char_Index(faceptr, c);

            //Here we load the actual glyph for the character
            int ret = FT.FT_Load_Glyph(faceptr, index, (int)FT_LOAD_TYPES.FT_LOAD_DEFAULT);
            if (ret != 0) return;

            //Convert the glyph to a bitmap
            System.IntPtr glyph;
            int retb = FT.FT_Get_Glyph(face.glyph, out glyph);
            if (retb != 0) return;
            //GlyphRec glyph_rec=(GlyphRec)Marshal.PtrToStructure( face.glyphrec, typeof(GlyphRec) );

            FT.FT_Glyph_To_Bitmap(out glyph, FT_RENDER_MODES.FT_RENDER_MODE_LIGHT, 0, 1);
            BitmapGlyph glyph_bmp = (BitmapGlyph)Marshal.PtrToStructure(glyph, typeof(BitmapGlyph));
            int size = (glyph_bmp.bitmap.width * glyph_bmp.bitmap.rows);
            symbolWidth[c] = glyph_bmp.bitmap.width;
            if (size <= 0)
            {
                //space is a special `blank` character
                extent_x[c] = 0;
                if (c == 32)
                {
                    Gl.glNewList((uint)(list_base + c), Gl.GL_COMPILE);
                    Gl.glTranslatef(font_size >> 1, 0, 0);
                    extent_x[c] = font_size >> 1;
                    symbolWidth[c] = font_size >> 1;
                    Gl.glEndList();
                }
                return;
            }

            byte[] bmp = new byte[size];
            Marshal.Copy(glyph_bmp.bitmap.buffer, bmp, 0, bmp.Length);

            //Next we expand the bitmap into an opengl texture       
            int width = next_po2(glyph_bmp.bitmap.width);
            int height = next_po2(glyph_bmp.bitmap.rows);
            byte[] expanded = new byte[2 * width * height];
            for (int j = 0; j < height; j++)
            {
                for (int i = 0; i < width; i++)
                {
                    expanded[2 * (i + j * width)] = expanded[2 * (i + j * width) + 1] =
                        (i >= glyph_bmp.bitmap.width || j >= glyph_bmp.bitmap.rows) ?
                        (byte)0 : bmp[i + glyph_bmp.bitmap.width * j];
                }
            }

            //Set up some texture parameters for opengl
            Gl.glBindTexture(Gl.GL_TEXTURE_2D, textures[c]);
            Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAG_FILTER, Gl.GL_LINEAR);
            Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_LINEAR);

            //Create the texture
            Gl.glTexImage2D(Gl.GL_TEXTURE_2D, 0, Gl.GL_RGBA, width, height,
                0, Gl.GL_LUMINANCE_ALPHA, Gl.GL_UNSIGNED_BYTE, expanded);
            expanded = null;
            bmp = null;

            //Create a display list and bind a texture to it
            Gl.glNewList((uint)(list_base + c), Gl.GL_COMPILE);
            Gl.glBindTexture(Gl.GL_TEXTURE_2D, textures[c]);

            //Account for freetype spacing rules
            Gl.glTranslatef(glyph_bmp.left + ((c>=48 && c<58) ? 1 : 0), 0, 0);
            Gl.glPushMatrix();
            Gl.glTranslatef(0, glyph_bmp.top - glyph_bmp.bitmap.rows, 0);
            float x = (float)glyph_bmp.bitmap.width / (float)width;
            float y = (float)glyph_bmp.bitmap.rows / (float)height;

            //Draw the quad
            Gl.glBegin(Gl.GL_QUADS);
            Gl.glTexCoord2d(0, 0); Gl.glVertex2f(0, glyph_bmp.bitmap.rows);
            Gl.glTexCoord2d(0, y); Gl.glVertex2f(0, 0);
            Gl.glTexCoord2d(x, y); Gl.glVertex2f(glyph_bmp.bitmap.width, 0);
            Gl.glTexCoord2d(x, 0); Gl.glVertex2f(glyph_bmp.bitmap.width, glyph_bmp.bitmap.rows);
            Gl.glEnd();
            Gl.glPopMatrix();

            //Advance for the next character     
            Gl.glTranslatef(glyph_bmp.bitmap.width, 0, 0);
            extent_x[c] = glyph_bmp.left + glyph_bmp.bitmap.width;
            Gl.glEndList();

        }

5. Печать текста

        public void print(float x, float y, string what)
        {
            int font = list_base;

            //Prepare openGL for rendering the font characters
            push_scm();
            Gl.glPushAttrib(Gl.GL_LIST_BIT | Gl.GL_CURRENT_BIT | Gl.GL_ENABLE_BIT | Gl.GL_TRANSFORM_BIT);
            Gl.glMatrixMode(Gl.GL_MODELVIEW);
            Gl.glDisable(Gl.GL_LIGHTING);
            Gl.glEnable(Gl.GL_TEXTURE_2D);
            Gl.glDisable(Gl.GL_DEPTH_TEST);
            Gl.glEnable(Gl.GL_BLEND);
            Gl.glBlendFunc(Gl.GL_SRC_ALPHA, Gl.GL_ONE_MINUS_SRC_ALPHA);
            Gl.glListBase(font);
            float[] modelview_matrix = new float[16];
            Gl.glGetFloatv(Gl.GL_MODELVIEW_MATRIX, modelview_matrix);
            Gl.glPushMatrix();
            Gl.glLoadIdentity();
            Gl.glTranslatef(x, y, 0);
            Gl.glMultMatrixf(modelview_matrix);

            //Render
            //byte[] textbytes = new byte[what.Length];
            //for (int i = 0; i < what.Length; i++)
            //    textbytes = (byte)what;
            Gl.glCallLists(what.Length, Gl.GL_UNSIGNED_SHORT, what);
            //textbytes = null;

            //Restore openGL state
            Gl.glPopMatrix();
            Gl.glPopAttrib();
            pop_pm(); 
        }

#6
11:02, 8 сен 2014

Yanusa3
Написано же, на OpenGL 3.3 (никаких glNewList и glBegin)
Laynos
в общих чертах:
загружаешь с помошью freetype шрифт -> делаешь в зависимости от языка атлас из необходимых символов (в тестуру), сохраняя параметры символа (юникод ID, текстурные координаты)
Для нужного текста собираешь VBO -> Выводишь.

#7
11:13, 8 сен 2014

MtriG
> в общих чертах:
> загружаешь с помошью freetype шрифт -> делаешь в зависимости от языка атлас из
> необходимых символов (в тестуру), сохраняя параметры символа (юникод ID,
> текстурные координаты)
> Для нужного текста собираешь VBO -> Выводишь.
Ну да, как-то так я себе это и представлял. Но... Как определить, что в таком-то месте стоит, скажем, буква "а"?
Я планирую загрузить шрифт в некоторый атлас, потом каждую букву\цифру\символ заносить в std::map. Т.е. при подачи текста для рендера функция будет разбирать слова на символы, искать их по map, после чего добавлять в VBO. Когда всё готово, VBO отдаётся видеокарте. По крайней мере до этого я вчера додумался. Так это или нет - сложно мне  судить... Да и из-за map, как по мне, производительность хорошенько просядет. Слышал что-то про кешированный map, но я пока не понимаю как он работает.
Yanusa3
Жалко, что для старой версии OGL...( Но всё равно спасибо

#8
11:18, 8 сен 2014

Кстати, а glEnable остаётся частью OGL 3.3?

#9
11:23, 8 сен 2014

Laynos
Да все правильно. Используй  std::unordered_map - по шустрее (он использует хеш таблицы). Работать с ним так же, как и с std::map.
Можно использовать просто массив и при этом еще хранить int смещения используемых символов в юникод кодировке (для латинской = 0 , для кириллицы = 1024(вроде)..)
Laynos
Да конечно

#10
11:28, 8 сен 2014

Laynos,
Да, конечно, многие фичи без glEnable/glDisable не сделать.  GL_DEPTH_TEST, GL_CULL_FACE, к примеру, как были, так и остались =)

Вместо map, конечно, можно попробовать использовать массив, устанавливающий параметры для каждого юникодовского символа, но это как-то чересчур, если ты не хочешь сразу все языки поддерживать. Мне тоже кажется, что map вполне подойдет. Однако было бы интересно ознакомиться с мнением более опытных товарищей :)

#11
11:30, 8 сен 2014

https://code.google.com/p/freetype-gl/

Пример с VBO
http://www.mbsoftworks.sk/index.php?page=tutorials&series=1&tutorial=12

#12
11:46, 8 сен 2014

Пример с VBO
Вся польза в скорости использования VBO улетает в трубу, т.к. в этом примере для каждого символа вызывается :

// Draw letter
glDrawArrays(GL_TRIANGLE_STRIP, iIndex*4, 4);

Лучше собирать все необходимое в индексный массив и рисовать одним вызовом.

#13
12:04, 8 сен 2014

MtriG
> Пример с VBO
> Вся польза в скорости использования VBO улетает в трубу, т.к. в этом примере
> для каждого символа вызывается :
>
> // Draw letter
> glDrawArrays(GL_TRIANGLE_STRIP, iIndex*4, 4);
>
> Лучше собирать все необходимое в индексный массив и рисовать одним вызовом.
То есть всю нужную инфу класть, скажем, в std::vector, после чего отправлять информацию в видеокарту и вызывать соответствующий шейдер?
MtriG
> Да все правильно. Используй std::unordered_map - по шустрее (он использует хеш
> таблицы). Работать с ним так же, как и с std::map.
> Можно использовать просто массив и при этом еще хранить int смещения
> используемых символов в юникод кодировке (для латинской = 0 , для кириллицы =
> 1024(вроде)..)
Про std::unordered_map сейчас поищу в своём справочнике... Таки интересно почему он пошустрее :)
Эм... Ещё раз извиняюсь за дурной вопрос, но что это за смещение? Смещение относительно чего? (относительно начала массива?)
Хранить адрес каждого символа?
allcreater
Ок, понял :)

Yanusa3
> https://code.google.com/p/freetype-gl/
>
> Пример с VBO
> http://www.mbsoftworks.sk/index.php?page=tutorials&series=1&tutorial=12
Спасибо, ознакомлюсь с кодом!

#14
12:41, 8 сен 2014

Не подскажите почему FT_Get_Char_Index может возвращать 0 для русских букв? (кстати сдвиг для русских букв 1040)

Страницы: 1 2 Следующая »
ПрограммированиеФорумГрафика

Тема в архиве.