/////////////////////////////////////////////////////
/////////////////////////////////////////////////////
//
// Draw 3D String
//
/////////////////////////////////////////////////////
/////////////////////////////////////////////////////
#include "CKAll.h"
#include "CKFontManager.h"
#define CKPGUID_ALIGNMENT CKGUID(0x2e1e2209,0x47da44b5)
#define CKPGUID_TEXTPROPERTIES CKGUID(0x4157001d,0x4cc82922)
CKObjectDeclaration *FillBehaviorText2DDecl();
CKERROR CreateText2DProto(CKBehaviorPrototype **);
int Text2D(const CKBehaviorContext& behcontext);
CKERROR TextCallback(const CKBehaviorContext& behcontext);
CKBOOL Text2DRenderCallback(CKRenderContext *context,CKRenderObject* ent,void *Argument);
CKObjectDeclaration *FillBehaviorText2DDecl()
{
CKObjectDeclaration *od = CreateCKObjectDeclaration("2D Text");
od->SetDescription("Display a text on a 2D 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:
- Screen Proportionnal: Enable this option if the text must be proportionnal of the screen size. Else, the size is fixed.
- Background: Enable this to display a background material behind the text, using the extents of the text.
- Clip To Dimension: Enable this to clip the text to the frame extents.
- Resize Verticaly: Enable this to resize the frame according to the text height.
- Resize Horizontaly: Enable this to resize the frame according to the text width. Works only with no wrapping and no justification.
- WordWrap: Enables the word wrapping of the text (automatically put a word to the next line when it doesn't fit in the frame.)
- Justified: Extension of the wrapping : words not fitting are sent to the next line and the spaces of the line are stretched for the
line to fit exactly the frame width. These two options are incompatible with the Resize Horizontaly option.
- Compiled: Enable this to compile the graphic data of the text, for more efficiency, if you know the string won't change
after the first display.
- Multiple: Transforms the behavior in an In-Out building block, allowing you to draw several text on several frames with a single
building block. Typically you can use this with an Array containing a text and a position, then with an Array Iterator, move the
frame to the stored position then display the text, and so on for each line of the array, all of this in one behavioral frame.
- Show Caret: Enable this if you want the caret to be displayed, when there is one.
*/
od->SetType( CKDLL_BEHAVIORPROTOTYPE);
od->SetGuid(CKGUID(0x55b29fe,0x662d5ca0));
od->SetAuthorGuid(VIRTOOLS_GUID);
od->SetAuthorName("Virtools");
od->SetVersion(0x00020000);
od->SetCreationFunction(CreateText2DProto);
od->SetCompatibleClassId(CKCID_2DENTITY);
od->SetCategory("Interface/Text");
return od;
}
CKERROR CreateText2DProto(CKBehaviorPrototype **pproto)
{
CKBehaviorPrototype *proto = CreateCKBehaviorPrototype("2D 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(Text2D);
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 Text2D(const CKBehaviorContext& behcontext)
{
CKBehavior* beh = behcontext.Behavior;
CKContext* ctx = behcontext.Context;
CK2dEntity* ent = (CK2dEntity*)beh->GetTarget();
if(beh->IsInputActive(1)) { // we enter by off
beh->ActivateInput(1, FALSE);
beh->ActivateOutput(1);
return CKBR_OK;
}
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) Text2DRenderCallback(behcontext.CurrentRenderContext, ent, (void*)beh->GetID());
return CKBR_OK;
}
}
// we add the render callback (temporarily)
if (ent) ent->AddPostRenderCallBack(Text2DRenderCallback,(void *)beh->GetID(),TRUE);
return CKBR_ACTIVATENEXTFRAME;
}
CKBOOL
Text2DRenderCallback(CKRenderContext *dev,CKRenderObject* obj,void *Argument)
{
CKBehavior* beh = (CKBehavior*)CKGetObject(dev->GetCKContext(),(CK_ID)Argument);
if (!beh) return TRUE;
CK2dEntity* ent = (CK2dEntity *)obj;
CKContext* ctx = beh->GetCKContext();
CKFontManager* fm = (CKFontManager*)ctx->GetManagerByGuid(FONT_MANAGER_GUID);
// 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 TRUE;
// We get the string
CKSTRING string = (CKSTRING)beh->GetInputParameterReadDataPtr(1);
if(!string) return 0;
// We get the alignment
int align = 0;
beh->GetInputParameterValue(2,&align);
// Margins
VxRect margins(2,2,2,2);
beh->GetInputParameterValue(3,&margins);
font->m_Margins = margins;
// Scroll Offset
Vx2DVector offset(0.0f,0.0f);
beh->GetInputParameterValue(4,&offset);
font->m_Offset = offset;
// Paragraph indentation
Vx2DVector pindent;
beh->GetInputParameterValue(5,&pindent);
font->m_ParagraphIndentation = pindent;
// Caret parameters
beh->GetInputParameterValue(7,&font->m_CaretSize);
font->m_CaretMaterial = (CKMaterial*)beh->GetInputParameterObject(8);
int textflags = 0;
beh->GetLocalParameterValue(0,&textflags);
// we iterate on the string
char* currentline = string;
///
// 2D Entity extents
VxRect destrect;
ent->GetRect(destrect);
if (ent->IsRatioOffset()) {
VxRect screen;
dev->GetViewRect(screen);
destrect.Translate(screen.GetTopLeft());
}
CKDWORD oldFog = dev->GetState(VXRENDERSTATE_FOGENABLE);
dev->SetState(VXRENDERSTATE_FOGENABLE,FALSE);
VxRect textzone = destrect;
// Screen Clipping
if (ent->IsClippedToCamera()) {
textflags |= TEXT_SCREENCLIP;
dev->GetViewRect(font->m_ClippingRect);
}
// Parent Clipping
if (ent->GetFlags() & CK_2DENTITY_CLIPTOPARENT) {
if (CK2dEntity* parent = ent->GetParent()) {
VxRect dummy;
if (textflags & TEXT_SCREENCLIP) { // Already clipped by screen
VxRect rect;
parent->GetExtents(dummy,rect);
rect.Clip(font->m_ClippingRect);
font->m_ClippingRect = rect;
} else {
textflags |= TEXT_SCREENCLIP;
parent->GetExtents(dummy,font->m_ClippingRect);
}
}
}
CKMaterial* mat = (CKMaterial*)beh->GetInputParameterObject(6);
if(textflags & TEXT_MULTIPLE) {
if(ent->IsVisible())
fm->DrawText(ent->GetID(), fontindex, string, font->m_Scale, font->m_StartColor, font->m_EndColor, align, textzone, mat, textflags);
}
else {
///
// Clipping : necessary because i m being clipped to the camera otherwise!!!
VxRect oldclip;
CKBOOL isnotclippedtocamera = !ent->IsClippedToCamera();
if (isnotclippedtocamera) {
dev->GetViewRect(oldclip);
VxRect clip = oldclip;
dev->GetWindowRect(clip);
clip.Translate(-clip.GetTopLeft());
dev->SetViewRect(clip);
}
// TODO : n'afficher que ce qui rentre dans le clipping actuel
font->DrawCKText(dev,ent,string,align,textzone,mat,textflags,TRUE);
// Clipping
if (isnotclippedtocamera) {
dev->SetViewRect(oldclip);
}
// We write the text extents
beh->SetOutputParameterValue(0,&font->m_TextExtents);
beh->SetOutputParameterValue(1, &font->m_LineCount);
if (dev->GetFogMode()!=VXFOG_NONE)
dev->SetState(VXRENDERSTATE_FOGENABLE , TRUE);
}
// Reenable Fog (if necessary)
dev->SetState(VXRENDERSTATE_FOGENABLE,oldFog);
return TRUE;
}