1
/************************************************************************************
3
AstroMenace (Hardcore 3D space shooter with spaceship upgrade possibilities)
4
Copyright © 2006-2012 Michael Kurinnoy, Viewizard
7
AstroMenace is free software: you can redistribute it and/or modify
8
it under the terms of the GNU General Public License as published by
9
the Free Software Foundation, either version 3 of the License, or
10
(at your option) any later version.
12
AstroMenace is distributed in the hope that it will be useful,
13
but WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
GNU General Public License for more details.
17
You should have received a copy of the GNU General Public License
18
along with AstroMenace. If not, see <http://www.gnu.org/licenses/>.
21
Web Site: http://www.viewizard.com/
22
Project: http://sourceforge.net/projects/openastromenace/
23
E-mail: viewizard@viewizard.com
25
*************************************************************************************/
32
void vw_AttachFontChar(eFontChar* FontChar);
33
void vw_DetachFontChar(eFontChar* FontChar);
34
extern FT_Face InternalFace;
35
extern int InternalFontSize;
39
//------------------------------------------------------------------------------------
40
// загрузка и генерация всех необходимых данных для символа (utf32)
41
//------------------------------------------------------------------------------------
42
eFontChar* vw_LoadFontChar(unsigned UTF32)
44
// прежде всего, пытаемся загрузить символ, а уже потом создаем структуру
47
// загрузка глифа нужного нам символа
48
if (FT_Load_Char( InternalFace, UTF32, FT_LOAD_RENDER | FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT))
50
fprintf(stderr, "Can't load Char: %u\n", UTF32);
55
// создаем структуру FontChar
57
NewChar = new eFontChar;
59
NewChar->UTF32 = UTF32;
60
NewChar->CharTexture = 0;
61
NewChar->TexturePositionLeft = 0;
62
NewChar->TexturePositionRight = InternalFace->glyph->bitmap.width; // в случае одной текстуры совпадают с шириной
63
NewChar->TexturePositionTop = 0;
64
NewChar->TexturePositionBottom = InternalFace->glyph->bitmap.rows; // в случае одной текстуры совпадают с высотой
65
NewChar->Width = InternalFace->glyph->bitmap.width;
66
NewChar->Height = InternalFace->glyph->bitmap.rows;
67
NewChar->Left = InternalFace->glyph->bitmap_left;
68
NewChar->Top = InternalFace->glyph->bitmap_top;
73
pixels = new BYTE[NewChar->Width*NewChar->Height*4];
75
// битмап идет в 1 канале градаций серого, делаем 32бита rgba
77
BYTE ColorRGB[3]={255,255,255};
78
for (int j=0; j<NewChar->Height; j++)
80
for (int i=0; i<NewChar->Width; i++)
82
// RGB составляющую заполняем белым
83
memcpy(pixels + k, ColorRGB, 3);
85
memcpy(pixels + k, InternalFace->glyph->bitmap.buffer+(NewChar->Height-j-1)*NewChar->Width+i, 1);
90
// называем текстуру номером символа в утф32
91
char texturefilename[MAX_PATH];
92
sprintf(texturefilename, "%i", UTF32);
94
vw_SetTextureProp(RI_MAGFILTER_LINEAR | RI_MINFILTER_LINEAR | RI_MIPFILTER_NONE, RI_CLAMP_TO_EDGE, true, TX_ALPHA_GREYSC, false);
95
NewChar->CharTexture = vw_CreateTextureFromMemory(texturefilename, pixels, NewChar->Width, NewChar->Height, 4, false);
99
// подключаем к менеджеру
100
vw_AttachFontChar(NewChar);
105
//-----------------------------------------------------------------------------
106
// делаем генерацию нужных символов по списку генерируя одну текстуру
107
//-----------------------------------------------------------------------------
108
void vw_GenerateFontChars(int FontTextureWidth, int FontTextureHeight, const char * CharsList)
111
printf("Font characters generation start.\n");
113
// будем использовать последовательность как имя текстуры
114
const char *TextureName = CharsList;
117
DIB = new BYTE[FontTextureWidth*FontTextureHeight*4]; // всегда делаем rgba
118
// устанавливаем 0 везде, чтобы потом не краcить rgb, а только формировать альфу
119
memset(DIB, 0, FontTextureWidth*FontTextureHeight*4);
121
// данные для работы с вклеиванием в текстуру
125
int MaxHeightInCurrentLine = 0;
128
// первый проход, формируем одну большую текстуру
129
const char *CharsList2 = CharsList;
130
while (strlen(CharsList) > 0)
132
unsigned CurrentChar;
133
// преобразуем в утф32 и "сдвигаемся" на следующий символ в строке
134
CharsList = utf8_to_utf32(CharsList, &CurrentChar);
137
// загрузка глифа нужного нам символа
138
if (FT_Load_Char( InternalFace, CurrentChar, FT_LOAD_RENDER | FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT))
140
fprintf(stderr, "Can't load Char: %u\n", CurrentChar);
144
// создаем структуру FontChar
146
NewChar = new eFontChar;
148
NewChar->UTF32 = CurrentChar;
149
NewChar->CharTexture = 0;
150
NewChar->TexturePositionLeft = 0;
151
NewChar->TexturePositionRight = 0;
152
NewChar->TexturePositionTop = 0;
153
NewChar->TexturePositionBottom = 0;
154
NewChar->Width = InternalFace->glyph->bitmap.width;
155
NewChar->Height = InternalFace->glyph->bitmap.rows;
156
NewChar->Left = InternalFace->glyph->bitmap_left;
157
NewChar->Top = InternalFace->glyph->bitmap_top;
161
// делаем установку параметров для вклеивания
163
// если в текущую строку символов уже не можем вписывать - смещаемся на новую, ниже
164
if (CurrentDIBX + NewChar->Width > FontTextureWidth)
167
CurrentDIBY += MaxHeightInCurrentLine + EdgingSpace;
168
MaxHeightInCurrentLine = 0;
170
// если в текущую строку не влазит уже по высоте - значит это фейл... кричим чтоб дали больше текстуру
171
if (CurrentDIBY + NewChar->Height > FontTextureHeight)
173
fprintf(stderr, "!!! Can't generate all font chars in one texture. Too many chars or too small texture size!\n");
178
// "вклеиваем" новый символ в массив
179
BYTE ColorRGB[3]={255,255,255};
180
for (int j=0; j<NewChar->Height; j++)
181
for (int i=0; i<NewChar->Width; i++)
183
memcpy(DIB + (FontTextureHeight-CurrentDIBY-j-1)*FontTextureWidth*4 + (CurrentDIBX+i)*4,
186
memcpy(DIB + (FontTextureHeight-CurrentDIBY-j-1)*FontTextureWidth*4 + (CurrentDIBX+i)*4 + 3,
187
InternalFace->glyph->bitmap.buffer+j*NewChar->Width+i,
191
// устанавливаем параметры текстуры для прорисовки нашему символу
192
NewChar->TexturePositionLeft = CurrentDIBX;
193
NewChar->TexturePositionRight = CurrentDIBX + NewChar->Width;
194
NewChar->TexturePositionTop = CurrentDIBY;
195
NewChar->TexturePositionBottom = CurrentDIBY + NewChar->Height;
197
// выбираем наибольшую высоту символов
198
if (MaxHeightInCurrentLine < NewChar->Height) MaxHeightInCurrentLine = NewChar->Height;
200
CurrentDIBX += NewChar->Width + EdgingSpace;
202
// подключаем к менеджеру
203
vw_AttachFontChar(NewChar);
207
/////////////////////////////////
209
// выводим в bmp файл сгенерированный DIB, если нужно проверить
212
temp = SDL_CreateRGBSurface(SDL_SWSURFACE, FontTextureWidth, FontTextureHeight, 32,
213
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
214
0x000000FF, 0x0000FF00, 0x00FF0000, 0
216
0x00FF0000, 0x0000FF00, 0x000000FF, 0
219
memcpy(temp->pixels, DIB, FontTextureWidth*FontTextureHeight*4);
220
SDL_SaveBMP(temp, "fontgenerationtest.bmp");
221
SDL_FreeSurface(temp);
223
/////////////////////////////////
227
vw_SetTextureProp(RI_MAGFILTER_LINEAR | RI_MINFILTER_LINEAR | RI_MIPFILTER_NONE, RI_CLAMP_TO_EDGE, true, TX_ALPHA_GREYSC, false);
228
eTexture* FontTexture = vw_CreateTextureFromMemory(TextureName, DIB, FontTextureWidth, FontTextureHeight, 4, false);
229
// освобождаем память
231
if (FontTexture == 0)
233
fprintf(stderr, "Can't create font texture.\n");
238
// второй проход, всем FontChars из списка, присваиваем сгенерированную текстуру
239
while (strlen(CharsList2) > 0)
241
unsigned CurrentChar;
242
// преобразуем в утф32 и "сдвигаемся" на следующий символ в строке
243
CharsList2 = utf8_to_utf32(CharsList2, &CurrentChar);
244
// ставим нашу общую текстуру
245
eFontChar* TMPChar = vw_FindFontCharByUTF32(CurrentChar);
246
if (TMPChar != 0) TMPChar->CharTexture = FontTexture;
250
printf("Font characters generation end.\n\n");
258
//------------------------------------------------------------------------------------
260
//------------------------------------------------------------------------------------
261
void vw_DrawFont(int X, int Y, float FlattenWidth, float MaxWidth, float FontScale, float R, float G, float B, float Transp, const char *Text, ...)
263
if (Text == 0) return;
265
// учитываем аспект рейшен
268
bool ASpresent=false;
269
ASpresent = vw_GetAspectWH(&AW, &AH);
270
// получаем данные текущего вьюпорта
272
vw_GetViewport(0, 0, &W, &H);
275
float RealTextYPos = AHw - 2*Y + 4 + InternalFontSize*FontScale;
276
if (ASpresent) RealTextYPos = AH - 2*Y + 4 + InternalFontSize*FontScale;
279
// если текст ниже чем ширина нашего окна - не рисуем
280
if (ASpresent){ if (Y > AH) return;}
281
else {if (Y > H) return;}
282
// если текст выше чем ноль - тоже рисовать его смысла нет
283
if (Y+InternalFontSize*FontScale < 0) return;
286
// FlattenWidth - выравнивать по ширине
287
// если FlattenWidth отрицателен, выравниваем по значению, "сжимая" буквы, если нужно
288
// MaxWidth - рисовать до ширины
291
// смотрим значения параметров в строке
295
vsprintf(text, Text, ap);
297
// в text уже полная строка
298
if (strlen(text) == 0) return;
301
// делаем пробел в 2/3 от размера фонта
302
float SpaceWidth = InternalFontSize * 2 / 3;
303
// коэф. изменения букв по ширине
304
float FontWidthScale = 1.0f;
306
if (Transp >= 1.0f) Transp = 1.0f;
309
// если нужно выравнивать, считаем данные пробелов
310
if (FlattenWidth > 0)
315
const char *CountCheck = text;
316
while (strlen(CountCheck) > 0)
319
// преобразуем в утф32 и "сдвигаемся" на следующий символ в строке
320
CountCheck = utf8_to_utf32(CountCheck, &UTF32);
321
// находим наш текущий символ
322
eFontChar* DrawChar = vw_FindFontCharByUTF32(UTF32);
323
if (DrawChar == 0) DrawChar = vw_LoadFontChar(UTF32);
325
// считаем кол-во пробелов
329
LineWidth += DrawChar->Width + DrawChar->Left;
332
if (FlattenWidth > LineWidth)
333
if (SpaceCount!=0) SpaceWidth = (FlattenWidth - LineWidth)/SpaceCount;
335
// если нужно сжать, считаем коэф. сжатия букв
336
if (FlattenWidth < 0)
340
const char *CountCheck = text;
341
while (strlen(CountCheck) > 0)
344
// преобразуем в утф32 и "сдвигаемся" на следующий символ в строке
345
CountCheck = utf8_to_utf32(CountCheck, &UTF32);
346
// находим наш текущий символ
347
eFontChar* DrawChar = vw_FindFontCharByUTF32(UTF32);
348
if (DrawChar == 0) DrawChar = vw_LoadFontChar(UTF32);
350
// считаем длину символов с пробелами
352
LineWidth += DrawChar->Width + DrawChar->Left;
354
LineWidth += SpaceWidth;
357
if (FlattenWidth*(-1.0f) < LineWidth) FontWidthScale = FlattenWidth/LineWidth*(-1.0f);
363
// установка свойств текстуры
364
vw_SetTextureBlend(true, RI_BLEND_SRCALPHA, RI_BLEND_INVSRCALPHA);
366
vw_SetColor(R, G, B, Transp);
369
eTexture* CurrentTexture = 0;
371
// буфер для последовательности RI_QUADS
372
// войдет RI_2f_XYZ | RI_2f_TEX
374
tmp = new float[(2+2)*4*strlen(text)]; if (tmp == 0) return;
376
// чтобы меньше делать операций умножения, включаем коэф. один в другой сразу для ширины символов
377
FontWidthScale = FontScale*FontWidthScale;
381
const char *textdraw = text;
382
// прорисовываем все символы
383
while (strlen(textdraw) > 0)
386
// преобразуем в утф32 и "сдвигаемся" на следующий символ в строке
387
textdraw = utf8_to_utf32(textdraw, &UTF32);
388
// находим наш текущий символ
389
eFontChar* DrawChar = vw_FindFontCharByUTF32(UTF32);
390
if (DrawChar == 0) DrawChar = vw_LoadFontChar(UTF32);
391
// первый символ - запоминаем его текстуру
392
if (CurrentTexture == 0) CurrentTexture = DrawChar->CharTexture;
395
// проверка на текстуру, если текстура поменялась - отрисовываем все что есть в буфере, если там что-то есть
396
if (CurrentTexture != DrawChar->CharTexture)
398
// если что-то было в буфере - выводим
401
// Установка текстуры
402
vw_SetTexture(0, CurrentTexture);
403
// отрисовываем все что есть в буфере
404
vw_SendVertices(RI_QUADS, 4*(k/16), RI_2f_XY | RI_1_TEX, tmp, 4*sizeof(float));
408
// запоминаем новую текстуру
409
CurrentTexture = DrawChar->CharTexture;
410
// сбрасываем счетчики
414
// если не пробел - рисуем
418
float DrawX = Xstart + DrawChar->Left*FontWidthScale;
419
float DrawY = Y + 2 + (InternalFontSize - DrawChar->Top)*FontScale; // 2 доп смещение ("привет" от старого фонта)
421
// Вычисление поправки по У в зависимости от DrawCorner
422
// - расположения угла начала координат
424
// изменяем только в случае RI_UL_CORNER
425
if (ASpresent) tmpPosY = (AH - DrawY - DrawY - DrawChar->Height*FontScale);
426
else tmpPosY = (AHw - DrawY - DrawY - DrawChar->Height*FontScale);
428
float ImageHeight = DrawChar->CharTexture->Height*1.0f;
429
float ImageWidth = DrawChar->CharTexture->Width*1.0f;
431
float FrameHeight = (DrawChar->TexturePositionBottom*1.0f )/ImageHeight;
432
float FrameWidth = (DrawChar->TexturePositionRight*1.0f )/ImageWidth;
434
float Yst = (DrawChar->TexturePositionTop*1.0f)/ImageHeight;
435
float Xst = (DrawChar->TexturePositionLeft*1.0f)/ImageWidth;
438
tmp[k++] = DrawY +tmpPosY + DrawChar->Height*FontScale;
443
tmp[k++] = DrawY +tmpPosY;
445
tmp[k++] = 1.0f-FrameHeight;
447
tmp[k++] = DrawX + DrawChar->Width*FontWidthScale;
448
tmp[k++] = DrawY +tmpPosY;
449
tmp[k++] = FrameWidth;
450
tmp[k++] = 1.0f-FrameHeight;
452
tmp[k++] = DrawX + DrawChar->Width*FontWidthScale;
453
tmp[k++] = DrawY +tmpPosY + DrawChar->Height*FontScale;
454
tmp[k++] = FrameWidth;
458
Xstart += (DrawChar->Width + DrawChar->Left)*FontWidthScale;
459
LineWidth += (DrawChar->Width + DrawChar->Left)*FontWidthScale;
463
Xstart += SpaceWidth*FontWidthScale;
464
LineWidth += SpaceWidth*FontWidthScale;
467
// если нужно прорисовывать с ограничением по длине
468
if (MaxWidth != 0.0f)
469
if (LineWidth >= MaxWidth) break;
473
// если что-то было в буфере - выводим
476
// Установка текстуры
477
vw_SetTexture(0, CurrentTexture);
478
// отрисовываем все что есть в буфере
479
vw_SendVertices(RI_QUADS, 4*(k/16), RI_2f_XY | RI_1_TEX, tmp, 4*sizeof(float));
484
if (tmp != 0){delete [] tmp; tmp = 0;}
485
vw_SetColor(1.0f, 1.0f, 1.0f, 1.0f);
486
vw_SetTextureBlend(false, 0, 0);
487
vw_BindTexture(0, 0);
492
//------------------------------------------------------------------------------------
493
// получаем размер строки
494
//------------------------------------------------------------------------------------
495
int vw_FontSize(const char *Text, ...)
497
if (Text == 0) return 0;
499
// смотрим значения параметров в строке
504
vsprintf(text, Text, ap);
506
// в text уже полная строка
507
if (strlen(text) == 0) return 0;
509
const char *textdraw = text;
510
// делаем пробел в 2/3 от размера фонта
511
float SpaceWidth = InternalFontSize * 2 / 3;
514
while (strlen(textdraw) > 0)
517
// преобразуем в утф32 и "сдвигаемся" на следующий символ в строке
518
textdraw = utf8_to_utf32(textdraw, &UTF32);
519
// находим наш текущий символ
520
eFontChar* DrawChar = vw_FindFontCharByUTF32(UTF32);
521
if (DrawChar == 0) DrawChar = vw_LoadFontChar(UTF32);
523
// считаем кол-во пробелов
525
LineWidth += SpaceWidth;
527
LineWidth += DrawChar->Width + DrawChar->Left;
531
return (int)LineWidth;
538
//------------------------------------------------------------------------------------
539
// прорисовка фонта в 3д пространстве
540
//------------------------------------------------------------------------------------
541
void vw_DrawFont3D(float X, float Y, float Z, const char *Text, ...)
544
if (Text == 0) return;
546
// смотрим значения параметров в строке
550
vsprintf(text, Text, ap);
552
// в text уже полная строка
553
if (strlen(text) == 0) return;
555
const char *textdraw = text;
559
// делаем пробел в 2/3 от размера фонта
560
float SpaceWidth = InternalFontSize * 2 / 3;
566
eTexture* CurrentTexture = 0;
568
// буфер для последовательности RI_QUADS
569
// войдет RI_2f_XY | RI_2f_TEX
571
tmp = new float[(2+2)*4*strlen(textdraw)]; if (tmp == 0) return;
573
// установка свойств текстуры
574
vw_SetTextureBlend(true, RI_BLEND_SRCALPHA, RI_BLEND_INVSRCALPHA);
575
// всегда стаим белый цвет
576
vw_SetColor(1.0f, 1.0f, 1.0f, 1.0f);
580
vw_Translate(VECTOR3D(X, Y, Z));
581
VECTOR3D CurrentCameraRotation;
582
vw_GetCameraRotation(&CurrentCameraRotation);
584
// поворачиваем к камере
585
vw_Rotate(CurrentCameraRotation.y, 0.0f, 1.0f, 0.0f);
586
vw_Rotate(CurrentCameraRotation.x, 1.0f, 0.0f, 0.0f);
589
// прорисовываем все символы
590
while (strlen(textdraw) > 0)
593
// преобразуем в утф32 и "сдвигаемся" на следующий символ в строке
594
textdraw = utf8_to_utf32(textdraw, &UTF32);
595
// находим наш текущий символ
596
eFontChar* DrawChar = vw_FindFontCharByUTF32(UTF32);
597
if (DrawChar == 0) DrawChar = vw_LoadFontChar(UTF32);
598
// первый символ - запоминаем его текстуру
599
if (CurrentTexture == 0) CurrentTexture = DrawChar->CharTexture;
602
// проверка на текстуру, если текстура поменялась - отрисовываем все что есть в буфере, если там что-то есть
603
if (CurrentTexture != DrawChar->CharTexture)
605
// если что-то было в буфере - выводим
608
// Установка текстуры
609
vw_SetTexture(0, CurrentTexture);
610
// отрисовываем все что есть в буфере
611
vw_SendVertices(RI_QUADS, 4*(k/16), RI_2f_XY | RI_1_TEX, tmp, 4*sizeof(float));
615
// запоминаем новую текстуру
616
CurrentTexture = DrawChar->CharTexture;
617
// сбрасываем счетчики
622
// если не пробел - рисуем
625
float DrawX = Xstart + DrawChar->Left;
626
float DrawY = InternalFontSize - DrawChar->Top;
629
float ImageHeight = DrawChar->CharTexture->Height*1.0f;
630
float ImageWidth = DrawChar->CharTexture->Width*1.0f;
632
float FrameHeight = (DrawChar->TexturePositionBottom*1.0f )/ImageHeight;
633
float FrameWidth = (DrawChar->TexturePositionRight*1.0f )/ImageWidth;
635
float Yst = (DrawChar->TexturePositionTop*1.0f)/ImageHeight;
636
float Xst = (DrawChar->TexturePositionLeft*1.0f)/ImageWidth;
638
tmp[k++] = DrawX/10.0f;
639
tmp[k++] = (DrawY + DrawChar->Height)/10.0f;
643
tmp[k++] = DrawX/10.0f;
644
tmp[k++] = DrawY/10.0f;
646
tmp[k++] = 1.0f-FrameHeight;
648
tmp[k++] = (DrawX + DrawChar->Width)/10.0f;
649
tmp[k++] = DrawY/10.0f;
650
tmp[k++] = FrameWidth;
651
tmp[k++] = 1.0f-FrameHeight;
653
tmp[k++] = (DrawX + DrawChar->Width)/10.0f;
654
tmp[k++] = (DrawY + DrawChar->Height)/10.0f;
655
tmp[k++] = FrameWidth;
659
Xstart += DrawChar->Width + DrawChar->Left;
663
Xstart += SpaceWidth;
669
// если что-то было в буфере - выводим
672
// Установка текстуры
673
vw_SetTexture(0, CurrentTexture);
674
// отрисовываем все что есть в буфере
675
vw_SendVertices(RI_QUADS, 4*(k/16), RI_2f_XY | RI_1_TEX, tmp, 4*sizeof(float));
683
if (tmp != 0){delete [] tmp; tmp = 0;};
684
vw_SetTextureBlend(false, 0, 0);
685
vw_BindTexture(0, 0);