MovableText write by c#

andyhebear1

26-04-2010 05:31:11

//--------------------------------------
//Rains http://hi.baidu.com/andyhebear
//QQ:233685340
//DateTime:2010-04-26
//Memo:Convert MovableText c++ To C#
//but i am not to test! Hope can help you!
//---------------------------------------
public class MovableText : SimpleRenderable {
const ushort POS_TEX_BINDING = 0;
const ushort COLOUR_BINDING = 1;
const byte UNICODE_NEL = 0x0085; ///< next line
const byte UNICODE_CR = 0x000D; ///< carriage return
const byte UNICODE_LF = 0x000A; ///< line feed
const byte UNICODE_SPACE = 0x0020; ///< space
const byte UNICODE_ZERO = 0x0030; ///< 0
const ushort OGRE_RENDERABLE_DEFAULT_PRIORITY=100;
//******************************** MovableText data ***************************
public enum HorizontalAlignment { H_LEFT, H_CENTER };
public enum VerticalAlignment { V_BELOW, V_ABOVE };

protected string mFontName = "BlueHighway";
protected string mType;//"MovableText"
protected string mName;
protected string mCaption;
protected HorizontalAlignment mHorizontalAlignment;
protected VerticalAlignment mVerticalAlignment;

protected ColourValue mColor = ColourValue.White;
protected RenderOperation mRenderOp;
protected AxisAlignedBox mAABB;
protected LightList mLList;

protected uint mCharHeight = 32;
protected uint mSpaceWidth;

protected bool mNeedUpdate;
protected bool mUpdateColors;
protected bool mOnTop;

protected float mTimeUntilNextToggle;
protected float mRadius;
protected float mAdditionalHeight;

protected Camera mpCam;//*mpCam;
protected RenderWindow mpWin;//*mpWin;
protected Font mpFont;//*mpFont;
protected MaterialPtr mpMaterial;
protected MaterialPtr mpBackgroundMaterial;

//******************************** public methods *****************************
//fontName= "BlueHighway" int charHeight = 32, const ColourValue &color = ColourValue::White
public unsafe MovableText(string name, string caption, string fontName, uint charHeight, ColourValue color) :
base(null) {
//ToDo
this.mName = name;
this.mCaption = caption;
this.mFontName = fontName;
this.mCharHeight = charHeight;
this.mColor = color;
//
if (name == "")
throw new Exception("Trying to create MovableText without name" + "MovableText:MovableText");

if (caption == "")
throw new Exception("Trying to create MovableText without caption" + "MovableText::MovableText");

mRenderOp.vertexData = null;
this.setFontName(mFontName);
this._setupGeometry();
}

~MovableText() {
if (mRenderOp.vertexData != null)
mRenderOp.vertexData.Dispose();
}
public string FontName {
get { return this.mFontName; }
set { this.mFontName = value; }
}

public string Caption {
get { return this.mCaption; }
set { this.mCaption = value; }
}

public ColourValue Color {
get { return this.mColor; }
set { this.mColor = value; }
}

public uint CharacterHeight {
get { return this.mCharHeight; }
set { this.mCharHeight = value; }
}

public uint SpaceWidth {
get { return this.mSpaceWidth; }
set { this.mSpaceWidth = value; }
}

public float AdditionalHeight {
get { return this.mAdditionalHeight; }
set { this.mAdditionalHeight = value; }
}

public bool ShowOnTop {
get { return this.mOnTop; }
set { this.mOnTop = value; }
}
// Set settings
public unsafe void setFontName(string fontName) {
if (MaterialManager.Singleton.ResourceExists(mName + "Material")) {
MaterialManager.Singleton.Remove(mName + "Material");
}
if (mFontName != fontName || mpMaterial == null || mpFont == null) {
mFontName = fontName;
mpFont = (FontPtr)FontManager.Singleton.GetByName(mFontName);
if (mpFont == null) {
throw new Exception("Could not find font " + fontName + "MovableText::setFontName");
mpFont.Load();
//
if (mpMaterial != null) {
MaterialManager.Singleton.Remove(mpMaterial.Name);
mpMaterial.Dispose();
}

mpMaterial = mpFont.GetMaterial().Clone(mName + "Material");
if (!mpMaterial.IsLoaded)
mpMaterial.Load();

mpMaterial.SetDepthCheckEnabled(!mOnTop);
mpMaterial.GetTechnique(0).GetPass(0).SetDepthBias(((!mOnTop)?1f:0f)); //setDepthBias(!mOnTop);
mpMaterial.SetDepthWriteEnabled(mOnTop);
mpMaterial.SetLightingEnabled(false);
mNeedUpdate = true;
}
#region
// if((Ogre::MaterialManager::getSingletonPtr()->resourceExists(mName + "Material")))
//{
// Ogre::MaterialManager::getSingleton().remove(mName + "Material");
//}

//if (mFontName != fontName || mpMaterial.isNull() || !mpFont)
//{
// mFontName = fontName;
// mpFont = (Font *)FontManager::getSingleton().getByName(mFontName).getPointer();
// if (!mpFont)
// Exception(Exception::ERR_ITEM_NOT_FOUND, "Could not find font " + fontName, "MovableText::setFontName");

// mpFont->load();
// if (!mpMaterial.isNull())
// {
// MaterialManager::getSingletonPtr()->remove(mpMaterial->getName());
// mpMaterial.setNull();
// }

// mpMaterial = mpFont->getMaterial()->clone(mName + "Material");
// if (!mpMaterial->isLoaded())
// mpMaterial->load();

// mpMaterial->setDepthCheckEnabled(!mOnTop);
// mpMaterial->getTechnique(0)->getPass(0)->setDepthBias(!mOnTop); //setDepthBias(!mOnTop);
// mpMaterial->setDepthWriteEnabled(mOnTop);
// mpMaterial->setLightingEnabled(false);
// mNeedUpdate = true;
//}
#endregion
}
}
public void setCaption(string caption) {
if (caption != mCaption) {
mCaption = caption;
this.mNeedUpdate = true;
}
}
public void setColor(ColourValue color) {
if (color != mColor) {
mColor = color;
mUpdateColors = true;
}
}
public void setCharacterHeight(uint height) {
if (height != mCharHeight) {
mCharHeight = height;
mNeedUpdate = true;
}
}
public void setSpaceWidth(uint width) {
if (width != mSpaceWidth) {
mSpaceWidth = width;
mNeedUpdate = true;
}
}
public void setTextAlignment(HorizontalAlignment horizontalAlignment, VerticalAlignment verticalAlignment) {
if (mHorizontalAlignment != horizontalAlignment) {
mHorizontalAlignment = horizontalAlignment;
mNeedUpdate = true;
}
if (mVerticalAlignment != verticalAlignment) {
mVerticalAlignment = verticalAlignment;
mNeedUpdate = true;
}
}
public void setAdditionalHeight(float height) {
if (mAdditionalHeight != height) {
mAdditionalHeight = height;
mNeedUpdate = true;
}
}
public void showOnTop(bool show) {
if (mOnTop != show && mpMaterial != null) {
mOnTop = show;
int dep = 1;
if (show)
dep = 0;
mpMaterial.GetTechnique(0).GetPass(0).SetDepthBias(dep);
mpMaterial.SetDepthCheckEnabled(!mOnTop);
mpMaterial.SetDepthWriteEnabled(mOnTop);
}
}

// Get settings
public string getFontName() { return mFontName; }
public string getCaption() { return mCaption; }
public ColourValue getColor() { return mColor; }

public uint getCharacterHeight() { return mCharHeight; }
public uint getSpaceWidth() { return mSpaceWidth; }
public float getAdditionalHeight() { return mAdditionalHeight; }
public bool getShowOnTop() { return mOnTop; }
public AxisAlignedBox GetAABB() { return mAABB; }

//******************************** protected methods and overload *************


// from MovableText, create the object
protected unsafe void _setupGeometry() {

System.Diagnostics.Debug.Assert(mpFont != null);
System.Diagnostics.Debug.Assert(mpMaterial != null);

uint vertexCount = (uint)(mCaption.Length * 6);

if (mRenderOp.vertexData != null) {
// Removed this test as it causes problems when replacing a caption
// of the same size: replacing "Hello" with "hello"
// as well as when changing the text alignment
if (mRenderOp.vertexData.vertexCount != vertexCount) {
mRenderOp.vertexData.Dispose();
mRenderOp.vertexData = null;
mUpdateColors = true;
}
}

if (mRenderOp.vertexData != null)
mRenderOp.vertexData = new VertexData();

mRenderOp.indexData = new IndexData();
mRenderOp.vertexData.vertexStart = 0;
mRenderOp.vertexData.vertexCount = vertexCount;
mRenderOp.operationType = RenderOperation.OperationTypes.OT_TRIANGLE_LIST;
mRenderOp.useIndexes = false;

VertexDeclaration decl = mRenderOp.vertexData.vertexDeclaration;
VertexBufferBinding bind = mRenderOp.vertexData.vertexBufferBinding;
uint offset = 0;

// create/bind positions/tex.ccord. buffer
if (decl.FindElementBySemantic(VertexElementSemantic.VES_POSITION) != null)
decl.AddElement(POS_TEX_BINDING, offset, VertexElementType.VET_FLOAT3, VertexElementSemantic.VES_POSITION);

offset += VertexElement.GetTypeSize(VertexElementType.VET_FLOAT3);

if (decl.FindElementBySemantic(VertexElementSemantic.VES_TEXTURE_COORDINATES) != null)
decl.AddElement(POS_TEX_BINDING, offset, VertexElementType.VET_FLOAT2, VertexElementSemantic.VES_TEXTURE_COORDINATES, 0);

HardwareVertexBufferSharedPtr ptbuf = HardwareBufferManager.Singleton.CreateVertexBuffer(decl.GetVertexSize(POS_TEX_BINDING),
mRenderOp.vertexData.vertexCount,
HardwareBuffer.Usage.HBU_DYNAMIC_WRITE_ONLY);
bind.SetBinding(POS_TEX_BINDING, ptbuf);

//// Colours - store these in a separate buffer because they change less often
if (decl.FindElementBySemantic(VertexElementSemantic.VES_DIFFUSE)!=null)
decl.AddElement(COLOUR_BINDING, 0, VertexElementType.VET_COLOUR, VertexElementSemantic.VES_DIFFUSE);

HardwareVertexBufferSharedPtr cbuf = HardwareBufferManager.Singleton.CreateVertexBuffer(decl.GetVertexSize(COLOUR_BINDING),
mRenderOp.vertexData.vertexCount,
HardwareBuffer.Usage.HBU_DYNAMIC_WRITE_ONLY);
bind.SetBinding(COLOUR_BINDING, cbuf);

int charlen = mCaption.Length;
float* pPCBuff = (float*)(ptbuf.Lock(HardwareBuffer.LockOptions.HBL_DISCARD));

float largestWidth = 0f;
float left = 0f * 2.0f - 1.0f;
float top = -((0f * 2.0f) - 1.0f);

//// Derive space width from a capital A
if (mSpaceWidth == 0)
mSpaceWidth = System.Convert.ToUInt32(mpFont.GetGlyphAspectRatio('A') * mCharHeight * 2.0f);

//// for calculation of AABB
Mogre.Vector3 min=new Vector3(0,0,0), max=new Vector3(0,0,0), currPos;
float maxSquaredRadius=0f;
bool first = true;

//// Use iterator
int i, iend;
iend = mCaption.Length;
bool newLine = true;
float len = 0.0f;

if(mVerticalAlignment ==VerticalAlignment.V_ABOVE)
{
// Raise the first line of the caption
top += mCharHeight;
for (i = 0; i != iend; ++i)
{
if (Caption[i] == '\n')
top += mCharHeight * 2.0f;
}
}

for (i = 0; i != iend; ++i)
{
if (newLine)
{
len = 0.0f;
for (int j = i; j != iend && Caption[j] != '\n'; j++)
{
if (Caption[j] == ' ')
len += mSpaceWidth;
else
len += mpFont.GetGlyphAspectRatio((uint)j) * mCharHeight * 2.0f;
}
newLine = false;
}

if (Caption[i] == '\n') {
left = 0f * 2.0f - 1.0f;
top -= mCharHeight * 2.0f;
newLine = true;
continue;
}

if (Caption[i] == ' ') {
// Just leave a gap, no tris
left += mSpaceWidth;
// Also reduce tri count
mRenderOp.vertexData.vertexCount -= 6;
continue;
}

float horiz_height = mpFont.GetGlyphAspectRatio((uint)i);
float u1, u2, v1, v2;
Mogre.FloatRect rect;
rect = mpFont.GetGlyphTexCoords((uint)i); // (*i, u1, v1, u2, v2);

u1 = rect.left;
v1 = rect.top;
u2 = rect.right;
v2 = rect.bottom;
// each vert is (x, y, z, u, v)
//-------------------------------------------------------------------------------------
// First tri
//
// Upper left
if(mHorizontalAlignment == HorizontalAlignment.H_LEFT)
*pPCBuff++ = left;
else
*pPCBuff++ = left - (len / 2);
*pPCBuff++ = top;
*pPCBuff++ = -1.0f;
*pPCBuff++ = u1;
*pPCBuff++ = v1;

// Deal with bounds
if(mHorizontalAlignment == HorizontalAlignment.H_LEFT)
currPos =new Mogre.Vector3(left, top, -1.0f);
else
currPos =new Vector3(left - (len / 2f), top, -1.0f);
if (first)
{
min = max = currPos;
maxSquaredRadius = currPos.SquaredLength;
first = false;
}
else
{
min.MakeFloor(currPos);
max.MakeCeil(currPos);
maxSquaredRadius = System.Math.Max(maxSquaredRadius, currPos.SquaredLength);
}

top -= mCharHeight * 2.0f;

// Bottom left
if(mHorizontalAlignment == HorizontalAlignment.H_LEFT)
*pPCBuff++ = left;
else
*pPCBuff++ = left - (len / 2);
*pPCBuff++ = top;
*pPCBuff++ = -1.0f;
*pPCBuff++ = u1;
*pPCBuff++ = v2;

// Deal with bounds
if(mHorizontalAlignment == HorizontalAlignment.H_LEFT)
currPos =new Vector3(left, top, -1.0f);
else
currPos =new Vector3(left - (len / 2f), top, -1.0f);
min.MakeFloor(currPos);
max.MakeCeil(currPos);
maxSquaredRadius = System.Math.Max(maxSquaredRadius, currPos.SquaredLength);

top += mCharHeight * 2.0f;
left += horiz_height * mCharHeight * 2.0f;

// Top right
if(mHorizontalAlignment == HorizontalAlignment.H_LEFT)
*pPCBuff++ = left;
else
*pPCBuff++ = left - (len / 2);
*pPCBuff++ = top;
*pPCBuff++ = -1.0f;
*pPCBuff++ = u2;
*pPCBuff++ = v1;
//-------------------------------------------------------------------------------------

// Deal with bounds
if(mHorizontalAlignment == HorizontalAlignment.H_LEFT)
currPos = new Vector3(left, top, -1.0f);
else
currPos = new Vector3(left - (len / 2f), top, -1.0f);
min.MakeFloor(currPos);
max.MakeCeil(currPos);
maxSquaredRadius = System.Math.Max(maxSquaredRadius, currPos.SquaredLength);

//-------------------------------------------------------------------------------------
// Second tri
//
// Top right (again)
if(mHorizontalAlignment == HorizontalAlignment.H_LEFT)
*pPCBuff++ = left;
else
*pPCBuff++ = left - (len / 2f);
*pPCBuff++ = top;
*pPCBuff++ = -1.0f;
*pPCBuff++ = u2;
*pPCBuff++ = v1;

currPos = new Vector3(left, top, -1.0f);
min.MakeFloor(currPos);
max.MakeCeil(currPos);
maxSquaredRadius = System.Math.Max(maxSquaredRadius, currPos.SquaredLength);

top -= mCharHeight * 2.0f;
left -= horiz_height * mCharHeight * 2.0f;

// Bottom left (again)
if(mHorizontalAlignment == HorizontalAlignment.H_LEFT)
*pPCBuff++ = left;
else
*pPCBuff++ = left - (len / 2f);
*pPCBuff++ = top;
*pPCBuff++ = -1.0f;
*pPCBuff++ = u1;
*pPCBuff++ = v2;

currPos =new Vector3(left, top, -1.0f);
min.MakeFloor(currPos);
max.MakeCeil(currPos);
maxSquaredRadius = System.Math.Max(maxSquaredRadius, currPos.SquaredLength);

left += horiz_height * mCharHeight * 2.0f;

// Bottom right
if(mHorizontalAlignment == HorizontalAlignment.H_LEFT)
*pPCBuff++ = left;
else
*pPCBuff++ = left - (len / 2f);
*pPCBuff++ = top;
*pPCBuff++ = -1.0f;
*pPCBuff++ = u2;
*pPCBuff++ = v2;
//-------------------------------------------------------------------------------------

currPos =new Vector3(left, top, -1.0f);
min.MakeFloor(currPos);
max.MakeCeil(currPos);
maxSquaredRadius = System.Math.Max(maxSquaredRadius, currPos.SquaredLength);

// Go back up with top
top += mCharHeight * 2.0f;

float currentWidth = (left + 1)/2 - 0;
if (currentWidth > largestWidth)
largestWidth = currentWidth;
}

// Unlock vertex buffer
ptbuf.Unlock();

// update AABB/Sphere radius
mAABB =new AxisAlignedBox(min, max);
mRadius = Mogre.Math.Sqrt(maxSquaredRadius);

if (mUpdateColors)
this._updateColors();

mNeedUpdate = false;

}
protected unsafe void _updateColors() {
System.Diagnostics.Debug.Assert(mpFont != null);
System.Diagnostics.Debug.Assert(mpMaterial != null);

// Convert to system-specific
uint color;
Root.Singleton.ConvertColourValue(mColor, out color);
HardwareVertexBufferSharedPtr vbuf = mRenderOp.vertexData.vertexBufferBinding.GetBuffer(COLOUR_BINDING);
byte* pDest = (byte*)vbuf.Lock(HardwareBuffer.LockOptions.HBL_DISCARD);
for (uint i = 0; i < mRenderOp.vertexData.vertexCount; ++i)
*pDest++ = (byte)color;
vbuf.Unlock();
}

// from MovableObject
protected void getWorldTransforms(Matrix4 xform) {
if (this.IsVisible() && mpCam != null) {
Matrix3 rot3x3 = Matrix3.IDENTITY, scale3x3 = Matrix3.IDENTITY;

// store rotation in a matrix
rot3x3=mpCam.DerivedOrientation.ToRotationMatrix();

// parent node position
Vector3 ppos = ParentNode._getDerivedPosition() + Vector3.UNIT_Y * mAdditionalHeight;

// apply scale
scale3x3[0,0] = ParentNode._getDerivedScale().x / 2;
scale3x3[1,1] = ParentNode._getDerivedScale().y / 2;
scale3x3[2,2] = ParentNode._getDerivedScale().z / 2;

// apply all transforms to xform
xform=new Matrix4(rot3x3 * scale3x3);
xform.SetTrans(ppos);
}
}
protected float getBoundingRadius() { return mRadius; }
protected float getSquaredViewDepth(Camera cam) { return 0; }
protected Quaternion getWorldOrientation() {
System.Diagnostics.Debug.Assert(mpCam != null);
return mpCam.DerivedOrientation;

}
protected Vector3 getWorldPosition() {
System.Diagnostics.Debug.Assert(ParentNode != null);
return this.ParentNode._getDerivedPosition();

}
protected AxisAlignedBox getBoundingBox() { return mAABB; }
protected string getName() { return mName; }
protected string getMovableType() { string movType = "MovableText"; return movType; }

protected new void _notifyCurrentCamera(Camera cam) {
mpCam = cam;
}
protected new void _updateRenderQueue(RenderQueue queue) {
if (this.IsVisible()) {
if (mNeedUpdate)
this._setupGeometry();
if (mUpdateColors)
this._updateColors();
// queue->addRenderable(this, mRenderQueueID, OGRE_RENDERABLE_DEFAULT_PRIORITY);
queue.AddRenderable(this, (byte)RenderQueueGroupID.RENDER_QUEUE_OVERLAY, OGRE_RENDERABLE_DEFAULT_PRIORITY);
// queue->addRenderable(this, mRenderQueueID, RENDER_QUEUE_SKIES_LATE);
}
}

// from renderable
protected void getRenderOperation(RenderOperation op) {
if (this.IsVisible()) {
if (mNeedUpdate)
this._setupGeometry();
if (mUpdateColors)
this._updateColors();
op = mRenderOp;
}
}
protected MaterialPtr getMaterial() { return mpMaterial; }
protected LightList getLights() { return mLList; }
}

Beauty

22-05-2010 12:46:29

Hi Andy,

nice that you published your new port(?) of MovableText :D
Is this similar to MOGRE MovableText?

Can you please add some more information about?

Can the text be clamped to a SceneNode?
Is it needed to recompile Mogre if somebody wants to use it. Or does we just need to add a class?
I suppose it runs with the current Mogre release.

Also an example how to use the code would be nide. And a related Screenshot.
Great would be a wiki page about, but this can be created later (with the content from this page).
Maybe I'll create the wiki page in next time.

smiley80

22-05-2010 15:02:11

Andy's code won't work, since it doesn't create a native Ogre SimpleRenderable and the required protected methods are either not wrapped or not virtual.

However, you can get a similar effect with billboards:
namespace Test
{
using System;
using System.Drawing;
using System.Runtime.InteropServices;

using Mogre;

public sealed class MovableText : IDisposable
{
private Billboard billboard;
private BillboardSet billboardSet;
private MaterialPtr material;
private SceneManager sceneMgr;
private Size size;
private TexturePtr texture;

public MovableText(string name, SceneManager sceneMgr, SceneNode node, Size size)
{
this.texture = TextureManager.Singleton.CreateManual(
name + "Texture",
ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME,
TextureType.TEX_TYPE_2D,
(uint)size.Width,
(uint)size.Height,
0,
PixelFormat.PF_A8R8G8B8);

this.material = MaterialManager.Singleton.Create(name + "Material", ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME);
this.material.GetTechnique(0).GetPass(0).CreateTextureUnitState(this.texture.Name);
this.material.SetSceneBlending(SceneBlendType.SBT_TRANSPARENT_ALPHA);
this.material.SetDepthCheckEnabled(false);

this.billboardSet = sceneMgr.CreateBillboardSet();
this.billboardSet.SetMaterialName(this.material.Name);
this.billboardSet.RenderQueueGroup = (byte)RenderQueueGroupID.RENDER_QUEUE_OVERLAY;

this.billboard = this.billboardSet.CreateBillboard(Vector3.ZERO);
this.billboard.SetDimensions(size.Width, size.Height);
this.billboard.Colour = ColourValue.ZERO;

node.AttachObject(this.billboardSet);
this.sceneMgr = sceneMgr;
this.size = size;
}

public Vector3 Offset
{
get
{
return this.billboard.Position;
}

set
{
this.billboard.Position = value;
}
}

public bool Visible
{
get
{
return this.billboardSet.Visible;
}

set
{
this.billboardSet.Visible = value;
}
}

public void Dispose()
{
this.billboardSet.DetachFromParent();
this.sceneMgr.DestroyBillboardSet(this.billboardSet);
this.billboardSet.Dispose();
this.billboardSet = null;
this.sceneMgr = null;

this.material.Unload();
MaterialManager.Singleton.Remove(this.material.Handle);
this.material.Dispose();
this.material = null;

this.texture.Unload();
TextureManager.Singleton.Remove(this.texture.Handle);
this.texture.Dispose();
this.texture = null;

GC.SuppressFinalize(this);
}

public void SetText(string text, System.Drawing.Font font, Color colour)
{
using (Bitmap bitmap = new Bitmap(this.size.Width, this.size.Height))
{
using (Graphics g = Graphics.FromImage(bitmap))
{
using (SolidBrush brush = new SolidBrush(colour))
{
g.Clear(Color.Transparent);
g.DrawString(text, font, brush, PointF.Empty);
ConvertImageToTexture(bitmap, this.texture.Name, this.size);
}
}
}
}

private static unsafe void ConvertImageToTexture(Bitmap image, string textureName, Size size)
{
int width = size.Width;
int height = size.Height;
using (ResourcePtr rpt = TextureManager.Singleton.GetByName(textureName))
{
using (TexturePtr texture = rpt)
{
HardwarePixelBufferSharedPtr texBuffer = texture.GetBuffer();
texBuffer.Lock(HardwareBuffer.LockOptions.HBL_DISCARD);
PixelBox pb = texBuffer.CurrentLock;

System.Drawing.Imaging.BitmapData data = image.LockBits(new System.Drawing.Rectangle(0, 0, width, height), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
CopyMemory(pb.data, data.Scan0, (uint)(width * height * 4));
image.UnlockBits(data);

texBuffer.Unlock();
texBuffer.Dispose();
}
}
}

[DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
private static extern void CopyMemory(IntPtr Destination, IntPtr Source, uint Length);
}
}

Usage:

MovableText mt = new MovableText("helloWorld", sceneMgr, sceneNode, new Size(128, 32));
mt.SetText("Hello World!", new System.Drawing.Font(FontFamily.GenericSansSerif, 16, FontStyle.Regular, GraphicsUnit.Pixel), Color.Red);

Beauty

04-06-2010 12:48:14

Thanky smiley :)
I put your code to the wiki and added some information.
Please check if the page content is right. And look to the tasks in the ToDo box.
http://www.ogre3d.org/wiki/index.php/MO ... Billboards