331 lines
12 KiB
C++
331 lines
12 KiB
C++
/////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////
|
|
//
|
|
// 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:
|
|
<SPAN CLASS=in>On: </SPAN>activates the process.<BR>
|
|
<SPAN CLASS=in>Off: </SPAN>deactivates the process.<BR>
|
|
<BR>
|
|
<SPAN CLASS=out>Exit On: </SPAN>is activated if the building block is activated.<BR>
|
|
<SPAN CLASS=out>Exit Off: </SPAN>is activated if the building block is deactivated.<BR>
|
|
<BR>
|
|
<SPAN CLASS=pin>Font:</SPAN>font created with the building blocks "Create Font" or "Create System Font".<BR>
|
|
<SPAN CLASS=pin>Text:</SPAN>text to be displayed. The text can be multiline.<BR>
|
|
<SPAN CLASS=pin>Alignment:</SPAN>alignement of the text in the frame.<BR>
|
|
<SPAN CLASS=pin>Margins:</SPAN>margins to leave empty in the border of the frame.<BR>
|
|
<SPAN CLASS=pin>Offset:</SPAN>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.<BR>
|
|
<SPAN CLASS=pin>Paragraph Indentation:</SPAN>space to leave horizontally and vertically at each
|
|
paragraph start (a paragraph begins just after a carriage return).<BR>
|
|
<SPAN CLASS=pin>Background Material:</SPAN>material to be used if a background must be drawn (option "Background" enabled).<BR>
|
|
<SPAN CLASS=pin>Caret Size:</SPAN>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.<BR>
|
|
<SPAN CLASS=pin>Caret Material:</SPAN>material to be used for the display of the caret.<BR>
|
|
<BR>
|
|
<SPAN CLASS=pout>Text Extents:</SPAN>real extents of the text drawn. Can be used to achieve a scrolling with
|
|
the <SPAN CLASS=pin>Offset</SPAN> parameter.<BR>
|
|
<SPAN CLASS=pout>Line Count:</SPAN>number of text lines displayed.<BR>
|
|
<BR>
|
|
<SPAN CLASS=setting>Text Properties:</SPAN>options of text displaying:<BR>
|
|
<UL>
|
|
<LI>Screen Proportionnal: Enable this option if the text must be proportionnal of the screen size. Else, the size is fixed.</LI>
|
|
<LI>Background: Enable this to display a background material behind the text, using the extents of the text.</LI>
|
|
<LI>Clip To Dimension: Enable this to clip the text to the frame extents.</LI>
|
|
<LI>Resize Verticaly: Enable this to resize the frame according to the text height.</LI>
|
|
<LI>Resize Horizontaly: Enable this to resize the frame according to the text width. Works only with no wrapping and no justification.</LI>
|
|
<LI>WordWrap: Enables the word wrapping of the text (automatically put a word to the next line when it doesn't fit in the frame.)</LI>
|
|
<LI>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.</LI>
|
|
<LI>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.</LI>
|
|
<LI>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.</LI>
|
|
<LI>Show Caret: Enable this if you want the caret to be displayed, when there is one.</LI>
|
|
</UL>
|
|
<BR>
|
|
*/
|
|
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;
|
|
} |