Index: src/common/effects/pseffectobjlabel.h =================================================================== --- src/common/effects/pseffectobjlabel.h (revision 0) +++ src/common/effects/pseffectobjlabel.h (revision 436) @@ -0,0 +1,82 @@ +/* + * Author: Roland Schulz + * + * Copyright (C) 2007 Atomic Blue (info@planeshift.it, http://www.atomicblue.org) + * + * + * 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 (version 2 of the License) + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef PS_EFFECT_OBJ_LABEL_HEADER +#define PS_EFFECT_OBJ_LABEL_HEADER + +#include "pseffectobj.h" +#include +#include +#include "pseffectobjtextable.h" + +struct iGraphics3D; +struct iGraphics2D; +struct iTextureManager; +struct iTextureWrapper; +struct iFont; +struct iParticle; +class psEffect2DRenderer; + +class psEffectObjLabel : public psEffectObj, public psEffectObjTextable +{ +private: + // needed managers + csRef txtmgr; + csRef facState; + csRef genState; + + // font + csString sizeFileName; + csArray xpos; + csArray ypos; + csArray width; + +public: + psEffectObjLabel(iView *parentView, psEffect2DRenderer * renderer2d); + virtual ~psEffectObjLabel(); + + /** Creates a material that will fit an array of text elements and draws those elements. + */ + virtual bool SetText(const csArray & elements); + virtual bool SetText(const csArray & rows); + virtual bool SetText(int rows, ...); + + bool Load(iDocumentNode * node); + void LoadGlyphs(csString name); + psEffectObj * Clone() const; + // inherited function overloads + virtual bool Render(const csVector3 &up); + virtual bool Update(csTicks elapsed); + virtual void CloneBase(psEffectObj * newObj) const; + +protected: + /** performs the post setup (after the effect obj has been loaded). + * Things like create mesh factory, etc are initialized here. + */ + bool PostSetup(); + + void DrawTextElement(const psEffectTextElement & element); + + /** Creates a mesh factory for this quad. + */ + virtual bool CreateMeshFact(); + +}; + +#endif Index: src/common/effects/pseffect.cpp =================================================================== --- src/common/effects/pseffect.cpp (revision 435) +++ src/common/effects/pseffect.cpp (revision 436) @@ -45,6 +45,7 @@ #include "pseffectobjtrail.h" #include "pseffectobjdecal.h" #include "pseffectobjtext2d.h" +#include "pseffectobjlabel.h" #include "util/log.h" #include "util/pscssetup.h" @@ -184,6 +185,10 @@ { obj = new psEffectObjText(parentView, renderer2d); } + else if (type == "label") + { + obj = new psEffectObjLabel(parentView, renderer2d); + } else if (type == "trail") { obj = new psEffectObjTrail(parentView, renderer2d); Index: src/common/effects/pseffectobjlabel.cpp =================================================================== --- src/common/effects/pseffectobjlabel.cpp (revision 0) +++ src/common/effects/pseffectobjlabel.cpp (revision 436) @@ -0,0 +1,436 @@ +/* +* Author: Roland Schulz +* +* Copyright (C) 2007 Atomic Blue (info@planeshift.it, http://www.atomicblue.org) +* +* +* 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 (version 2 of the License) +* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +* +*/ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "effects/pseffectobjlabel.h" +#include "effects/pseffectanchor.h" +#include "effects/pseffect2drenderer.h" + +#include "util/log.h" +#include "util/pscssetup.h" + +#define NUM_GLYPHS 256 + +psEffectObjLabel::psEffectObjLabel(iView * parentView, psEffect2DRenderer * renderer2d) + : psEffectObj(parentView, renderer2d) +{ + meshFact = 0; + xpos.SetSize(NUM_GLYPHS,0); + ypos.SetSize(NUM_GLYPHS,0); + width.SetSize(NUM_GLYPHS,64); + for(int i=0; i<256; i++) + { + xpos[i] = (i%16) * 64; + ypos[i] = (i/16-2) * 64; + } +} + +psEffectObjLabel::~psEffectObjLabel() +{ + if( meshFact ) + { + engine->RemoveObject(meshFact); + } + if( mesh ) + { + engine->RemoveObject(mesh); + } + +} + +bool psEffectObjLabel::Load(iDocumentNode *node) +{ + // get the attributes + name = ""; + materialName = ""; + csRef attribIter = node->GetAttributes(); + while (attribIter->HasNext()) + { + csRef attr = attribIter->Next(); + csString attrName = attr->GetName(); + + attrName.Downcase(); + if (attrName == "name") + name = attr->GetValue(); + else if (attrName == "material") + materialName = attr->GetValue(); + else if (attrName == "sizefile") + sizeFileName = attr->GetValue(); + } + if (name == "") + { + csReport(psCSSetup::object_reg, CS_REPORTER_SEVERITY_ERROR, "planeshift_effects", "Attempting to create an effect obj with no name.\n"); + return false; + } + if (materialName == "") + { + csReport(psCSSetup::object_reg, CS_REPORTER_SEVERITY_ERROR, "planeshift_effects", "Attempting to create an effect obj with no material.\n"); + return false; + } + if (sizeFileName == "") + { + LoadGlyphs(sizeFileName); + } + + if (!psEffectObj::Load(node)) + { + return false; + } + return PostSetup(); +} + + +void psEffectObjLabel::LoadGlyphs(csString filename) +{ + csRef vfs = csQueryRegistry ( psCSSetup::object_reg ); + csRef xml = csQueryRegistry (psCSSetup::object_reg); + csRef doc = xml->CreateDocument(); + csRef buf (vfs->ReadFile (filename)); + if (!buf || !buf->GetSize ()) + { + return ; + } + const char* error = doc->Parse( buf ); + if ( error ) + { + printf("Error loading glyphs file: %s\n", error); + return ; + } + + csRef iter = doc->GetRoot()->GetNode("glyphs")->GetNodes(); + int number; + + while ( iter->HasNext() ) + { + csRef child = iter->Next(); + + if ( child->GetType() != CS_NODE_ELEMENT ) + continue; + sscanf(child->GetValue(), "glyph%d", &number); + if (number < 0 || number >= NUM_GLYPHS) + continue; + width[number] = child->GetAttributeValueAsInt("width"); + xpos[number] = child->GetAttributeValueAsInt("x"); + ypos[number] = child->GetAttributeValueAsInt("y"); + } +} + + +bool psEffectObjLabel::PostSetup() +{ +// if (!CreateMeshFact()) +// return false; + + return true; +} + +bool psEffectObjLabel::CreateMeshFact() +{ + static unsigned int uniqueID = 0; + csString facName = "effect_label_fac_"; + facName += uniqueID++; + + meshFact = engine->CreateMeshFactory ("crystalspace.mesh.object.genmesh", facName.GetData()); + region->Add(meshFact->QueryObject()); + + iMeshObjectFactory * fact = meshFact->GetMeshObjectFactory(); + facState = scfQueryInterface (fact); + if (!facState) + { + csReport(psCSSetup::object_reg, CS_REPORTER_SEVERITY_ERROR, "planeshift_effects", "Couldn't create genmesh: %s\n", name.GetData()); + return false; + } + + // setup the material + csRef mat = region->FindMaterial(materialName); + if (mat) + { + fact->SetMaterialWrapper(mat); + } else { + csReport(psCSSetup::object_reg, CS_REPORTER_SEVERITY_ERROR, "planeshift_effects", "No material for label mesh: %s\n", materialName.GetData()); + } + +#if 0 + facState->SetVertexCount(4); + + // we have to set the vertices so that the quad actually gets rendered + facState->GetVertices()[0].Set( 0.5f, 0, 0.5f); + facState->GetVertices()[1].Set(-0.5f, 0, 0.5f); + facState->GetVertices()[2].Set(-0.5f, 0, -0.5f); + facState->GetVertices()[3].Set( 0.5f, 0, -0.5f); + facState->GetTexels()[0].Set(5.0/8,4.0/16); + facState->GetTexels()[1].Set(4.0/8,4.0/16); + facState->GetTexels()[2].Set(4.0/8,5.0/16); + facState->GetTexels()[3].Set(5.0/8,5.0/16); + facState->GetNormals()[0].Set(0,1,0); + facState->GetNormals()[1].Set(0,1,0); + facState->GetNormals()[2].Set(0,1,0); + facState->GetNormals()[3].Set(0,1,0); + + facState->SetTriangleCount(4); + + facState->GetTriangles()[0].Set(0, 2, 1); + facState->GetTriangles()[1].Set(0, 2, 3); + facState->GetTriangles()[2].Set(2, 0, 1); + facState->GetTriangles()[3].Set(2, 0, 3); +#endif + return true; +} + + +bool psEffectObjLabel::Render(const csVector3 &up) +{ + if(!CreateMeshFact()) + return false; + + objUp = up; + + static unsigned long nextUniqueID = 0; + csString effectID = "effect_label_"; + effectID += nextUniqueID++; + + // create a mesh wrapper from the factory we just created + mesh = engine->CreateMeshWrapper(meshFact, effectID.GetData()); + if (!mesh) + { + csReport(psCSSetup::object_reg, CS_REPORTER_SEVERITY_ERROR, "planeshift_effects", "Couldn't create meshwrapper in label effect\n"); + return false; + } + + // do the up vector +// csReversibleTransform rt; +// rt.LookAt(csVector3(up.x, up.z, up.y), csVector3(0,2,1)); +// matUp = rt.GetT2O(); +// matBase = matUp; + + // common flags + mesh->GetFlags().Set(CS_ENTITY_NOHITBEAM); + mesh->GetFlags().Set(CS_ENTITY_NODECAL); + // we can have labels overlay geometry, or we can have them be occluded by it like normal objects + //priority = engine->GetAlphaRenderPriority(); + // zFunc = CS_ZBUF_NONE; + priority = engine->GetObjectRenderPriority(); + zFunc = CS_ZBUF_USE; + mixmode = CS_FX_COPY; + //printf("zbufmode: %d pri: %d mixmode: %d\n", zFunc, priority, mixmode); + mesh->SetZBufMode(zFunc); + mesh->SetRenderPriority(priority); + + // disable culling + csRef globalStringSet = csQueryRegistryTagInterface + (psCSSetup::object_reg, "crystalspace.shared.stringset"); + csStringID viscull_id = globalStringSet->Request ("viscull"); + mesh->GetMeshObject()->GetObjectModel()->SetTriangleData(viscull_id, 0); + + genState = scfQueryInterface (mesh->GetMeshObject()); + genState->SetLighting(false); + + // obj specific + + if (mixmode != CS_FX_ALPHA) + mesh->GetMeshObject()->SetMixMode(mixmode); // to check + // genState->SetMixMode(mixmode); //was not working with latest CS + + return true; +} + +bool psEffectObjLabel::Update(csTicks elapsed) +{ + if (!anchor || !anchor->IsReady()) // wait for anchor to be ready + return true; + + if (!psEffectObj::Update(elapsed)) + return false; + + return true; +} + +void psEffectObjLabel::CloneBase(psEffectObj * newObj) const +{ + psEffectObj::CloneBase(newObj); + + psEffectObjLabel * newLabelObj = dynamic_cast(newObj); + + newLabelObj->materialName = materialName; +} + +psEffectObj * psEffectObjLabel::Clone() const +{ + psEffectObjLabel * newObj = new psEffectObjLabel(view, renderer2d); + CloneBase(newObj); + + return newObj; +} + +bool psEffectObjLabel::SetText(const csArray & elements) +{ + printf("settext not supported\n"); + return false; +} + +bool psEffectObjLabel::SetText(const csArray & rows) +{ + printf("settext not supported\n"); + return false; +} + +bool psEffectObjLabel::SetText(int rows, ...) +{ + size_t lettercount = 0; + + static csArray elemBuffer; + psEffectTextElement newElem; + psEffectTextRow * row = 0; + int y = 0; + + // calculate dimensions of text area + int maxWidth = 0; + int maxHeight = 0; + + elemBuffer.Empty(); + + va_list arg; + va_start(arg, rows); + + // Loop through all rows + for (int a=0; acolour; + newElem.hasOutline = row->hasOutline; + newElem.hasShadow = row->hasShadow; + newElem.shadowColour = row->shadowColour; + newElem.outlineColour = row->outlineColour; + newElem.text = row->text; + newElem.align = row->align; + newElem.width = 0; + for(uint b=0; bGetDimensions(newElem.text, newElem.width, newElem.height); + newElem.height = 64; + newElem.x = 0; + newElem.y = y; + elemBuffer.Push(newElem); + y += newElem.height; + lettercount += newElem.text.Length(); + + int right = newElem.x + newElem.width; + int bottom = newElem.y + newElem.height; + + if (right > maxWidth) + maxWidth = right; + if (bottom > maxHeight) + maxHeight = bottom; + } + va_end(arg); + + CS_ASSERT(facState!=0); + iMeshObjectFactory * fact = meshFact->GetMeshObjectFactory(); + int mw,mh; + fact->GetMaterialWrapper()->GetMaterial()->GetTexture()->GetOriginalDimensions(mw, mh); + + facState->SetVertexCount( lettercount * 4 ); + facState->SetTriangleCount( lettercount * 2 ); + + size_t elementCount = elemBuffer.GetSize(); + int cp = 0; + + for(size_t i=0; iGetVertices()[cp ].Set(fx2,0,fy1); + facState->GetVertices()[cp+1].Set(fx1,0,fy1); + facState->GetVertices()[cp+2].Set(fx1,0,fy2); + facState->GetVertices()[cp+3].Set(fx2,0,fy2); + // texture is assumed to be 8x8, each cell 64x64 + float fracx1 = (float)xpos[c] / mw; + float fracy1 = (float)ypos[c] / mh; + float fracx2 = (float)(xpos[c]+width[c]) / mw; + float fracy2 = (float)(ypos[c]+64) / mh; + //printf("texels %c %d,%d - %f %f %f %f\n", text[j], xpos[c], ypos[c], fracx1, fracy1, fracx2, fracy2); + facState->GetTexels()[cp ].Set( fracx2, fracy2 ); + facState->GetTexels()[cp+1].Set( fracx1, fracy2 ); + facState->GetTexels()[cp+2].Set( fracx1, fracy1 ); + facState->GetTexels()[cp+3].Set( fracx2, fracy1 ); + facState->GetNormals()[0].Set(0,1,0); + facState->GetNormals()[1].Set(0,1,0); + facState->GetNormals()[2].Set(0,1,0); + facState->GetNormals()[3].Set(0,1,0); + //facState->GetTriangles()[(cp/2) ].Set( cp , cp+2, cp+1); + facState->GetTriangles()[(cp/2) ].Set( cp , cp+2, cp+3); + facState->GetTriangles()[(cp/2)+1].Set( cp+2, cp , cp+1); + //facState->GetTriangles()[cp+3].Set( cp+2, cp , cp+3); + cp += 4; + x += 64; + } + csColor color((float)((newElem.colour>>16) & 255)/255.0F, + (float)((newElem.colour>> 8) & 255)/255.0F, + (float)((newElem.colour ) & 255)/255.0F); + mesh->GetMeshObject()->SetColor(color); + } +// facState->CalculateNormals(); +// facState->SetColor(csColor(1.0,1.0,1.0)); +// facState->SetLighting(false); +// fact->SetMixMode(CS_FX_ADD); +// Render2(objUp); + return true; +} Index: data/effects/misc/labelfontglyphs.xml =================================================================== --- data/effects/misc/labelfontglyphs.xml (revision 0) +++ data/effects/misc/labelfontglyphs.xml (revision 436) @@ -0,0 +1,3 @@ + + + Index: data/effects/misc/label.eff =================================================================== --- data/effects/misc/label.eff (revision 0) +++ data/effects/misc/label.eff (revision 436) @@ -0,0 +1,28 @@ + + + + + /this/art/effects/character_set_myriad.dds + + + + + + labelfonttable + + + + + + none + + + alpha + pos + none + billboard + + + + Index: src/client/entitylabels.h =================================================================== --- src/client/entitylabels.h (revision 447) +++ src/client/entitylabels.h (working copy) @@ -138,9 +138,9 @@ void CreateLabelOfObject( GEMClientObject* object ); /** - * Shows or hides label of given entity (only sets visibility, doesn't create/destruct it) - * This is used when visibility mode is OnMouseOver - labels are created for all entities, - * but only one is set visible (or none at all). + * Shows or hides label of given entity, and creates the label if it does not exist + * and needs to be shown, this is used for the mouseover setting, to create + * labels just before they are viewed for the first time */ void ShowLabelOfObject( GEMClientObject* object, bool show ); Index: src/client/entitylabels.cpp =================================================================== --- src/client/entitylabels.cpp (revision 447) +++ src/client/entitylabels.cpp (working copy) @@ -224,8 +224,7 @@ csString guild( actor->GetGuildName() ); csString guild2( psengine->GetGuildName() ); - if ( guild.Length() ) - if ( guild.Length() ) + if ( guild2.Length() && guild.Length() == guild2.Length() ) { // If same guild, indicate with color if (guild == guild2) @@ -276,6 +275,19 @@ void psEntityLabels::CreateLabelOfObject(GEMClientObject *object) { + if (!object) + { + Debug1( LOG_ANY, 0, "NULL object passed to psEntityLabels::CreateLabelOfObject" ); + return; + } + + // Don't make labels for the player or action locations + if (object->GetEntity() == celClient->GetMainActor() || object->GetObjectType() == GEM_ACTION_LOC) + return; + + psEffectManager* effectMgr = psengine->GetEffectManager(); + CS_ASSERT_MSG("Effects Manager must exist before loading entity labels!", effectMgr ); + iMeshWrapper* mesh = object->pcmesh->GetMesh(); // Has it got a mesh to attach to? @@ -285,16 +297,13 @@ // Get the height of the model const csBox3& boundBox = mesh->GetMeshObject()->GetObjectModel()->GetObjectBoundingBox(); - psEffectManager* effectMgr = psengine->GetEffectManager(); - // Create the effect - unsigned int id = effectMgr->RenderEffect( "entitylabel", + unsigned int id = effectMgr->RenderEffect( "label", csVector3(0.0f,boundBox.Max(1) + 0.25f,0.0f), mesh ); psEffect* effect = effectMgr->FindEffect(id); object->SetEntityLabel(effect); - effectMgr->ShowEffect(id,false); // Hide until told to show // Update text SetObjectText(object); @@ -315,21 +324,10 @@ void psEntityLabels::OnObjectArrived( GEMClientObject* object ) { - CS_ASSERT_MSG("Effects Manager must exist before loading entity labels!", psengine->GetEffectManager() ); - - if (!object) - { - Debug1( LOG_ANY, 0, "NULL object passed to psEntityLabels::OnObjectArried" ); + if (visibility == LABEL_NEVER || visibility == LABEL_ONMOUSE) return; - } - // Action location? - if (object->GetObjectType() == GEM_ACTION_LOC) - return; - - DeleteLabelOfObject(object); // just to be sure - if ( object->GetEntity() != celClient->GetMainActor() ) - CreateLabelOfObject( object ); + CreateLabelOfObject( object ); } @@ -473,9 +471,20 @@ inline void psEntityLabels::ShowLabelOfObject(GEMClientObject* object, bool show) { - psEffect* effect = object->GetEntityLabel(); - if (effect != NULL) - psengine->GetEffectManager()->ShowEffect(effect->GetUniqueID(),show); + if (object->GetEntityLabel() == NULL) + { + // If the label is not created, don't bother creating and hiding it, it won't be visible + if (!show) + return; + + CreateLabelOfObject(object); + } + + psEffect* entityLabel = object->GetEntityLabel(); + if (entityLabel != NULL) + { + psengine->GetEffectManager()->ShowEffect(entityLabel->GetUniqueID(),show); + } } void psEntityLabels::RepaintAllLabels() Index: src/client/psengine.cpp =================================================================== --- src/client/psengine.cpp (revision 447) +++ src/client/psengine.cpp (working copy) @@ -826,8 +826,10 @@ { UnmuteAllSounds(); } - if (IsGameLoaded()) - celclient->GetEntityLabels()->RepaintAllLabels(); + // RS: this causes a freeze switching back to the client window + // for up to a few seconds, and seems very much unnecessary + //if (IsGameLoaded()) + // celclient->GetEntityLabels()->RepaintAllLabels(); } else if (ev.Name == event_focusgained) { @@ -1056,7 +1058,7 @@ { } -inline void psEngine::FinishFrame() +void psEngine::FinishFrame() { g3d->FinishDraw (); g3d->Print (NULL);