2 * ***** BEGIN GPL LICENSE BLOCK *****
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19 * All rights reserved.
21 * The Original Code is: all of this file.
23 * Contributor(s): none yet.
25 * ***** END GPL LICENSE BLOCK *****
28 /** \file gameengine/Ketsji/KX_FontObject.cpp
32 #include "KX_FontObject.h"
33 #include "DNA_curve_types.h"
34 #include "DNA_vfont_types.h"
36 #include "KX_PythonInit.h"
38 #include "EXP_StringValue.h"
39 #include "RAS_IRasterizer.h"
41 /* paths needed for font load */
42 #include "BLI_blenlib.h"
43 #include "BKE_global.h"
46 #include "DNA_packedFile_types.h"
52 #define BGE_FONT_RES 100
55 int GetFontId(VFont *font);
57 static std::vector<STR_String> split_string(STR_String str)
59 std::vector<STR_String> text = std::vector<STR_String>();
61 /* Split the string upon new lines */
63 while (end < str.Length())
65 if (str.GetAt(end) == '\n')
67 text.push_back(str.Mid(begin, end-begin));
72 //Now grab the last line
73 text.push_back(str.Mid(begin, end-begin));
78 KX_FontObject::KX_FontObject(void* sgReplicationInfo,
79 SG_Callbacks callbacks,
80 RAS_IRasterizer* rasterizer,
82 bool do_color_management):
83 KX_GameObject(sgReplicationInfo, callbacks),
87 m_rasterizer(rasterizer),
88 m_do_color_management(do_color_management)
90 Curve *text = static_cast<Curve *> (ob->data);
91 m_text = split_string(text->str);
92 m_fsize = text->fsize;
93 m_line_spacing = text->linedist;
94 m_offset = MT_Vector3(text->xof, text->yof, 0);
96 m_fontid = GetFontId(text->vfont);
98 /* initialize the color with the object color and store it in the KX_Object class
99 * This is a workaround waiting for the fix:
100 * [#25487] BGE: Object Color only works when it has a keyed frame */
101 copy_v4_v4(m_color, (const float*) ob->col);
102 this->SetObjectColor((const MT_Vector4&) m_color);
105 KX_FontObject::~KX_FontObject()
107 //remove font from the scene list
108 //it's handled in KX_Scene::NewRemoveObject
111 CValue* KX_FontObject::GetReplica()
113 KX_FontObject* replica = new KX_FontObject(*this);
114 replica->ProcessReplica();
118 void KX_FontObject::ProcessReplica()
120 KX_GameObject::ProcessReplica();
123 int GetFontId(VFont *vfont)
125 PackedFile *packedfile=NULL;
128 if (vfont->packedfile) {
129 packedfile= vfont->packedfile;
130 fontid= BLF_load_mem(vfont->name, (unsigned char*)packedfile->data, packedfile->size);
133 printf("ERROR: packed font \"%s\" could not be loaded.\n", vfont->name);
134 fontid = BLF_load("default");
139 /* once we have packed working we can load the builtin font */
140 const char *filepath = vfont->name;
141 if (BKE_vfont_is_builtin(vfont)) {
142 fontid = BLF_load("default");
144 /* XXX the following code is supposed to work (after you add get_builtin_packedfile to BKE_font.h )
145 * unfortunately it's crashing on blf_glyph.c:173 because gc->max_glyph_width is 0
147 // packedfile=get_builtin_packedfile();
148 // fontid= BLF_load_mem(font->name, (unsigned char*)packedfile->data, packedfile->size);
151 return BLF_load("default");
154 /* convert from absolute to relative */
155 char expanded[256]; // font names can be bigger than FILE_MAX (240)
156 BLI_strncpy(expanded, filepath, 256);
157 BLI_path_abs(expanded, G.main->name);
159 fontid = BLF_load(expanded);
163 fontid = BLF_load("default");
168 void KX_FontObject::DrawFontText()
170 /* Allow for some logic brick control */
171 if (this->GetProperty("Text"))
172 m_text = split_string(this->GetProperty("Text")->GetText());
174 /* only draws the text if visible */
175 if (this->GetVisible() == 0) return;
177 /* update the animated color */
178 this->GetObjectColor().getValue(m_color);
180 /* Font Objects don't use the glsl shader, this color management code is copied from gpu_shader_material.glsl */
182 if (m_do_color_management) {
183 linearrgb_to_srgb_v4(color, m_color);
186 copy_v4_v4(color, m_color);
189 /* HARDCODED MULTIPLICATION FACTOR - this will affect the render resolution directly */
190 const float RES = BGE_FONT_RES * m_resolution;
192 const float size = m_fsize * this->NodeGetWorldScaling()[0] * RES;
193 const float aspect = m_fsize / size;
195 /* Get a working copy of the OpenGLMatrix to use */
196 float *mat = GetOpenGLMatrix();
198 /* Account for offset */
199 MT_Vector3 offset = this->NodeGetWorldOrientation() * m_offset * this->NodeGetWorldScaling();
200 mat[12] += offset[0]; mat[13] += offset[1]; mat[14] += offset[2];
202 /* Orient the spacing vector */
203 MT_Vector3 spacing = MT_Vector3(0.0f, m_fsize*m_line_spacing, 0.0f);
204 spacing = this->NodeGetWorldOrientation() * spacing * this->NodeGetWorldScaling()[1];
206 /* Draw each line, taking spacing into consideration */
207 for (int i=0; i<m_text.size(); ++i)
211 mat[12] -= spacing[0];
212 mat[13] -= spacing[1];
213 mat[14] -= spacing[2];
215 m_rasterizer->RenderText3D(m_fontid, m_text[i], int(size), m_dpi, color, mat, aspect);
221 /* ------------------------------------------------------------------------- */
222 /* Python Integration Hooks */
223 /* ------------------------------------------------------------------------- */
225 PyTypeObject KX_FontObject::Type = {
226 PyVarObject_HEAD_INIT(NULL, 0)
228 sizeof(PyObjectPlus_Proxy),
237 &KX_GameObject::Sequence,
238 &KX_GameObject::Mapping,
243 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
248 &KX_GameObject::Type,
253 PyMethodDef KX_FontObject::Methods[] = {
254 {NULL,NULL} //Sentinel
257 PyAttributeDef KX_FontObject::Attributes[] = {
258 //KX_PYATTRIBUTE_STRING_RW("text", 0, 280, false, KX_FontObject, m_text[0]), //arbitrary limit. 280 = 140 unicode chars in unicode
259 KX_PYATTRIBUTE_RW_FUNCTION("text", KX_FontObject, pyattr_get_text, pyattr_set_text),
260 KX_PYATTRIBUTE_FLOAT_RW("size", 0.0001f, 10000.0f, KX_FontObject, m_fsize),
261 KX_PYATTRIBUTE_FLOAT_RW("resolution", 0.0001f, 10000.0f, KX_FontObject, m_resolution),
262 /* KX_PYATTRIBUTE_INT_RW("dpi", 0, 10000, false, KX_FontObject, m_dpi), */// no real need for expose this I think
266 PyObject *KX_FontObject::pyattr_get_text(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
268 KX_FontObject* self = static_cast<KX_FontObject*>(self_v);
269 STR_String str = STR_String();
270 for (int i=0; i<self->m_text.size(); ++i)
274 str += self->m_text[i];
276 return PyUnicode_From_STR_String(str);
279 int KX_FontObject::pyattr_set_text(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
281 KX_FontObject* self = static_cast<KX_FontObject*>(self_v);
282 if (!PyUnicode_Check(value))
283 return PY_SET_ATTR_FAIL;
284 const char *chars = _PyUnicode_AsString(value);
286 /* Allow for some logic brick control */
287 CValue* tprop = self->GetProperty("Text");
289 CValue *newstringprop = new CStringValue(STR_String(chars), "Text");
290 self->SetProperty("Text", newstringprop);
291 newstringprop->Release();
294 self->m_text = split_string(STR_String(chars));
297 return PY_SET_ATTR_SUCCESS;
300 #endif // WITH_PYTHON