From 7038db28fa6715915235df06a075d1a8f5282dd8 Mon Sep 17 00:00:00 2001 From: Porteries Tristan Date: Fri, 3 Jun 2016 08:19:20 +0000 Subject: [PATCH] UPBGE: Render text objects as mesh objects. Previously all text objects was rendered at the frame render end. It caused that as text objects use transparency, they were all on top of all other transparent regular meshes which are not writing to the depth buffer. To solve this issue the text objects should be rendered like the other regular meshes and enjoy the ordering made for transparency objects. But this would assume that text objects are meshes which is not really the case as they don't use any materials. To first considerate the text objects as meshes they need a material. This material is particular as it doesn't bind any shader. It exists only to say that meshes using it are texts. This material must be global to the game engine to make sure that we use as much as possible a common RAS_DisplayArrayBucket and RAS_MaterialBucket. The material is then a subclass of RAS_IPolyMaterial named KX_TextMaterial which contains mostly empty functions, only it's constructor enable material text flags. An instance of this material is stored statically in KX_TextMaterial.cpp and get its pointer with GetTextMaterial from KX_TextMaterial.h. RAS_IPolyMaterial contains a new function IsText which returns true for KX_TextMaterial depending of a text flag. This function is used when creating the material bucket to add the material bucket in a specific list accessed with m_buckets[TEXT_BUCKET]. The function is used again when rendering to call IndexPrimitivesText with the mesh user. As texts objects doesn't have any RAS_MeshObject and RAS_DisplayArray, then the RAS_DisplayArrayBucket must check if the m_mesh is non NULL before for example get if it is modified. Also m_mesh is used to differ a modifier display array bucket than a text display array bucket in FindDisplayArrayBucket as the both have a NULL display array. As KX_FontObject inherit of KX_GameObject, we just have to make virtual functions managing mesh user and mesh slots (AddMeshUser, UpdateBuckets). The override of AddMeshUser just find or create the material bucket with the global KX_TextMaterial. UpdateBuckets updates all data needed to render the texts in the RAS_TextUser. The RAS_TextUser is a subclass of RAS_MeshUser containing extra data used to render the texts: - dpi - size - aspect - resolution - fontid - offset - spacing - texts[] In IndexPrimitivesText we loop on all text contained in RAS_TextUser::m_texts, translate text matrix and call RenderText3D with all other values contained in RAS_TextUser. Two bugs are fixed with this patch coresponding to issues #119 and #114. #119 is about unordered transparency and #114 is for text rendered even if they are inactive because the scene render all object in the list of texts which is wrong as some of them can be inactive. This is fixed by the fact that only active objects update theirs mesh user and add theirs mesh slot to be rendered. This patch allow for the moment to draw text objects as meshes with an empty material, but later if a way is found to render texts with original material, the rest will be already done. --- .../Converter/BL_BlenderDataConversion.cpp | 4 +- source/gameengine/Ketsji/CMakeLists.txt | 2 + source/gameengine/Ketsji/KX_FontObject.cpp | 134 +++++++++++------- source/gameengine/Ketsji/KX_FontObject.h | 3 +- source/gameengine/Ketsji/KX_GameObject.h | 4 +- source/gameengine/Ketsji/KX_KetsjiEngine.cpp | 7 - source/gameengine/Ketsji/KX_Scene.cpp | 9 -- source/gameengine/Ketsji/KX_Scene.h | 5 - source/gameengine/Ketsji/KX_TextMaterial.cpp | 116 +++++++++++++++ source/gameengine/Ketsji/KX_TextMaterial.h | 64 +++++++++ source/gameengine/Rasterizer/CMakeLists.txt | 2 + .../Rasterizer/RAS_BucketManager.cpp | 4 + .../gameengine/Rasterizer/RAS_BucketManager.h | 1 + .../Rasterizer/RAS_DisplayArrayBucket.cpp | 11 +- .../Rasterizer/RAS_DisplayArrayBucket.h | 3 +- .../Rasterizer/RAS_IPolygonMaterial.cpp | 9 +- .../Rasterizer/RAS_IPolygonMaterial.h | 2 + .../gameengine/Rasterizer/RAS_IRasterizer.h | 3 + .../Rasterizer/RAS_MaterialBucket.cpp | 11 +- .../Rasterizer/RAS_MaterialBucket.h | 2 +- source/gameengine/Rasterizer/RAS_MeshSlot.cpp | 2 +- .../RAS_OpenGLRasterizer.cpp | 26 ++++ .../RAS_OpenGLRasterizer.h | 1 + source/gameengine/Rasterizer/RAS_TextUser.cpp | 115 +++++++++++++++ source/gameengine/Rasterizer/RAS_TextUser.h | 69 +++++++++ .../gameengine/VideoTexture/ImageRender.cpp | 2 - 26 files changed, 521 insertions(+), 90 deletions(-) create mode 100644 source/gameengine/Ketsji/KX_TextMaterial.cpp create mode 100644 source/gameengine/Ketsji/KX_TextMaterial.h create mode 100644 source/gameengine/Rasterizer/RAS_TextUser.cpp create mode 100644 source/gameengine/Rasterizer/RAS_TextUser.h diff --git a/source/gameengine/Converter/BL_BlenderDataConversion.cpp b/source/gameengine/Converter/BL_BlenderDataConversion.cpp index 976a3ae2b210..1742589a2d91 100644 --- a/source/gameengine/Converter/BL_BlenderDataConversion.cpp +++ b/source/gameengine/Converter/BL_BlenderDataConversion.cpp @@ -1141,9 +1141,7 @@ static KX_GameObject *gameobject_from_blenderobject( /* font objects have no bounding box */ gameobj = new KX_FontObject(kxscene,KX_Scene::m_callbacks, rendertools, ob, do_color_management); - /* add to the list only the visible fonts */ - if ((ob->lay & kxscene->GetBlenderScene()->lay) != 0) - kxscene->AddFont(static_cast(gameobj)); + kxscene->AddFont(static_cast(gameobj)); break; } diff --git a/source/gameengine/Ketsji/CMakeLists.txt b/source/gameengine/Ketsji/CMakeLists.txt index 0422ec8aec67..dfd67f060088 100644 --- a/source/gameengine/Ketsji/CMakeLists.txt +++ b/source/gameengine/Ketsji/CMakeLists.txt @@ -130,6 +130,7 @@ set(SRC KX_SoundActuator.cpp KX_StateActuator.cpp KX_SteeringActuator.cpp + KX_TextMaterial.cpp KX_TimeCategoryLogger.cpp KX_TimeLogger.cpp KX_TouchEventManager.cpp @@ -216,6 +217,7 @@ set(SRC KX_SoundActuator.h KX_StateActuator.h KX_SteeringActuator.h + KX_TextMaterial.h KX_TimeCategoryLogger.h KX_TimeLogger.h KX_TouchEventManager.h diff --git a/source/gameengine/Ketsji/KX_FontObject.cpp b/source/gameengine/Ketsji/KX_FontObject.cpp index 6f3160559bf7..0be76641d391 100644 --- a/source/gameengine/Ketsji/KX_FontObject.cpp +++ b/source/gameengine/Ketsji/KX_FontObject.cpp @@ -35,9 +35,13 @@ #include "KX_Scene.h" #include "KX_Globals.h" #include "KX_PythonInit.h" +#include "KX_TextMaterial.h" #include "BLI_math.h" #include "EXP_StringValue.h" #include "RAS_IRasterizer.h" +#include "RAS_BucketManager.h" +#include "RAS_MaterialBucket.h" +#include "RAS_TextUser.h" /* paths needed for font load */ #include "BLI_blenlib.h" @@ -113,6 +117,85 @@ void KX_FontObject::ProcessReplica() KX_GameObject::ProcessReplica(); } +void KX_FontObject::AddMeshUser() +{ + m_meshUser = new RAS_TextUser(m_pClient_info); + + // set the part of the mesh slot that never change + float *fl = GetOpenGLMatrixPtr()->getPointer(); + m_meshUser->SetMatrix(fl); + + RAS_BucketManager *bucketManager = GetScene()->GetBucketManager(); + bool created = false; + RAS_MaterialBucket *bucket = bucketManager->FindBucket(GetTextMaterial(), created); + + // If the material bucket is just created then we add a new mesh slot. + if (created) { + bucket->AddMesh(NULL); + } + + /* We copy the original mesh slot which is at the begin of the list, if it's not the case it + * doesn't matter as the mesh slot are all similar exepted their mesh user pointer which is + * set to NULL in copy. By copying instead of adding a mesh slot we reuse the same display + * array bucket. + */ + RAS_MeshSlot *ms = bucket->CopyMesh(*bucket->msBegin()); + ms->SetMeshUser(m_meshUser); + ms->SetDeformer(NULL); + m_meshUser->AddMeshSlot(ms); +} + +void KX_FontObject::UpdateBuckets() +{ + // Update datas and add mesh slot to be rendered only if the object is not culled. + if (m_bVisible && m_meshUser) { + if (m_pSGNode->IsDirty()) { + GetOpenGLMatrix(); + } + + // Allow for some logic brick control + if (GetProperty("Text")) { + m_text = split_string(GetProperty("Text")->GetText()); + } + + // update the animated color + GetObjectColor().getValue(m_color); + + // Font Objects don't use the glsl shader, this color management code is copied from gpu_shader_material.glsl + float color[4]; + if (m_do_color_management) { + linearrgb_to_srgb_v4(color, m_color); + } + else { + copy_v4_v4(color, m_color); + } + + // HARDCODED MULTIPLICATION FACTOR - this will affect the render resolution directly + const float RES = BGE_FONT_RES * m_resolution; + + const float size = m_fsize * NodeGetWorldScaling()[0] * RES; + const float aspect = m_fsize / size; + + // Account for offset + MT_Vector3 offset = NodeGetWorldOrientation() * m_offset * NodeGetWorldScaling(); + // Orient the spacing vector + MT_Vector3 spacing = MT_Vector3(0.0f, m_fsize * m_line_spacing, 0.0f); + + RAS_TextUser *textUser = (RAS_TextUser *)m_meshUser; + + textUser->SetColor(MT_Vector4(color)); + textUser->SetFrontFace(!m_bIsNegativeScaling); + textUser->SetFontId(m_fontid); + textUser->SetSize(size); + textUser->SetDpi(m_dpi); + textUser->SetAspect(aspect); + textUser->SetOffset(offset); + textUser->SetSpacing(spacing); + textUser->SetTexts(m_text); + textUser->ActivateMeshSlots(); + } +} + int GetFontId(VFont *vfont) { PackedFile *packedfile = NULL; @@ -158,57 +241,6 @@ int GetFontId(VFont *vfont) return fontid; } -void KX_FontObject::DrawFontText() -{ - // Allow for some logic brick control - if (GetProperty("Text")) - m_text = split_string(GetProperty("Text")->GetText()); - - // only draws the text if visible - if (GetVisible() == 0) { - return; - } - - // update the animated color - GetObjectColor().getValue(m_color); - - // Font Objects don't use the glsl shader, this color management code is copied from gpu_shader_material.glsl - float color[4]; - if (m_do_color_management) { - linearrgb_to_srgb_v4(color, m_color); - } - else { - copy_v4_v4(color, m_color); - } - - // HARDCODED MULTIPLICATION FACTOR - this will affect the render resolution directly - const float RES = BGE_FONT_RES * m_resolution; - - const float size = m_fsize * NodeGetWorldScaling()[0] * RES; - const float aspect = m_fsize / size; - - /* Get a working copy of the OpenGLMatrix to use */ - float *mat = GetOpenGLMatrix(); - - /* Account for offset */ - MT_Vector3 offset = NodeGetWorldOrientation() * m_offset * NodeGetWorldScaling(); - mat[12] += offset[0]; mat[13] += offset[1]; mat[14] += offset[2]; - - /* Orient the spacing vector */ - MT_Vector3 spacing = MT_Vector3(0.0f, m_fsize * m_line_spacing, 0.0f); - spacing = NodeGetWorldOrientation() * spacing * NodeGetWorldScaling()[1]; - - /* Draw each line, taking spacing into consideration */ - for (unsigned int i = 0; i < m_text.size(); ++i) { - if (i != 0) { - mat[12] -= spacing[0]; - mat[13] -= spacing[1]; - mat[14] -= spacing[2]; - } - m_rasterizer->RenderText3D(m_fontid, m_text[i], int(size), m_dpi, color, mat, aspect); - } -} - #ifdef WITH_PYTHON /* ------------------------------------------------------------------------- */ diff --git a/source/gameengine/Ketsji/KX_FontObject.h b/source/gameengine/Ketsji/KX_FontObject.h index 01b4159a9d50..4c1f1c32982e 100644 --- a/source/gameengine/Ketsji/KX_FontObject.h +++ b/source/gameengine/Ketsji/KX_FontObject.h @@ -45,7 +45,8 @@ class KX_FontObject : public KX_GameObject virtual ~KX_FontObject(); - void DrawFontText(); + virtual void AddMeshUser(); + virtual void UpdateBuckets(); /** * Inherited from CValue -- return a new copy of this diff --git a/source/gameengine/Ketsji/KX_GameObject.h b/source/gameengine/Ketsji/KX_GameObject.h index 92e9eb4e778b..8bb2af67c7fb 100644 --- a/source/gameengine/Ketsji/KX_GameObject.h +++ b/source/gameengine/Ketsji/KX_GameObject.h @@ -721,7 +721,7 @@ class KX_GameObject : public SCA_IObject * Update buckets to indicate that there is a new * user of this object's meshes. */ - void + virtual void AddMeshUser( ); @@ -730,7 +730,7 @@ class KX_GameObject : public SCA_IObject * creating or duplicating the object, changing * visibility, object color, .. . */ - void UpdateBuckets(); + virtual void UpdateBuckets(); /** * Clear the meshes associated with this class diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp index d2e21665132b..da61523f26c8 100644 --- a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp +++ b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp @@ -298,8 +298,6 @@ void KX_KetsjiEngine::RenderDome() // do the rendering m_dome->RenderDomeFrame(scene, cam, i); - // render all the font objects for this scene - scene->RenderFonts(); } list *cameras = scene->GetCameras(); @@ -315,8 +313,6 @@ void KX_KetsjiEngine::RenderDome() // do the rendering m_dome->RenderDomeFrame(scene, (*it), i); - // render all the font objects for this scene - scene->RenderFonts(); } it++; @@ -1184,9 +1180,6 @@ void KX_KetsjiEngine::RenderFrame(KX_Scene *scene, KX_Camera *cam) scene->RenderBuckets(camtrans, m_rasterizer); - // render all the font objects for this scene - scene->RenderFonts(); - if (scene->GetPhysicsEnvironment()) scene->GetPhysicsEnvironment()->DebugDrawWorld(); } diff --git a/source/gameengine/Ketsji/KX_Scene.cpp b/source/gameengine/Ketsji/KX_Scene.cpp index c7e5cf8a6952..94470bf254c1 100644 --- a/source/gameengine/Ketsji/KX_Scene.cpp +++ b/source/gameengine/Ketsji/KX_Scene.cpp @@ -1749,15 +1749,6 @@ void KX_Scene::RenderBuckets(const MT_Transform & cameratransform, KX_BlenderMaterial::EndFrame(rasty); } -void KX_Scene::RenderFonts() -{ - list::iterator it = m_fonts.begin(); - while (it != m_fonts.end()) { - (*it)->DrawFontText(); - ++it; - } -} - void KX_Scene::UpdateObjectLods() { if (!m_active_camera) diff --git a/source/gameengine/Ketsji/KX_Scene.h b/source/gameengine/Ketsji/KX_Scene.h index 8dbf203b6456..106e95de82e9 100644 --- a/source/gameengine/Ketsji/KX_Scene.h +++ b/source/gameengine/Ketsji/KX_Scene.h @@ -396,11 +396,6 @@ class KX_Scene : public CValue, public SCA_IScene KX_FontObject* ); - /** Render the fonts in this scene. */ - void - RenderFonts( - ); - /** Camera Routines */ std::list* diff --git a/source/gameengine/Ketsji/KX_TextMaterial.cpp b/source/gameengine/Ketsji/KX_TextMaterial.cpp new file mode 100644 index 000000000000..65740f07f9e4 --- /dev/null +++ b/source/gameengine/Ketsji/KX_TextMaterial.cpp @@ -0,0 +1,116 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gameengine/Ketsji/KX_TextMaterial.cpp + * \ingroup ketsji + */ + +#include "KX_TextMaterial.h" + +#include "DNA_material_types.h" + +static KX_TextMaterial textMaterial = KX_TextMaterial(); + +KX_TextMaterial *GetTextMaterial() +{ + return &textMaterial; +} + +KX_TextMaterial::KX_TextMaterial() + :RAS_IPolyMaterial("__TextMaterial__", NULL) +{ + m_rasMode |= (RAS_ALPHA | RAS_TEXT); + m_flag |= RAS_BLENDERGLSL; + m_alphablend = GEMAT_ALPHA; +} + +KX_TextMaterial::~KX_TextMaterial() +{ +} + +void KX_TextMaterial::Activate(RAS_IRasterizer *rasty) +{ +} + +void KX_TextMaterial::Desactivate(RAS_IRasterizer *rasty) +{ +} + +void KX_TextMaterial::ActivateInstancing(RAS_IRasterizer *rasty, void *matrixoffset, void *positionoffset, void *coloroffset, unsigned int stride) +{ +} + +void KX_TextMaterial::DesactivateInstancing() +{ +} + +void KX_TextMaterial::ActivateMeshSlot(RAS_MeshSlot *ms, RAS_IRasterizer *rasty) +{ +} + +const STR_String& KX_TextMaterial::GetTextureName() const +{ + static STR_String empty = ""; + return empty; +} + +Material *KX_TextMaterial::GetBlenderMaterial() const +{ + return NULL; +} + +Image *KX_TextMaterial::GetBlenderImage() const +{ + return NULL; +} + +MTexPoly *KX_TextMaterial::GetMTexPoly() const +{ + return NULL; +} + +Scene *KX_TextMaterial::GetBlenderScene() const +{ + return NULL; +} + +bool KX_TextMaterial::UseInstancing() const +{ + return false; +} + +void KX_TextMaterial::ReleaseMaterial() +{ +} + +void KX_TextMaterial::UpdateIPO(MT_Vector4 rgba, MT_Vector3 specrgb, MT_Scalar hard, MT_Scalar spec, MT_Scalar ref, + MT_Scalar emit, MT_Scalar ambient, MT_Scalar alpha, MT_Scalar specalpha) +{ +} + +void KX_TextMaterial::Replace_IScene(SCA_IScene *val) +{ +} + +void KX_TextMaterial::OnConstruction() +{ +} diff --git a/source/gameengine/Ketsji/KX_TextMaterial.h b/source/gameengine/Ketsji/KX_TextMaterial.h new file mode 100644 index 000000000000..3f10b1e643dc --- /dev/null +++ b/source/gameengine/Ketsji/KX_TextMaterial.h @@ -0,0 +1,64 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file KX_TextMaterial.h + * \ingroup ketsji + * \brief Fake material used for all text objects. + */ + +#ifndef __KX_TEXTMATERIAL_H__ +#define __KX_TEXTMATERIAL_H__ + +#include "RAS_IPolygonMaterial.h" + +class KX_TextMaterial : public RAS_IPolyMaterial +{ +public: + KX_TextMaterial(); + virtual ~KX_TextMaterial(); + + virtual void Activate(RAS_IRasterizer *rasty); + virtual void Desactivate(RAS_IRasterizer *rasty); + virtual void ActivateInstancing(RAS_IRasterizer *rasty, void *matrixoffset, void *positionoffset, void *coloroffset, unsigned int stride); + virtual void DesactivateInstancing(); + virtual void ActivateMeshSlot(RAS_MeshSlot *ms, RAS_IRasterizer *rasty); + + virtual const STR_String& GetTextureName() const; + virtual Material *GetBlenderMaterial() const; + virtual Image *GetBlenderImage() const; + virtual MTexPoly *GetMTexPoly() const; + virtual Scene *GetBlenderScene() const; + virtual bool UseInstancing() const; + virtual void ReleaseMaterial(); + + virtual void UpdateIPO(MT_Vector4 rgba, MT_Vector3 specrgb, MT_Scalar hard, MT_Scalar spec, MT_Scalar ref, + MT_Scalar emit, MT_Scalar ambient, MT_Scalar alpha, MT_Scalar specalpha); + + virtual void Replace_IScene(SCA_IScene *val); + + virtual void OnConstruction(); +}; + +/// Global text material instance pointer used to create or find a material bucket in the bucket manager. +KX_TextMaterial *GetTextMaterial(); + +#endif // __KX_TEXTMATERIAL_H__ diff --git a/source/gameengine/Rasterizer/CMakeLists.txt b/source/gameengine/Rasterizer/CMakeLists.txt index 552226409185..d10c897a56fe 100644 --- a/source/gameengine/Rasterizer/CMakeLists.txt +++ b/source/gameengine/Rasterizer/CMakeLists.txt @@ -60,6 +60,7 @@ set(SRC RAS_Polygon.cpp RAS_Shader.cpp RAS_Texture.cpp + RAS_TextUser.cpp RAS_TexVert.cpp RAS_ICanvas.cpp RAS_2DFilterData.cpp @@ -91,6 +92,7 @@ set(SRC RAS_Rect.h RAS_Shader.h RAS_Texture.h + RAS_TextUser.h RAS_TexVert.h RAS_OpenGLFilters/RAS_Blur2DFilter.h RAS_OpenGLFilters/RAS_Dilation2DFilter.h diff --git a/source/gameengine/Rasterizer/RAS_BucketManager.cpp b/source/gameengine/Rasterizer/RAS_BucketManager.cpp index 51547984c928..601a9f789623 100644 --- a/source/gameengine/Rasterizer/RAS_BucketManager.cpp +++ b/source/gameengine/Rasterizer/RAS_BucketManager.cpp @@ -332,6 +332,10 @@ RAS_MaterialBucket *RAS_BucketManager::FindBucket(RAS_IPolyMaterial *material, b else m_buckets[useinstancing ? SOLID_SHADOW_INSTANCING_BUCKET : SOLID_SHADOW_BUCKET].push_back(bucket); } + if (material->IsText()) { + m_buckets[TEXT_BUCKET].push_back(bucket); + } + // Used to free the bucket. m_buckets[ALL_BUCKET].push_back(bucket); return bucket; diff --git a/source/gameengine/Rasterizer/RAS_BucketManager.h b/source/gameengine/Rasterizer/RAS_BucketManager.h index 4179d018878f..0cb1ff76c58e 100644 --- a/source/gameengine/Rasterizer/RAS_BucketManager.h +++ b/source/gameengine/Rasterizer/RAS_BucketManager.h @@ -72,6 +72,7 @@ class RAS_BucketManager ALPHA_SHADOW_BUCKET, SOLID_SHADOW_INSTANCING_BUCKET, ALPHA_SHADOW_INSTANCING_BUCKET, + TEXT_BUCKET, ALL_BUCKET, NUM_BUCKET_TYPE, }; diff --git a/source/gameengine/Rasterizer/RAS_DisplayArrayBucket.cpp b/source/gameengine/Rasterizer/RAS_DisplayArrayBucket.cpp index f25d79093745..c481cea9ef90 100644 --- a/source/gameengine/Rasterizer/RAS_DisplayArrayBucket.cpp +++ b/source/gameengine/Rasterizer/RAS_DisplayArrayBucket.cpp @@ -126,6 +126,11 @@ RAS_MaterialBucket *RAS_DisplayArrayBucket::GetMaterialBucket() const return m_bucket; } +RAS_MeshObject *RAS_DisplayArrayBucket::GetMesh() const +{ + return m_mesh; +} + void RAS_DisplayArrayBucket::ActivateMesh(RAS_MeshSlot *slot) { m_activeMeshSlots.push_back(slot); @@ -205,7 +210,7 @@ void RAS_DisplayArrayBucket::UpdateActiveMeshSlots(RAS_IRasterizer *rasty) } } - if (m_mesh->GetModifiedFlag() & RAS_MeshObject::MESH_MODIFIED) { + if (m_mesh && m_mesh->GetModifiedFlag() & RAS_MeshObject::MESH_MODIFIED) { m_meshModified = true; } @@ -217,7 +222,9 @@ void RAS_DisplayArrayBucket::UpdateActiveMeshSlots(RAS_IRasterizer *rasty) void RAS_DisplayArrayBucket::SetMeshUnmodified() { - m_mesh->SetModifiedFlag(0); + if (m_mesh) { + m_mesh->SetModifiedFlag(0); + } } RAS_IStorageInfo *RAS_DisplayArrayBucket::GetStorageInfo() const diff --git a/source/gameengine/Rasterizer/RAS_DisplayArrayBucket.h b/source/gameengine/Rasterizer/RAS_DisplayArrayBucket.h index c1123bff7338..c4a458cb0e0e 100644 --- a/source/gameengine/Rasterizer/RAS_DisplayArrayBucket.h +++ b/source/gameengine/Rasterizer/RAS_DisplayArrayBucket.h @@ -58,7 +58,7 @@ class RAS_DisplayArrayBucket RAS_MaterialBucket *m_bucket; /// The display array = list of vertexes and indexes. RAS_DisplayArray *m_displayArray; - /// The parent mesh object. + /// The parent mesh object, it can be NULL for text objects. RAS_MeshObject *m_mesh; /// The list fo all visible mesh slots to render this frame. RAS_MeshSlotList m_activeMeshSlots; @@ -98,6 +98,7 @@ class RAS_DisplayArrayBucket /// \section Accesor RAS_DisplayArray *GetDisplayArray() const; RAS_MaterialBucket *GetMaterialBucket() const; + RAS_MeshObject *GetMesh() const; /// \section Active Mesh Slots Management. void ActivateMesh(RAS_MeshSlot *slot); diff --git a/source/gameengine/Rasterizer/RAS_IPolygonMaterial.cpp b/source/gameengine/Rasterizer/RAS_IPolygonMaterial.cpp index 7164c3548c62..6c33510b3f66 100644 --- a/source/gameengine/Rasterizer/RAS_IPolygonMaterial.cpp +++ b/source/gameengine/Rasterizer/RAS_IPolygonMaterial.cpp @@ -43,7 +43,9 @@ RAS_IPolyMaterial::RAS_IPolyMaterial( m_rasMode(0), m_flag(0) { - m_drawingmode = ConvertFaceMode(game); + if (game) { + m_drawingmode = ConvertFaceMode(game); + } for (unsigned short i = 0; i < RAS_Texture::MaxUnits; ++i) { m_textures[i] = NULL; @@ -82,6 +84,11 @@ bool RAS_IPolyMaterial::IsWire() const return (m_rasMode & RAS_WIRE); } +bool RAS_IPolyMaterial::IsText() const +{ + return (m_rasMode & RAS_TEXT); +} + void RAS_IPolyMaterial::GetRGBAColor(unsigned char *rgba) const { *rgba++ = 0xFF; diff --git a/source/gameengine/Rasterizer/RAS_IPolygonMaterial.h b/source/gameengine/Rasterizer/RAS_IPolygonMaterial.h index 8984d096e844..91340ed75cb0 100644 --- a/source/gameengine/Rasterizer/RAS_IPolygonMaterial.h +++ b/source/gameengine/Rasterizer/RAS_IPolygonMaterial.h @@ -66,6 +66,7 @@ enum MaterialRasterizerModes RAS_ZSORT = 4, RAS_ALPHA = 8, RAS_WIRE = 64, + RAS_TEXT = 128, RAS_TWOSIDED = 512, }; @@ -107,6 +108,7 @@ class RAS_IPolyMaterial bool IsAlpha() const; bool IsZSort() const; bool IsWire() const; + bool IsText() const; int GetDrawingMode() const; virtual STR_String& GetName(); unsigned int GetFlag() const; diff --git a/source/gameengine/Rasterizer/RAS_IRasterizer.h b/source/gameengine/Rasterizer/RAS_IRasterizer.h index 69c46b5313de..e87882967adf 100644 --- a/source/gameengine/Rasterizer/RAS_IRasterizer.h +++ b/source/gameengine/Rasterizer/RAS_IRasterizer.h @@ -379,6 +379,9 @@ class RAS_IRasterizer * IndexPrimitives_3DText will render text into the polygons. */ virtual void IndexPrimitives_3DText(class RAS_MeshSlot *ms, class RAS_IPolyMaterial *polymat) = 0; + + /// Render text mesh slot using BLF functions. + virtual void IndexPrimitivesText(RAS_MeshSlot *ms) = 0; virtual void SetProjectionMatrix(MT_CmMatrix4x4 &mat) = 0; diff --git a/source/gameengine/Rasterizer/RAS_MaterialBucket.cpp b/source/gameengine/Rasterizer/RAS_MaterialBucket.cpp index 07b117556e31..141e6665cd40 100644 --- a/source/gameengine/Rasterizer/RAS_MaterialBucket.cpp +++ b/source/gameengine/Rasterizer/RAS_MaterialBucket.cpp @@ -186,16 +186,19 @@ void RAS_MaterialBucket::RenderMeshSlot(const MT_Transform& cameratrans, RAS_IRa ms->m_mesh->SortPolygons(ms, cameratrans * MT_Transform(meshUser->GetMatrix())); rasty->PushMatrix(); - if (!ms->m_pDeformer || !ms->m_pDeformer->SkipVertexTransform()) { + if ((!ms->m_pDeformer || !ms->m_pDeformer->SkipVertexTransform()) && !m_material->IsText()) { float mat[16]; rasty->GetTransform(meshUser->GetMatrix(), m_material->GetDrawingMode(), mat); rasty->MultMatrix(mat); } if (m_material->GetDrawingMode() & RAS_IRasterizer::RAS_RENDER_3DPOLYGON_TEXT) { - // for text drawing using faces + // for text drawing using faces rasty->IndexPrimitives_3DText(ms, m_material); } + else if (m_material->IsText()) { + rasty->IndexPrimitivesText(ms); + } else { rasty->IndexPrimitives(ms); } @@ -246,13 +249,13 @@ void RAS_MaterialBucket::SetMeshUnmodified() } } -RAS_DisplayArrayBucket *RAS_MaterialBucket::FindDisplayArrayBucket(RAS_DisplayArray *array) +RAS_DisplayArrayBucket *RAS_MaterialBucket::FindDisplayArrayBucket(RAS_DisplayArray *array, RAS_MeshObject *mesh) { for (RAS_DisplayArrayBucketList::iterator it = m_displayArrayBucketList.begin(), end = m_displayArrayBucketList.end(); it != end; ++it) { RAS_DisplayArrayBucket *displayArrayBucket = *it; - if (displayArrayBucket->GetDisplayArray() == array) { + if (displayArrayBucket->GetDisplayArray() == array && displayArrayBucket->GetMesh() == mesh) { return displayArrayBucket; } } diff --git a/source/gameengine/Rasterizer/RAS_MaterialBucket.h b/source/gameengine/Rasterizer/RAS_MaterialBucket.h index 5d0e8d72244a..e6dcd4394004 100644 --- a/source/gameengine/Rasterizer/RAS_MaterialBucket.h +++ b/source/gameengine/Rasterizer/RAS_MaterialBucket.h @@ -76,7 +76,7 @@ class RAS_MaterialBucket unsigned int GetNumActiveMeshSlots(); /// Find a display array bucket for the given display array. - RAS_DisplayArrayBucket *FindDisplayArrayBucket(RAS_DisplayArray *array); + RAS_DisplayArrayBucket *FindDisplayArrayBucket(RAS_DisplayArray *array, RAS_MeshObject *mesh); void AddDisplayArrayBucket(RAS_DisplayArrayBucket *bucket); void RemoveDisplayArrayBucket(RAS_DisplayArrayBucket *bucket); diff --git a/source/gameengine/Rasterizer/RAS_MeshSlot.cpp b/source/gameengine/Rasterizer/RAS_MeshSlot.cpp index bce2d3643376..891db3be5642 100644 --- a/source/gameengine/Rasterizer/RAS_MeshSlot.cpp +++ b/source/gameengine/Rasterizer/RAS_MeshSlot.cpp @@ -132,7 +132,7 @@ void RAS_MeshSlot::SetDeformer(RAS_Deformer *deformer) else { // the deformer is not using vertex array (Modifier), release them m_displayArrayBucket->Release(); - m_displayArrayBucket = m_bucket->FindDisplayArrayBucket(NULL); + m_displayArrayBucket = m_bucket->FindDisplayArrayBucket(NULL, m_mesh); if (m_displayArrayBucket) { m_displayArrayBucket->AddRef(); } diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp index 5230aa36d4e0..8d54dff4870e 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp @@ -42,6 +42,7 @@ #include "RAS_TexVert.h" #include "RAS_MeshObject.h" #include "RAS_MeshUser.h" +#include "RAS_TextUser.h" #include "RAS_Polygon.h" #include "RAS_DisplayArray.h" #include "RAS_ILightObject.h" @@ -873,6 +874,31 @@ bool RAS_OpenGLRasterizer::UseDisplayLists() const return m_storageInfo & RAS_STORAGE_USE_DISPLAY_LIST; } +void RAS_OpenGLRasterizer::IndexPrimitivesText(RAS_MeshSlot *ms) +{ + RAS_TextUser *textUser = (RAS_TextUser *)ms->m_meshUser; + + float mat[16]; + memcpy(mat, textUser->GetMatrix(), sizeof(float) * 16); + + const MT_Vector3& spacing = textUser->GetSpacing(); + const MT_Vector3& offset = textUser->GetOffset(); + + mat[12] += offset[0]; + mat[13] += offset[1]; + mat[14] += offset[2]; + + for (unsigned short int i = 0, size = textUser->GetTexts().size(); i < size; ++i) { + if (i != 0) { + mat[12] -= spacing[0]; + mat[13] -= spacing[1]; + mat[14] -= spacing[2]; + } + RenderText3D(textUser->GetFontId(), textUser->GetTexts()[i], textUser->GetSize(), textUser->GetDpi(), + textUser->GetColor().getValue(), mat, textUser->GetAspect()); + } +} + void RAS_OpenGLRasterizer::IndexPrimitives_3DText(RAS_MeshSlot *ms, class RAS_IPolyMaterial *polymat) { bool obcolor = polymat->UsesObjectColor(); diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h index 604c92fbbf06..1f6f9ff0e031 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h @@ -202,6 +202,7 @@ class RAS_OpenGLRasterizer : public RAS_IRasterizer virtual void IndexPrimitives(class RAS_MeshSlot *ms); virtual void IndexPrimitivesInstancing(RAS_DisplayArrayBucket *arrayBucket); virtual void IndexPrimitives_3DText(class RAS_MeshSlot *ms, class RAS_IPolyMaterial *polymat); + virtual void IndexPrimitivesText(RAS_MeshSlot *ms); virtual void DrawDerivedMesh(class RAS_MeshSlot *ms); virtual void SetProjectionMatrix(MT_CmMatrix4x4 &mat); diff --git a/source/gameengine/Rasterizer/RAS_TextUser.cpp b/source/gameengine/Rasterizer/RAS_TextUser.cpp new file mode 100644 index 000000000000..61875394116d --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_TextUser.cpp @@ -0,0 +1,115 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is: all of this file. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file RAS_TextUser.cpp + * \ingroup bgerast + */ + +#include "RAS_TextUser.h" +#include "RAS_DisplayArrayBucket.h" + +RAS_TextUser::RAS_TextUser(void *clientobj) + :RAS_MeshUser(clientobj), + m_fontid(0), + m_size(0), + m_dpi(0), + m_aspect(0.0f), + m_offset(MT_Vector3(0.0f, 0.0f, 0.0f)), + m_spacing(MT_Vector3(0.0f, 0.0f, 0.0f)) +{ +} + +RAS_TextUser::~RAS_TextUser() +{ +} + +int RAS_TextUser::GetFontId() const +{ + return m_fontid; +} + +int RAS_TextUser::GetSize() const +{ + return m_size; +} + +int RAS_TextUser::GetDpi() const +{ + return m_dpi; +} + +float RAS_TextUser::GetAspect() const +{ + return m_aspect; +} + +const MT_Vector3& RAS_TextUser::GetOffset() const +{ + return m_offset; +} + +const MT_Vector3& RAS_TextUser::GetSpacing() const +{ + return m_spacing; +} + +const std::vector& RAS_TextUser::GetTexts() const +{ + return m_texts; +} + +void RAS_TextUser::SetFontId(int fontid) +{ + m_fontid = fontid; +} + +void RAS_TextUser::SetSize(int size) +{ + m_size = size; +} + +void RAS_TextUser::SetDpi(int dpi) +{ + m_dpi = dpi; +} + +void RAS_TextUser::SetAspect(float aspect) +{ + m_aspect = aspect; +} + +void RAS_TextUser::SetOffset(const MT_Vector3& offset) +{ + m_offset = offset; +} + +void RAS_TextUser::SetSpacing(const MT_Vector3& spacing) +{ + m_spacing = spacing; +} + +void RAS_TextUser::SetTexts(const std::vector& texts) +{ + m_texts = texts; +} diff --git a/source/gameengine/Rasterizer/RAS_TextUser.h b/source/gameengine/Rasterizer/RAS_TextUser.h new file mode 100644 index 000000000000..b49cb99b8ca9 --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_TextUser.h @@ -0,0 +1,69 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is: all of this file. + * + * Contributor(s): Porteries Tristan. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file RAS_TextUser.h + * \ingroup bgerast + */ + +#ifndef __RAS_TEXT_USER_H__ +#define __RAS_TEXT_USER_H__ + +#include "RAS_MeshUser.h" + +#include "STR_String.h" + +class RAS_TextUser : public RAS_MeshUser +{ +private: + std::vector m_texts; + int m_fontid; + int m_size; + int m_dpi; + float m_aspect; + float m_resolution; + MT_Vector3 m_offset; + MT_Vector3 m_spacing; + +public: + RAS_TextUser(void *clientobj); + virtual ~RAS_TextUser(); + + int GetFontId() const; + int GetSize() const; + int GetDpi() const; + float GetAspect() const; + const MT_Vector3& GetOffset() const; + const MT_Vector3& GetSpacing() const; + const std::vector& GetTexts() const; + + void SetFontId(int fontid); + void SetSize(int size); + void SetDpi(int dpi); + void SetAspect(float aspect); + void SetOffset(const MT_Vector3& offset); + void SetSpacing(const MT_Vector3& spacing); + void SetTexts(const std::vector& texts); +}; + +#endif // __RAS_TEXT_USER_H__ diff --git a/source/gameengine/VideoTexture/ImageRender.cpp b/source/gameengine/VideoTexture/ImageRender.cpp index 1d246d56e10a..c1c9a9193a4d 100644 --- a/source/gameengine/VideoTexture/ImageRender.cpp +++ b/source/gameengine/VideoTexture/ImageRender.cpp @@ -398,8 +398,6 @@ bool ImageRender::Render() m_scene->RenderBuckets(camtrans, m_rasterizer); - m_scene->RenderFonts(); - // restore the canvas area now that the render is completed m_canvas->GetWindowArea() = area; m_canvas->EndFrame();