Allegro.cc - Online Community

Allegro.cc Forums » Off-Topic Ordeals » Basic game development library?

This thread is locked; no one can reply to it. rss feed Print
Basic game development library?
gnolam
Member #2,030
March 2002
avatar

(Starting a new thread since that other one's gone all off-topic and this is a slightly different question anyway)
I've realized that I really can't proceed with at least two of my AllegroGL projects due to AllegroGL's shoddy text handling. Using just FreeType and writing the rest myself seems like too much work, and with all the other Allegro... quirks... one has to deal with, I thought I might as well leave AllegroGL altogether. So I'm looking for a library that provides:

  • Window/OpenGL context creation.

  • Audio output.

  • Keyboard/mouse/joystick input.

  • TTF font loading and rendering (Unicode/UTF-8!) with at least basic justification support.

  • Some form of timing.

  • Cross-platform support (I'm willing to negotiate on this one as long as Windows is supported though).

  • EDIT: Production-ready code. :P

  • EDIT2: Decent documentation.

</li>

SDL fails the last condition. SFML seems to have a godawful text API, but appears nice otherwise.

Do you have any other suggestions on libraries to try out?

--
Move to the Democratic People's Republic of Vivendi Universal (formerly known as Sweden) - officially democracy- and privacy-free since 2008-06-18!

Evert
Member #794
November 2000
avatar

Quote:

Do you have any other suggestions on libraries to try out?

Sure. Allegro. :P

Allegro 4.9 current svn that is (to be Allegro 5).
It does all the things you listed, the only downside is that it's a WIP, so some things are a bit rough. It's usable already though.

gnolam
Member #2,030
March 2002
avatar

Updated the list. :P

[EDIT]
... and from what little Allegro 4.9 documentation I can find, it does not in fact appear to satisfy my demands. :P

--
Move to the Democratic People's Republic of Vivendi Universal (formerly known as Sweden) - officially democracy- and privacy-free since 2008-06-18!

Evert
Member #794
November 2000
avatar

As I said, it's usable right now, but installation may be a bit rough and the API is not in feature freeze yet.
There is documentation (this isn't obvious), not yet up to the level of A4 but sure to get there. The examples are easy enough to follow anyway.

It's probably at least worth a quick look.

StevenVI
Member #562
July 2000
avatar

Use Fudgefont. It loads TTF files as Allegro fonts and they look quite beautiful when rendered with alpha blending. It loads them with Freetype. It looks like the sourceforge page for it isn't functioning, so I've attached my modified version of the source and header file.

When you say "basic justification support" do you mean similar to Allegro's left/right/centre functions?

A5 also does TTF loading quite well. I have some tutorials linked in my signature, but they have a critical flaw in the timer code, so disregard that portion of them if you decide to take a look.

__________________________________________________
Skoobalon Software
[ Lander! v2.5 ] [ Zonic the Hog v1.1 ] [ Raid 2 v1.0 ]

Peter Wang
Member #23
April 2000

[potential thread derailment; deleted]

Thomas Harte
Member #33
April 2000
avatar

Quote:

Using just FreeType and writing the rest myself seems like too much work

It's actually a lot less work than you think. FreeType passes you vectors that describe the edges of arbitrarily-shaped polygons, and GLU has code to turn that sort of polygon into triangles. All you really need to do is write glue code with a tiny bit to turn Beziers into line segments, assuming you're happy with doing your fonts as geometry rather than textures.

I'm at work, so can't excise the relevant bits from my code, but check out my old Ice Field Frenzy (ChristmasHack '07 entry) code, or wait for me to post later.

OICW
Member #4,069
November 2003
avatar

Quote:

A license that isn't (L)GPL.

Quote:

SDL fails the last condition.

I see, but their page states:

Quote:

SDL is distributed under GNU LGPL version 2. This license allows you to use SDL freely in commercial programs as long as you link with the dynamic library.

That leads me to a conlusion that as long as you link dynamic version of the library you cat have closed code. Can you elaborate your problem?

[My website][CppReference][Pixelate][Allegators worldwide][Who's online]
"Final Fantasy XIV, I feel that anything I could say will be repeating myself, so I'm just gonna express my feelings with a strangled noise from the back of my throat. Graaarghhhh..." - Yahtzee
"Uhm... this is a.cc. Did you honestly think this thread WOULDN'T be derailed and ruined?" - BAF
"You can discuss it, you can dislike it, you can disagree with it, but that's all what you can do with it"

MiquelFire
Member #3,110
January 2003
avatar

I think it's the open code that it becomes a problem. The (L)GPL is a bit viral.

---
Febreze (and other air fresheners actually) is just below perfumes/colognes, and that's just below dead skunks in terms of smells that offend my nose.
MiquelFire.red
If anyone is of the opinion that there is no systemic racism in America, they're either blind, stupid, or racist too. ~Edgar Reynaldo

gnolam
Member #2,030
March 2002
avatar

Harry Carey: thanks, but as far as I can see that only does the TTF loading bit - it still goes through AllegroGL's horribly broken font and text handling.

OICW said:

Can you elaborate your problem?

A lesser evil is still evil.
(Elaborating in detail would take too much time)

--
Move to the Democratic People's Republic of Vivendi Universal (formerly known as Sweden) - officially democracy- and privacy-free since 2008-06-18!

Mokkan
Member #4,355
February 2004
avatar

ClanLib, maybe? It claims to have a BSD style license.

OICW
Member #4,069
November 2003
avatar

Quote:

A lesser evil is still evil.
(Elaborating in detail would take too much time)

Allright, fair enough.

Quote:

I think it's the open code that it becomes a problem. The (L)GPL is a bit viral.

I'm not sure I'm following your chain of thoughts. I know that when you actually use GPL'ed code you have to GPL the whole source of yours, however when you link dynamically the library it's ok.

[My website][CppReference][Pixelate][Allegators worldwide][Who's online]
"Final Fantasy XIV, I feel that anything I could say will be repeating myself, so I'm just gonna express my feelings with a strangled noise from the back of my throat. Graaarghhhh..." - Yahtzee
"Uhm... this is a.cc. Did you honestly think this thread WOULDN'T be derailed and ruined?" - BAF
"You can discuss it, you can dislike it, you can disagree with it, but that's all what you can do with it"

SiegeLord
Member #7,827
October 2006
avatar

Quote:

I'm not sure I'm following your chain of thoughts.

It is generally hard to follow thoughts of reactionary zealots. Even harder than those of the normal ones.

"For in much wisdom is much grief: and he that increases knowledge increases sorrow."-Ecclesiastes 1:18
[SiegeLord's Abode][Codes]:[DAllegro5]:[RustAllegro]

ImLeftFooted
Member #3,935
October 2003
avatar

How does A5 stack up against SDL?

Thomas Fjellstrom
Member #476
June 2000
avatar

Quote:

I know that when you actually use GPL'ed code you have to GPL the whole source of yours, however when you link dynamically the library it's ok.

That only qualifies for LGPL. While I'm not sure this point has actually been tested in court (which is the only way to know if something is legal or illegal in the us), the GPL actually effects any linked code, dynamic or static. Since your code does directly use it, which makes it a derivative, which makes it subject to the GPL.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

OICW
Member #4,069
November 2003
avatar

Quote:

That only qualifies for LGPL. While I'm not sure this point has actually been tested in court (which is the only way to know if something is legal or illegal in the us), the GPL actually effects any linked code, dynamic or static. Since your code does directly use it, which makes it a derivative, which makes it subject to the GPL.

All right. SDL seems to be LGPL. But anyway, it hasn't been tested. By the way, has it been tested with GPL?

[My website][CppReference][Pixelate][Allegators worldwide][Who's online]
"Final Fantasy XIV, I feel that anything I could say will be repeating myself, so I'm just gonna express my feelings with a strangled noise from the back of my throat. Graaarghhhh..." - Yahtzee
"Uhm... this is a.cc. Did you honestly think this thread WOULDN'T be derailed and ruined?" - BAF
"You can discuss it, you can dislike it, you can disagree with it, but that's all what you can do with it"

gnolam
Member #2,030
March 2002
avatar

I said:

A lesser evil is still evil.

To expand a little bit more: ensuring LGPL compliance isn't as straightforward as you think it is. Can we get back on topic now, please? :P

--
Move to the Democratic People's Republic of Vivendi Universal (formerly known as Sweden) - officially democracy- and privacy-free since 2008-06-18!

OICW
Member #4,069
November 2003
avatar

Quote:

To expand a little bit more: ensuring LGPL compliance isn't as straightforward as you think it is. Can we get back on topic now, please? :P

Fair enough. Sure, sorry for this little debate.

I just digged out of my memory that Richard Phipps was working with PTK. Looks like it can be used for free. Maybe it can be worthwile to look at.

[My website][CppReference][Pixelate][Allegators worldwide][Who's online]
"Final Fantasy XIV, I feel that anything I could say will be repeating myself, so I'm just gonna express my feelings with a strangled noise from the back of my throat. Graaarghhhh..." - Yahtzee
"Uhm... this is a.cc. Did you honestly think this thread WOULDN'T be derailed and ruined?" - BAF
"You can discuss it, you can dislike it, you can disagree with it, but that's all what you can do with it"

Thomas Harte
Member #33
April 2000
avatar

How does A5 stack up against SDL? In license terms, Allegro is more liberal as discussed above. In ideological terms, SDL is lower level but has much more mature OpenGL support and as a result of both of those facts, it supports a much wider array of platforms. In terms of being in the process of an API refresh, both are equal. Except that now I'd say that Allegro's is more likely to arrive. Back to my real promise, code to do TTF in OpenGL. There's much more to it than I thought, because of the way I've chosen to optimise it. Much of it is unnecessary fluff. And some of it probably just replicates the STL, I don't know. Code it relies on includes my DataCollector template. It exists only to aggregate things it is given one at a time into C-style arrays and is the main thing I think STL can probably do for you. Here: template class DataCollector { public: DataCollector() {Array = NULL; NumAllocated = NumStored = 0;} ~DataCollector() {Flush();} void Flush() { free(Array); Array = NULL; NumAllocated = NumStored = 0; } void Add(T v) { if(NumAllocated == NumStored) { NumAllocated += 256; Array = (T *)realloc(Array, sizeof(T)*NumAllocated); } Array[NumStored++] = v; } T Get(int index) {return Array[index];} int GetNum() {return NumStored;} T *GetArray() {return Array;} T &operator [](int n) {return &Array[n];} private: T *Array; int NumAllocated, NumStored; }; There are also my VertexArray and DrawElements handlers, which are their own separate classes so that they can opt to use VBOs if available. If you don't care about VBOs then they're an unnecessary complication. ebgf_DrawElements.h (don't worry about CResource — it's the mechanism I use to maintain objects that are otherwise lost when I destroy and create contexts, e.g. when switching to fullscreen mode or, because of the way SDL is set up, when the user resizes the window): class CDrawElements: public CResource { public: CDrawElements(GLenum mode, GLsizei count, GLenum type, GLvoid *pointer, bool copy = true); ~CDrawElements(); void Draw(); virtual void Backup(); virtual bool Restore(); private: GLenum mode; GLsizei count; GLenum type; GLvoid *ptr; GLuint buffer; int DataSize; }; And .cpp: #include "ebgf_GLExts.h" CDrawElements::CDrawElements(GLenum mode, GLsizei count, GLenum type, GLvoid *pointer, bool copy) { this->mode = mode; this->count = count; this->type = type; int basesize; switch(type) { case GL_UNSIGNED_BYTE: basesize = sizeof(GLubyte); break; case GL_UNSIGNED_SHORT: basesize = sizeof(GLushort); break; case GL_UNSIGNED_INT: basesize = sizeof(GLuint); break; } DataSize = basesize*count; if(copy) { ptr = new unsigned char[DataSize]; memcpy(ptr, pointer, DataSize); } else ptr = pointer; Restore(); Filename = new char[50]; sprintf(Filename, "DrawElements::%016x", (const unsigned int)this); __EBGF_StoreHash(this); } CDrawElements::~CDrawElements() { Backup(); delete[] (unsigned char *)ptr; EBGF_ReturnResource(this, false); } void CDrawElements::Backup() { if(AvailableGLExtensions&GLEXT_VBO) glDeleteBuffersARB(1, &buffer); } bool CDrawElements::Restore() { buffer = 0; if(AvailableGLExtensions&GLEXT_VBO) { //VBO extension supported, upload glGenBuffersARB(1, &buffer); glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, buffer); glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, DataSize, ptr, GL_STATIC_DRAW_ARB); } return true; } void CDrawElements::Draw() { if(!buffer) glDrawElements(mode, count, type, ptr); else { glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, buffer); glDrawElements(mode, count, type, 0); glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); } } And VertexArray, which is almost a copy'n'paste job of DrawElements (I've reduced code redundancy in another version of my code, I just can't find it right now): class CVertexArray: public CResource { public: CVertexArray(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer, int number); ~CVertexArray(); void Enable(); void Disable(); virtual void Backup(); virtual bool Restore(); private: GLint size; GLenum type; GLsizei stride; GLvoid *ptr; GLuint buffer; int DataSize; }; #include "ebgf_GLExts.h" CVertexArray::CVertexArray(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer, int number) { ptr = NULL; this->size = size; this->type = type; this->stride = stride; int basesize; switch(type) { case GL_SHORT: basesize = sizeof(GLshort); break; case GL_INT: basesize = sizeof(GLint); break; case GL_FLOAT: basesize = sizeof(GLfloat); break; case GL_DOUBLE: basesize = sizeof(GLdouble); break; } DataSize = (basesize*size + stride) * number; ptr = malloc(DataSize); memcpy(ptr, pointer, DataSize); Restore(); Filename = new char[50]; sprintf(Filename, "VArray::%016x", (unsigned int)this); __EBGF_StoreHash(this); } CVertexArray::~CVertexArray() { Backup(); free(ptr); EBGF_ReturnResource(this, false); } void CVertexArray::Backup() { if(buffer) glDeleteBuffersARB(1, &buffer); buffer = 0; } bool CVertexArray::Restore() { buffer = 0; if(AvailableGLExtensions&GLEXT_VBO) { //VBO extension supported, try to upload glGenBuffersARB(1, &buffer); if(1)//glIsBufferARB(buffer)) { glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffer); glBufferDataARB(GL_ARRAY_BUFFER_ARB, DataSize, ptr, GL_STATIC_DRAW_ARB); } else buffer = 0; } return true; } void CVertexArray::Enable() { glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT); glEnableClientState(GL_VERTEX_ARRAY); if(!buffer) glVertexPointer(size, type, stride, ptr); else { glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffer); glVertexPointer(size, type, stride, NULL); } } void CVertexArray::Disable() { if(buffer) glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); glPopClientAttrib(); } So, up to here, mostly dull dry support stuff that adds a useful thing or two but creates complexity. You don't need an equivalent of my VertexArray or DrawElements holders, they're just the mechanism I use for utilising VBOs in a transparent fashion. The first class that is actually really helpful for TTF is my Polygon class. You feed it a sequence of vertices and then later you can ask it to draw the resulting polygon. Really it's just a thin layer on top of the GLU tesselator, utilising my pet classes for VBOs. #ifndef WIN32 #define __stdcall #endif class CPolygon { public: CPolygon(); ~CPolygon(); void Draw(); void AddVert(GLfloat x, GLfloat y); void NewContour(); void Finish(); private: static void __stdcall Begin(GLenum type); static void __stdcall End(void); static void __stdcall Combine(GLdouble coords[3], void *vertex_data[4], GLfloat weight[4], void **outData); static void __stdcall Vertex(void *Data); static int StoreVert(GLfloat x, GLfloat y); CVertexArray *Array; struct Plate { Plate() {Elements = NULL; Next = NULL;} ~Plate() {delete Elements;} CDrawElements *Elements; Plate *Next; } *PlateList; static Plate *PlateWorker; static DataCollector *TVList; static DataCollector *VPtr; static GLUtesselator *tesselator; static GLenum CurType; }; DataCollector *CPolygon::TVList; DataCollector *CPolygon::VPtr; GLUtesselator *CPolygon::tesselator; GLenum CPolygon::CurType; CPolygon::Plate *CPolygon::PlateWorker; int *BasePtr; void __stdcall CPolygon::Begin(GLenum type) { CurType = type; VPtr = new DataCollector; } void __stdcall CPolygon::End(void) { Plate *NP = new Plate; NP->Elements = new CDrawElements(CurType, VPtr->GetNum(), GL_UNSIGNED_INT, VPtr->GetArray()); NP->Next = PlateWorker; PlateWorker = NP; delete VPtr; VPtr = NULL; } void __stdcall CPolygon::Vertex(void *Data) { VPtr->Add((GLuint)((int *)Data - BasePtr)); } void __stdcall CPolygon::Combine(GLdouble coords[3], void *vertex_data[4], GLfloat weight[4], void **outData) { *outData = &BasePtr[StoreVert((GLfloat)coords[0], (GLfloat)coords[1])]; } int CPolygon::StoreVert(GLfloat x, GLfloat y) { // ensure storage is available int r = TVList->GetNum() >> 1; TVList->Add(x); TVList->Add(y); return r; } void CPolygon::AddVert(GLfloat x, GLfloat y) { int c = StoreVert(x, y); // pass to gluTesselate GLdouble VD[3] = {x, y, 0}; gluTessVertex(tesselator, VD, &BasePtr[c]); } typedef GLvoid (__stdcall *CallBackFunc)(); CPolygon::CPolygon() { // generate tesselator tesselator = gluNewTess(); // prepare vertex list TVList = new DataCollector; PlateWorker = NULL; Array = NULL; PlateList = NULL; // register callbacks gluTessCallback(tesselator, GLU_TESS_BEGIN, (CallBackFunc)Begin); gluTessCallback(tesselator, GLU_TESS_END, (CallBackFunc)End); gluTessCallback(tesselator, GLU_TESS_COMBINE, (CallBackFunc)Combine); gluTessCallback(tesselator, GLU_TESS_VERTEX, (CallBackFunc)Vertex); // begin polygon gluBeginPolygon(tesselator); gluTessBeginContour(tesselator); } void CPolygon::NewContour() { gluTessEndContour(tesselator); gluTessBeginContour(tesselator); } void CPolygon::Finish() { // end final polygon gluTessEndContour(tesselator); gluEndPolygon(tesselator); // store vertices Array = new CVertexArray(2, GL_FLOAT, 0, TVList->GetArray(), TVList->GetNum() >> 1); /* at this point, lots of info is sent to my callbacks */ // free memory delete TVList; TVList = NULL; // free tesselator gluDeleteTess(tesselator); // take copy of plates PlateList = PlateWorker; PlateWorker = NULL; } CPolygon::~CPolygon() { delete Array; while(PlateList) { Plate *N = PlateList->Next; delete PlateList; PlateList = N; } } void CPolygon::Draw() { if(!Array) return; Array->Enable(); Plate *P = PlateList; while(P) { P->Elements->Draw(); P = P->Next; } Array->Disable(); } Which just leaves my tiny bit of code for turning a TTF glyph into a polygon. I'm going to have to cut things a bit here since I've lazily just used a 7bit ASCII glyph table and that isn't what you want. Just imagine you are set up so that the Glyphs struct is large enough to hold a continuous array spanning every glyph you may want to use. That'd be a really bad unicode implementation decision, but I don't really expect you to use my code verbatim anyway. #include #include FT_FREETYPE_H #include FT_OUTLINE_H class CFont: public CResource { struct Glyph { CPolygon *Graphic; float Width; } *Glyphs; static Glyph *CurGlyph; FT_Face face; static FT_Pos CurPos[2]; static void TTF_AddVert(GLfloat x, GLfloat y); static int TTF_MoveTo(const FT_Vector *to, void *user); static int TTF_AddLine(const FT_Vector *to, void *user); static int TTF_AddQuadratic(const FT_Vector *control, const FT_Vector *to, void *user); static int TTF_AddCubic(const FT_Vector *control1, const FT_Vector *control2, const FT_Vector *to, void *user); void GetChar(int character); static bool InContour; }; #define GLYPH_MULTIPLIER 128 bool CFont::Open(const char *name) { if(FT_New_Face(__ebgf_TTFLibrary, name, 0, &face)) return false; FT_Set_Char_Size(face, GLYPH_MULTIPLIER << 6, GLYPH_MULTIPLIER << 6, 72, 72); // default size is 1x1, with 72dpi return true; } bool CFont::InContour; FT_Pos CFont::CurPos[2]; CFont::Glyph *CFont::CurGlyph; void CFont::TTF_AddVert(GLfloat x, GLfloat y) { CurGlyph->Graphic->AddVert(x, y); } int CFont::TTF_MoveTo(const FT_Vector *to, void *user) { /* pen up, move, pen down — breaks polygon */ if(!InContour || CurPos[0] != to->x || CurPos[1] != to->y) { if(InContour) CurGlyph->Graphic->NewContour(); InContour = true; CurPos[0] = to->x; CurPos[1] = to->y; TTF_AddVert((GLfloat)CurPos[0], (GLfloat)CurPos[1]); } return 0; } int CFont::TTF_AddLine(const FT_Vector *to, void *user) { /* move */ if(CurPos[0] != to->x || CurPos[1] != to->y) TTF_AddVert((GLfloat)(CurPos[0] = to->x), (GLfloat)(CurPos[1] = to->y)); return 0; } #define BEZIER_SEGMENTS 2 int CFont::TTF_AddQuadratic(const FT_Vector *control, const FT_Vector *to, void *user) { /* quadratic bezier from current location to 'to', with control point 'control' */ for(int c = 1; c < BEZIER_SEGMENTS; c++) { float t = (float)c / BEZIER_SEGMENTS; float coeff1 = (1-t) * (1-t); float coeff2 = 2 * t * (1-t); float coeff3 = t * t; TTF_AddVert( coeff1*CurPos[0] + coeff2 * control->x + coeff3*to->x, coeff1*CurPos[1] + coeff2 * control->y + coeff3*to->y ); } TTF_AddVert((GLfloat)(CurPos[0] = to->x), (GLfloat)(CurPos[1] = to->y)); return 0; } int CFont::TTF_AddCubic(const FT_Vector *control1, const FT_Vector *control2, const FT_Vector *to, void *user) { /* cubic bezier - rarely happens */ for(int c = 1; c < BEZIER_SEGMENTS; c++) { float t = (float)c / BEZIER_SEGMENTS; float coeff1 = (1-t) * (1-t) * (1-t); float coeff2 = 3 * t * (1-t) * (1-t); float coeff3 = 3 * t * t; float coeff4 = t * t * t; TTF_AddVert( coeff1*CurPos[0] + coeff2 * control1->x + coeff3*control2->x + coeff4*to->x, coeff1*CurPos[1] + coeff2 * control1->y + coeff3*control2->y + coeff4*to->y ); } TTF_AddVert((GLfloat)(CurPos[0] = to->x), (GLfloat)(CurPos[1] = to->y)); return 0; } void CFont::GetChar(int character) { FT_Outline outline; FT_Outline_Funcs func_interface; func_interface.shift = 0; func_interface.delta = 0; func_interface.move_to = (FT_Outline_MoveToFunc)TTF_MoveTo; func_interface.line_to = (FT_Outline_LineToFunc)TTF_AddLine; func_interface.conic_to = (FT_Outline_ConicToFunc)TTF_AddQuadratic; func_interface.cubic_to = (FT_Outline_CubicToFunc)TTF_AddCubic; /* lookup glyph */ if(FT_Load_Char(face, character, FT_LOAD_NO_BITMAP|FT_LOAD_NO_HINTING)) return; outline = face->glyph->outline; CurPos[0] = CurPos[1] = 0; CurGlyph = &Glyphs[character]; CurGlyph->Graphic = new CPolygon; InContour = false; // throw font shape into tesselator FT_Outline_Decompose( &outline, &func_interface, NULL); Glyphs[character].Width = (float)face->glyph->advance.x; CurGlyph->Graphic->Finish(); } And these are called just once, when the program is first loaded and before it is shut: FT_Library __ebgf_TTFLibrary = NULL; void __EBGF_FreeFontLibrary() { FT_Done_FreeType(__ebgf_TTFLibrary); } void __EBGF_SetupFontLibrary() { FT_Init_FreeType(&__ebgf_TTFLibrary); atexit(__EBGF_FreeFontLibrary); } In my 7bit ASCII world, I have the following print function, which does the obvious stuff + pair kerning: void CFont::Print(const char *fmt, ...) { char String[2048]; va_list varlist; va_start(varlist, fmt); // vsnprintf(String, 2048, fmt, varlist); vsprintf(String, fmt, varlist); va_end(varlist); glPushAttrib(GL_ENABLE_BIT); glDisable(GL_CULL_FACE); fmt = String; glPushMatrix(); glScalef(1.0f / (64.0f * GLYPH_MULTIPLIER), 1.0f / (64.0f * GLYPH_MULTIPLIER), 1.0f / (64.0f * GLYPH_MULTIPLIER)); while(*fmt) { int idx = (*fmt)&127; if(Glyphs[idx].Graphic) Glyphs[idx].Graphic->Draw(); glTranslatef(Glyphs[idx].Width, 0, 0); int glyph_index1; int glyph_index2; FT_Vector kerning; glyph_index1 = FT_Get_Char_Index(face, (FT_ULong)fmt[0]); glyph_index2 = FT_Get_Char_Index(face, (FT_ULong)fmt[1]); FT_Get_Kerning(face, glyph_index1, glyph_index2, FT_KERNING_UNFITTED, &kerning); glTranslatef((GLfloat)kerning.x, 0, 0); fmt++; } glPopMatrix(); glPopAttrib(); } So, yes, a lot of my code is a mess and I don't expect you to use it verbatim. But it hopefully shows that linking FreeType to GLU is really quite easy.
SiegeLord
Member #7,827
October 2006
avatar

Quote:

How does A5 stack up against SDL?

And if it does so unfavourably in some way, you can always make a suggestion and affect how the yet unfinished A5 will stack up to SDL as the former is under active development... ;)

"For in much wisdom is much grief: and he that increases knowledge increases sorrow."-Ecclesiastes 1:18
[SiegeLord's Abode][Codes]:[DAllegro5]:[RustAllegro]

Thomas Fjellstrom
Member #476
June 2000
avatar

Quote:

you can always make a suggestion and affect how the yet unfinished A5 will stack up to SDL as the former is under active development... ;)

And I intend to keep it that way ;) even if I don't get anywhere near as much actual work done on it myself as I want to (especially in a reasonable amount of time, fshooks could have been done last year)

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Elias
Member #358
May 2000

Quote:

So, yes, a lot of my code is a mess and I don't expect you to use it verbatim. But it hopefully shows that linking FreeType to GLU is really quite easy.

Someone want to add that to A5's ttf addon? Or as a new addon? :)

--
"Either help out or stop whining" - Evert

Thomas Harte
Member #33
April 2000
avatar

I think it'll need to wait until either SiegeLord's primitive stuff is in the library, giving implicit access to VBOs and suchlike from on top of Allegro with no regard whatsoever for which particular driver is in use, or — if it is planned at all — until it's clear how and to what extent Allegro will expose OpenGL (specifically, how the user will keep track of resources that are tied to specific rendering context if there are some operations that cause Allegro to destroy the current context and create a new one).

FreeType obviously isn't OpenGL specific, and GLU actually isn't either. You can link against and use GLU without linking against or using the main body of OpenGL, so probably waiting to see what SiegeLord comes up with is smartest. He's already assured me that it'll be set up to allow vertex data to be left on the GPU. Then we can have a nice TTF-as-geometry library that's platform agnostic.

axilmar
Member #1,204
April 2001

SFML seems very good. Very nice tutorials, nicely organized homepage, nice APIs. I will give it a try.

Go to: