This patch creates an interface for ["Text"] properties in Font objects.
[blender.git] / source / gameengine / Ketsji / KX_FontObject.cpp
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
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.
8  *
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.
13  *
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.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file gameengine/Ketsji/KX_FontObject.cpp
29  *  \ingroup ketsji
30  */
31
32 #include "KX_FontObject.h"
33 #include "DNA_curve_types.h"
34 #include "KX_Scene.h"
35 #include "KX_PythonInit.h"
36 #include "BLI_math.h"
37 #include "StringValue.h"
38
39 extern "C" {
40 #include "BLF_api.h"
41 }
42
43 #define BGE_FONT_RES 100
44
45 std::vector<STR_String> split_string(STR_String str)
46 {
47         std::vector<STR_String> text = std::vector<STR_String>();
48
49         /* Split the string upon new lines */
50         int begin=0, end=0;
51         while (end < str.Length())
52         {
53                 if(str.GetAt(end) == '\n')
54                 {
55                         text.push_back(str.Mid(begin, end-begin));
56                         begin = end+1;
57                 }
58                 end++;
59         }
60         //Now grab the last line
61         text.push_back(str.Mid(begin, end-begin));
62
63         return text;
64 }
65 KX_FontObject::KX_FontObject(   void* sgReplicationInfo,
66                                                                 SG_Callbacks callbacks,
67                                                                 RAS_IRenderTools* rendertools,
68                                                                 Object *ob):
69         KX_GameObject(sgReplicationInfo, callbacks),
70         m_object(ob),
71         m_dpi(72),
72         m_resolution(1.f),
73         m_rendertools(rendertools)
74 {
75         Curve *text = static_cast<Curve *> (ob->data);
76         m_text = split_string(text->str);
77         m_fsize = text->fsize;
78         m_line_spacing = text->linedist;
79         m_offset = MT_Vector3(text->xof, text->yof, 0);
80
81         /* FO_BUILTIN_NAME != "default" */
82         /* I hope at some point Blender (2.5x) can have a single font   */
83         /* with unicode support for ui and OB_FONT                      */
84         /* once we have packed working we can load the FO_BUILTIN_NAME font     */
85         const char* filepath = text->vfont->name;
86         if (strcmp(FO_BUILTIN_NAME, filepath) == 0)
87                 filepath = "default";
88
89         /* XXX - if it's packed it will not work. waiting for bdiego (Diego) fix for that. */
90         m_fontid = BLF_load(filepath);
91         if (m_fontid == -1)
92                 m_fontid = BLF_load("default");
93
94         /* initialize the color with the object color and store it in the KX_Object class
95            This is a workaround waiting for the fix:
96            [#25487] BGE: Object Color only works when it has a keyed frame */
97         copy_v4_v4(m_color, (const float*) ob->col);
98         this->SetObjectColor((const MT_Vector4&) m_color);
99 }
100
101 KX_FontObject::~KX_FontObject()
102 {
103         //remove font from the scene list
104         //it's handled in KX_Scene::NewRemoveObject
105 }
106
107 CValue* KX_FontObject::GetReplica() {
108         KX_FontObject* replica = new KX_FontObject(*this);
109         replica->ProcessReplica();
110         return replica;
111 }
112
113 void KX_FontObject::ProcessReplica()
114 {
115         KX_GameObject::ProcessReplica();
116         KX_GetActiveScene()->AddFont(this);
117 }
118
119 void KX_FontObject::DrawText()
120 {
121         /* Allow for some logic brick control */
122         if(this->GetProperty("Text"))
123                 m_text = split_string(this->GetProperty("Text")->GetText());
124
125         /* only draws the text if visible */
126         if(this->GetVisible() == 0) return;
127
128         /* update the animated color */
129         this->GetObjectColor().getValue(m_color);
130
131         /* HARDCODED MULTIPLICATION FACTOR - this will affect the render resolution directly */
132         float RES = BGE_FONT_RES * m_resolution;
133
134         float size = m_fsize * m_object->size[0] * RES;
135         float aspect = 1.f / (m_object->size[0] * RES);
136
137         /* Get a working copy of the OpenGLMatrix to use */
138         double mat[16];
139         memcpy(mat, this->GetOpenGLMatrix(), sizeof(double)*16);
140
141         /* Account for offset */
142         MT_Vector3 offset = this->NodeGetWorldOrientation() * m_offset * this->NodeGetWorldScaling();
143         mat[12] += offset[0]; mat[13] += offset[1]; mat[14] += offset[2];
144
145         /* Orient the spacing vector */
146         MT_Vector3 spacing = MT_Vector3(0, m_fsize*m_line_spacing, 0);
147         spacing = this->NodeGetWorldOrientation() * spacing * this->NodeGetWorldScaling()[1];
148
149         /* Draw each line, taking spacing into consideration */
150         for(int i=0; i<m_text.size(); ++i)
151         {
152                 if (i!=0)
153                 {
154                         mat[12] -= spacing[0];
155                         mat[13] -= spacing[1];
156                         mat[14] -= spacing[2];
157                 }
158                 m_rendertools->RenderText3D(m_fontid, m_text[i], int(size), m_dpi, m_color, mat, aspect);
159         }
160 }
161
162 #ifdef WITH_PYTHON
163
164 /* ------------------------------------------------------------------------- */
165 /* Python Integration Hooks                                                                      */
166 /* ------------------------------------------------------------------------- */
167
168 PyTypeObject KX_FontObject::Type = {
169         PyVarObject_HEAD_INIT(NULL, 0)
170         "KX_FontObject",
171         sizeof(PyObjectPlus_Proxy),
172         0,
173         py_base_dealloc,
174         0,
175         0,
176         0,
177         0,
178         py_base_repr,
179         0,
180         &KX_GameObject::Sequence,
181         &KX_GameObject::Mapping,
182         0,0,0,
183         NULL,
184         NULL,
185         0,
186         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
187         0,0,0,0,0,0,0,
188         Methods,
189         0,
190         0,
191         &KX_GameObject::Type,
192         0,0,0,0,0,0,
193         py_base_new
194 };
195
196 PyMethodDef KX_FontObject::Methods[] = {
197         {NULL,NULL} //Sentinel
198 };
199
200 PyAttributeDef KX_FontObject::Attributes[] = {
201         //KX_PYATTRIBUTE_STRING_RW("text", 0, 280, false, KX_FontObject, m_text[0]), //arbitrary limit. 280 = 140 unicode chars in unicode
202         KX_PYATTRIBUTE_RW_FUNCTION("text", KX_FontObject, pyattr_get_text, pyattr_set_text),
203         KX_PYATTRIBUTE_FLOAT_RW("size", 0.0001f, 10000.0f, KX_FontObject, m_fsize),
204         KX_PYATTRIBUTE_FLOAT_RW("resolution", 0.0001f, 10000.0f, KX_FontObject, m_resolution),
205         /* KX_PYATTRIBUTE_INT_RW("dpi", 0, 10000, false, KX_FontObject, m_dpi), */// no real need for expose this I think
206         { NULL }        //Sentinel
207 };
208
209 PyObject* KX_FontObject::pyattr_get_text(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
210 {
211         KX_FontObject* self= static_cast<KX_FontObject*>(self_v);
212         STR_String str = STR_String();
213         for(int i=0; i<self->m_text.size(); ++i)
214         {
215                 if(i!=0)
216                         str += '\n';
217                 str += self->m_text[i];
218         }
219         return PyUnicode_From_STR_String(str);
220 }
221
222 int KX_FontObject::pyattr_set_text(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
223 {
224         KX_FontObject* self= static_cast<KX_FontObject*>(self_v);
225         if(!PyUnicode_Check(value))
226                 return PY_SET_ATTR_FAIL;
227         char* chars = _PyUnicode_AsString(value);
228
229         /* Allow for some logic brick control */
230         CValue* tprop = self->GetProperty("Text");
231         if(tprop) {
232                 CValue *newstringprop = new CStringValue(STR_String(chars), "Text");
233                 self->SetProperty("Text", newstringprop);
234                 newstringprop->Release();
235         }
236         else {
237                 self->m_text = split_string(STR_String(chars));
238         }
239
240         return PY_SET_ATTR_SUCCESS;
241 }
242
243 #endif // WITH_PYTHON