///////////////////////////////////////////////////// ///////////////////////////////////////////////////// // // Draw 3D String // ///////////////////////////////////////////////////// ///////////////////////////////////////////////////// #include "CKAll.h" #include "CKFontManager.h" #define CKPGUID_ALIGNMENT CKGUID(0x2e1e2209,0x47da44b5) #define CKPGUID_TEXTPROPERTIES CKGUID(0x4157001d,0x4cc82922) CKObjectDeclaration *FillBehaviorText3DDecl(); CKERROR CreateText3DProto(CKBehaviorPrototype **); int Text3D(const CKBehaviorContext& behcontext); CKERROR TextCallback(const CKBehaviorContext& behcontext); int Text3DRenderCallback(CKRenderContext *dev,CKRenderObject *mov,void *arg); CKObjectDeclaration *FillBehaviorText3DDecl() { CKObjectDeclaration *od = CreateCKObjectDeclaration("3D Text"); od->SetDescription("Display a text on the plane XY of a 3D Frame, using a texture font"); /* rem: On: activates the process.
Off: deactivates the process.

Exit On: is activated if the building block is activated.
Exit Off: is activated if the building block is deactivated.

Font:font created with the building blocks "Create Font" or "Create System Font".
Text:text to be displayed. The text can be multiline.
Alignment:alignement of the text in the frame.
Margins:margins to leave empty in the border of the frame.
Offset:offset at which the text is displayed inside the frame. This offset can be used to make a scrolling inside the frame, thus taking advantage of the frame clipping.
Paragraph Indentation:space to leave horizontally and vertically at each paragraph start (a paragraph begins just after a carriage return).
Background Material:material to be used if a background must be drawn (option "Background" enabled).
Caret Size:size of the caret in percent. The caret is only displayed when using the building blocks "Input String" or "Set Caret Position" and with the option "Show Caret" enabled.
Caret Material:material to be used for the display of the caret.

Text Extents:real extents of the text drawn. Can be used to achieve a scrolling with the Offset parameter.
Line Count:number of text lines displayed.

Text Properties:options of text displaying:

*/ od->SetType( CKDLL_BEHAVIORPROTOTYPE); od->SetGuid(CKGUID(0x1f5b2fe7,0x6d355175)); od->SetAuthorGuid(VIRTOOLS_GUID); od->SetAuthorName("Virtools"); od->SetVersion(0x00020000); od->SetCreationFunction(CreateText3DProto); od->SetCompatibleClassId(CKCID_3DENTITY); od->SetCategory("Interface/Text"); return od; } CKERROR CreateText3DProto(CKBehaviorPrototype **pproto) { CKBehaviorPrototype *proto = CreateCKBehaviorPrototype("3D Text"); if(!proto) return CKERR_OUTOFMEMORY; proto->DeclareInput("On"); proto->DeclareInput("Off"); proto->DeclareOutput("Exit On"); proto->DeclareOutput("Exit Off"); proto->DeclareInParameter("Font",CKPGUID_FONT); proto->DeclareInParameter("Text",CKPGUID_STRING); proto->DeclareInParameter("Alignment",CKPGUID_ALIGNMENT,"Top-Left"); proto->DeclareInParameter("Margins",CKPGUID_RECT,"(2,2),(2,2)"); proto->DeclareInParameter("Offset",CKPGUID_2DVECTOR); proto->DeclareInParameter("Paragraph Indentation",CKPGUID_2DVECTOR); proto->DeclareInParameter("Background Material",CKPGUID_MATERIAL); proto->DeclareInParameter("Caret Size",CKPGUID_PERCENTAGE,"10"); proto->DeclareInParameter("Caret Material",CKPGUID_MATERIAL); proto->DeclareOutParameter("Text Extents",CKPGUID_RECT); proto->DeclareOutParameter("Line Count",CKPGUID_INT); proto->DeclareSetting("Text Properties",CKPGUID_TEXTPROPERTIES); proto->SetFlags(CK_BEHAVIORPROTOTYPE_NORMAL); proto->SetFunction(Text3D); proto->SetBehaviorFlags((CK_BEHAVIOR_FLAGS)(CKBEHAVIOR_INTERNALLYCREATEDINPUTS|CKBEHAVIOR_INTERNALLYCREATEDOUTPUTS|CKBEHAVIOR_INTERNALLYCREATEDINPUTPARAMS|CKBEHAVIOR_INTERNALLYCREATEDOUTPUTPARAMS|CKBEHAVIOR_TARGETABLE)); proto->SetBehaviorCallbackFct( TextCallback ,CKCB_BEHAVIORSETTINGSEDITED|CKCB_BEHAVIORLOAD|CKCB_BEHAVIORCREATE ); *pproto = proto; return CK_OK; } int Text3D(const CKBehaviorContext& behcontext) { CKBehavior* beh = behcontext.Behavior; CKContext* ctx = behcontext.Context; CK3dEntity* ent = (CK3dEntity*)beh->GetTarget(); if(beh->IsInputActive(0)) { beh->ActivateInput(0, FALSE); beh->ActivateOutput(0); int options = 0; beh->GetLocalParameterValue(0, &options); if(options & TEXT_MULTIPLE) { // Only when activated, we set the callback if (ent && ent->IsVisible() && !ent->IsHiddenByParent()) Text3DRenderCallback(behcontext.CurrentRenderContext, ent, (void*)beh->GetID()); return CKBR_OK; } else { if (ent) ent->SetRenderAsTransparent(TRUE); } } if(beh->IsInputActive(1)) { beh->ActivateInput(1, FALSE); beh->ActivateOutput(1); return CKBR_OK; } if (ent && (ent->GetClassID() == CKCID_3DENTITY) && ent->IsAllOutsideFrustrum()) { // if the frame was completly outside last frame VxBbox box; ent->SetBoundingBox(&box); } // we add the render callback (temporarily) if (ent) ent->AddPostRenderCallBack(Text3DRenderCallback,(void *)beh->GetID(),TRUE); return CKBR_ACTIVATENEXTFRAME; } CKERROR TextCallback(const CKBehaviorContext& behcontext) { CKBehavior* beh = behcontext.Behavior; int options = 0; beh->GetLocalParameterValue(0, &options); switch(behcontext.CallbackMessage) { case CKM_BEHAVIORLOAD : case CKM_BEHAVIORCREATE: beh->EnableInputParameter(6,options&TEXT_BACKGROUND); beh->EnableInputParameter(7,options&TEXT_SHOWCARET); beh->EnableInputParameter(8,options&TEXT_SHOWCARET); break; case CKM_BEHAVIORSETTINGSEDITED: { beh->EnableInputParameter(6,options&TEXT_BACKGROUND); beh->EnableInputParameter(7,options&TEXT_SHOWCARET); beh->EnableInputParameter(8,options&TEXT_SHOWCARET); int nbOut = beh->GetOutputCount(); if(options & TEXT_MULTIPLE) { if(nbOut == 2) { beh->DeleteInput(1); beh->DeleteInput(0); beh->DeleteOutput(1); beh->DeleteOutput(0); CKDestroyObject(beh->RemoveOutputParameter(1)); CKDestroyObject(beh->RemoveOutputParameter(0)); beh->CreateInput("In"); beh->CreateOutput("Out"); } } else { if(nbOut == 1) { beh->DeleteInput(0); beh->DeleteOutput(0); beh->CreateInput("On"); beh->CreateInput("Off"); beh->CreateOutput("Exit On"); beh->CreateOutput("Exit Off"); beh->CreateOutputParameter("Text Extents", CKPGUID_RECT); beh->CreateOutputParameter("Line Count", CKPGUID_INT); } } } break; } return CKBR_OK; } int Text3DRenderCallback(CKRenderContext *dev,CKRenderObject *obj,void *arg) { static const float inv32f = 1.0f / 32.0f; static const float inv16f = 1.0f / 16.0f; CKBehavior* beh = (CKBehavior*)CKGetObject(dev->GetCKContext(),(CK_ID)arg); if (!beh) return TRUE; CK3dEntity* ent = (CK3dEntity *)obj; CKFontManager* fm = (CKFontManager*)beh->GetCKContext()->GetManagerByGuid(FONT_MANAGER_GUID); if (!fm) return 0; // Old version care for space changing fm->m_VersionUpdate = (beh->GetVersion() >= 0x00020000); /// // Input Parameters // We get the texture font int fontindex = 0; beh->GetInputParameterValue(0,&fontindex); CKTextureFont* font = fm->GetFont(fontindex); if (!font) return 0; // We get the string CKSTRING texttodisplay = (CKSTRING)beh->GetInputParameterReadDataPtr(1); if (!texttodisplay) return 0; // We get the alignment int align = 0; beh->GetInputParameterValue(2,&align); // Margins font->m_Margins.SetCorners(2,2,2,2); beh->GetInputParameterValue(3,&font->m_Margins); font->m_Margins *= inv16f; // Scroll Offset font->m_Offset.Set(0.0f,0.0f); beh->GetInputParameterValue(4,&font->m_Offset); // Paragraph indentation font->m_ParagraphIndentation.Set(0.0f,0.0f); beh->GetInputParameterValue(5,&font->m_ParagraphIndentation); // Background Material CKMaterial* material = (CKMaterial*)beh->GetInputParameterObject(6); // Caret parameters beh->GetInputParameterValue(7,&font->m_CaretSize); font->m_CaretMaterial = (CKMaterial*)beh->GetInputParameterObject(8); /// // Settings Parameters // Text flags int textflags = 0; beh->GetLocalParameterValue(0,&textflags); textflags |= TEXT_3D; if (textflags & TEXT_JUSTIFIED) { align &= ~HALIGN_RIGHT; align |= HALIGN_LEFT; } // we calculate the scales of the frame VxVector entscale; ent->GetScale(&entscale,FALSE); VxRect textzone(-entscale.x,-entscale.y,entscale.x,entscale.y); if (CKIsChildClassOf(ent,CKCID_SPRITE3D)) { // the size must be take into account the bounding box of sprite3D const VxBbox& bbox = ent->GetBoundingBox(TRUE); textzone.left = bbox.Min.x*entscale.x; textzone.right = bbox.Max.x*entscale.x; textzone.top = bbox.Min.y*entscale.y; textzone.bottom = bbox.Max.y*entscale.y; } // TODO : n'afficher que ce qui rentre dans le clipping actuel if (textflags & TEXT_MULTIPLE) { // Registering the text for future display fm->DrawText(ent->GetID(), fontindex, texttodisplay, font->m_Scale, font->m_StartColor, font->m_EndColor, align, textzone, material, textflags); } else { // Rendering Now /// // We set the transformation to the 3D Entity (slightly transformed (Y negative)) const VxMatrix& mat = ent->GetWorldMatrix(); VxMatrix resmat = mat; resmat[0] = (mat[0]/entscale.x); resmat[1] = -(mat[1]/entscale.y); resmat[2] = -(mat[2]/entscale.z); dev->SetWorldTransformationMatrix(resmat); // draw the text font->DrawCKText(dev,ent,texttodisplay,align,textzone,material,textflags,TRUE); // we restore the transfo mat dev->SetWorldTransformationMatrix(mat); if (!CKIsChildClassOf(ent,CKCID_SPRITE3D)) { // No modif for the bounding boxes of Sprite 3D VxBbox bbox; bbox.Min.Set(font->m_TextExtents.left, -font->m_TextExtents.bottom,0.0f); bbox.Max.Set(font->m_TextExtents.right, -font->m_TextExtents.top,0.0f); VxVector off(font->m_Offset.x, -font->m_Offset.y, 0.f); bbox.Min += off; bbox.Max += off; bbox.Min /= entscale; bbox.Max /= entscale; if (material) { VxBbox unitbox(1.0f); bbox.Merge(unitbox); } ((CK3dEntity*)ent)->SetBoundingBox(&bbox,TRUE); } // We write the text extents beh->SetOutputParameterValue(0,&(font->m_TextExtents)); beh->SetOutputParameterValue(1,&(font->m_LineCount)); } return 1; }