Blender V2.61 - r43446

KX_FontObject.cpp

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00019  * All rights reserved.
00020  *
00021  * The Original Code is: all of this file.
00022  *
00023  * Contributor(s): none yet.
00024  *
00025  * ***** END GPL LICENSE BLOCK *****
00026  */
00027 
00032 #include "KX_FontObject.h"
00033 #include "DNA_curve_types.h"
00034 #include "KX_Scene.h"
00035 #include "KX_PythonInit.h"
00036 #include "BLI_math.h"
00037 #include "StringValue.h"
00038 
00039 /* paths needed for font load */
00040 #include "BLI_blenlib.h"
00041 #include "BKE_global.h"
00042 #include "BKE_font.h"
00043 #include "BKE_main.h"
00044 #include "DNA_packedFile_types.h"
00045 
00046 extern "C" {
00047 #include "BLF_api.h"
00048 }
00049 
00050 #define BGE_FONT_RES 100
00051 
00052 /* proptotype */
00053 int GetFontId(VFont *font);
00054 
00055 std::vector<STR_String> split_string(STR_String str)
00056 {
00057     std::vector<STR_String> text = std::vector<STR_String>();
00058 
00059     /* Split the string upon new lines */
00060     int begin=0, end=0;
00061     while (end < str.Length())
00062     {
00063         if(str.GetAt(end) == '\n')
00064         {
00065             text.push_back(str.Mid(begin, end-begin));
00066             begin = end+1;
00067         }
00068         end++;
00069     }
00070     //Now grab the last line
00071     text.push_back(str.Mid(begin, end-begin));
00072 
00073     return text;
00074 }
00075 
00076 KX_FontObject::KX_FontObject(   void* sgReplicationInfo,
00077                                 SG_Callbacks callbacks,
00078                                 RAS_IRenderTools* rendertools,
00079                                 Object *ob):
00080     KX_GameObject(sgReplicationInfo, callbacks),
00081     m_object(ob),
00082     m_dpi(72),
00083     m_resolution(1.f),
00084     m_rendertools(rendertools)
00085 {
00086     Curve *text = static_cast<Curve *> (ob->data);
00087     m_text = split_string(text->str);
00088     m_fsize = text->fsize;
00089     m_line_spacing = text->linedist;
00090     m_offset = MT_Vector3(text->xof, text->yof, 0);
00091     
00092     m_fontid = GetFontId(text->vfont);
00093     
00094     /* initialize the color with the object color and store it in the KX_Object class
00095        This is a workaround waiting for the fix:
00096        [#25487] BGE: Object Color only works when it has a keyed frame */
00097     copy_v4_v4(m_color, (const float*) ob->col);
00098     this->SetObjectColor((const MT_Vector4&) m_color);
00099 }
00100 
00101 KX_FontObject::~KX_FontObject()
00102 {
00103     //remove font from the scene list
00104     //it's handled in KX_Scene::NewRemoveObject
00105 }
00106 
00107 CValue* KX_FontObject::GetReplica() {
00108     KX_FontObject* replica = new KX_FontObject(*this);
00109     replica->ProcessReplica();
00110     return replica;
00111 }
00112 
00113 void KX_FontObject::ProcessReplica()
00114 {
00115     KX_GameObject::ProcessReplica();
00116     KX_GetActiveScene()->AddFont(this);
00117 }
00118 
00119 int GetFontId (VFont *font) {
00120     PackedFile *packedfile=NULL;
00121     int fontid = -1;
00122 
00123     if (font->packedfile) {
00124         packedfile= font->packedfile;
00125         fontid= BLF_load_mem(font->name, (unsigned char*)packedfile->data, packedfile->size);
00126         
00127         if (fontid == -1) {
00128             printf("ERROR: packed font \"%s\" could not be loaded.\n", font->name);
00129             fontid = BLF_load("default");
00130         }
00131         return fontid;
00132     }
00133     
00134     /* once we have packed working we can load the FO_BUILTIN_NAME font */
00135     const char *filepath = font->name;
00136     if (strcmp(FO_BUILTIN_NAME, filepath) == 0) {
00137         fontid = BLF_load("default");
00138         
00139         /* XXX the following code is supposed to work (after you add get_builtin_packedfile to BKE_font.h )
00140          * unfortunately it's crashing on blf_glyph.c:173 because gc->max_glyph_width is 0
00141          */
00142         // packedfile=get_builtin_packedfile();
00143         // fontid= BLF_load_mem(font->name, (unsigned char*)packedfile->data, packedfile->size);
00144         // return fontid;
00145 
00146         return BLF_load("default");
00147     }
00148     
00149     /* convert from absolute to relative */
00150     char expanded[256]; // font names can be bigger than FILE_MAX (240)
00151     BLI_strncpy(expanded, filepath, 256);
00152     BLI_path_abs(expanded, G.main->name);
00153     
00154     fontid = BLF_load(expanded);
00155 
00156     /* fallback */
00157     if (fontid == -1)
00158         fontid = BLF_load("default");
00159     
00160     return fontid;
00161 }
00162 
00163 void KX_FontObject::DrawText()
00164 {
00165     /* Allow for some logic brick control */
00166     if(this->GetProperty("Text"))
00167         m_text = split_string(this->GetProperty("Text")->GetText());
00168 
00169     /* only draws the text if visible */
00170     if(this->GetVisible() == 0) return;
00171 
00172     /* update the animated color */
00173     this->GetObjectColor().getValue(m_color);
00174 
00175     /* HARDCODED MULTIPLICATION FACTOR - this will affect the render resolution directly */
00176     float RES = BGE_FONT_RES * m_resolution;
00177 
00178     float size = m_fsize * m_object->size[0] * RES;
00179     float aspect = 1.f / (m_object->size[0] * RES);
00180 
00181     /* Get a working copy of the OpenGLMatrix to use */
00182     double mat[16];
00183     memcpy(mat, this->GetOpenGLMatrix(), sizeof(double)*16);
00184 
00185     /* Account for offset */
00186     MT_Vector3 offset = this->NodeGetWorldOrientation() * m_offset * this->NodeGetWorldScaling();
00187     mat[12] += offset[0]; mat[13] += offset[1]; mat[14] += offset[2];
00188 
00189     /* Orient the spacing vector */
00190     MT_Vector3 spacing = MT_Vector3(0, m_fsize*m_line_spacing, 0);
00191     spacing = this->NodeGetWorldOrientation() * spacing * this->NodeGetWorldScaling()[1];
00192 
00193     /* Draw each line, taking spacing into consideration */
00194     for(int i=0; i<m_text.size(); ++i)
00195     {
00196         if (i!=0)
00197         {
00198             mat[12] -= spacing[0];
00199             mat[13] -= spacing[1];
00200             mat[14] -= spacing[2];
00201         }
00202         m_rendertools->RenderText3D(m_fontid, m_text[i], int(size), m_dpi, m_color, mat, aspect);
00203     }
00204 }
00205 
00206 #ifdef WITH_PYTHON
00207 
00208 /* ------------------------------------------------------------------------- */
00209 /* Python Integration Hooks                                                  */
00210 /* ------------------------------------------------------------------------- */
00211 
00212 PyTypeObject KX_FontObject::Type = {
00213     PyVarObject_HEAD_INIT(NULL, 0)
00214     "KX_FontObject",
00215     sizeof(PyObjectPlus_Proxy),
00216     0,
00217     py_base_dealloc,
00218     0,
00219     0,
00220     0,
00221     0,
00222     py_base_repr,
00223     0,
00224     &KX_GameObject::Sequence,
00225     &KX_GameObject::Mapping,
00226     0,0,0,
00227     NULL,
00228     NULL,
00229     0,
00230     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
00231     0,0,0,0,0,0,0,
00232     Methods,
00233     0,
00234     0,
00235     &KX_GameObject::Type,
00236     0,0,0,0,0,0,
00237     py_base_new
00238 };
00239 
00240 PyMethodDef KX_FontObject::Methods[] = {
00241     {NULL,NULL} //Sentinel
00242 };
00243 
00244 PyAttributeDef KX_FontObject::Attributes[] = {
00245     //KX_PYATTRIBUTE_STRING_RW("text", 0, 280, false, KX_FontObject, m_text[0]), //arbitrary limit. 280 = 140 unicode chars in unicode
00246     KX_PYATTRIBUTE_RW_FUNCTION("text", KX_FontObject, pyattr_get_text, pyattr_set_text),
00247     KX_PYATTRIBUTE_FLOAT_RW("size", 0.0001f, 10000.0f, KX_FontObject, m_fsize),
00248     KX_PYATTRIBUTE_FLOAT_RW("resolution", 0.0001f, 10000.0f, KX_FontObject, m_resolution),
00249     /* KX_PYATTRIBUTE_INT_RW("dpi", 0, 10000, false, KX_FontObject, m_dpi), */// no real need for expose this I think
00250     { NULL }    //Sentinel
00251 };
00252 
00253 PyObject* KX_FontObject::pyattr_get_text(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
00254 {
00255     KX_FontObject* self= static_cast<KX_FontObject*>(self_v);
00256     STR_String str = STR_String();
00257     for(int i=0; i<self->m_text.size(); ++i)
00258     {
00259         if(i!=0)
00260             str += '\n';
00261         str += self->m_text[i];
00262     }
00263     return PyUnicode_From_STR_String(str);
00264 }
00265 
00266 int KX_FontObject::pyattr_set_text(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
00267 {
00268     KX_FontObject* self= static_cast<KX_FontObject*>(self_v);
00269     if(!PyUnicode_Check(value))
00270         return PY_SET_ATTR_FAIL;
00271     char* chars = _PyUnicode_AsString(value);
00272 
00273     /* Allow for some logic brick control */
00274     CValue* tprop = self->GetProperty("Text");
00275     if(tprop) {
00276         CValue *newstringprop = new CStringValue(STR_String(chars), "Text");
00277         self->SetProperty("Text", newstringprop);
00278         newstringprop->Release();
00279     }
00280     else {
00281         self->m_text = split_string(STR_String(chars));
00282     }
00283 
00284     return PY_SET_ATTR_SUCCESS;
00285 }
00286 
00287 #endif // WITH_PYTHON