roimatola
13-10-2007 18:44:08
Did anyone suceeded in rendering a font to a texture? I wanted to make a billboard with a timer, but i'm having troubles writing the time to a texture. I tried to port this method
http://www.ogre3d.org/wiki/index.php/HowTo:_Write_text_on_texture
like this
but i have AcessViolationExceptions in both PixelUtil.UnpackColour() and PixelUtil.PackColour();
What am i doing wrong? Is there a easier way to write text on a texture? Did anyone managed to port this method?
Thanks in advanced
http://www.ogre3d.org/wiki/index.php/HowTo:_Write_text_on_texture
like this
private unsafe void WriteToTexture(String str, TexturePtr destTexture, Box destRectangle, FontPtr font, ColourValue color)
{
char justify='1';
bool wordwrap = true;
if (destTexture.Height < destRectangle.bottom)
destRectangle.bottom = destTexture.Height;
if (destTexture.Width < destRectangle.right)
destRectangle.right = destTexture.Width;
if (!font.IsLoaded)
font.Load();
TexturePtr fontTexture = (TexturePtr) TextureManager.Singleton.GetByName(font.GetMaterial().GetTechnique(0).GetPass(0).GetTextureUnitState(0).TextureName);
HardwarePixelBufferSharedPtr fontBuffer = fontTexture.GetBuffer();
HardwarePixelBufferSharedPtr destBuffer = destTexture.GetBuffer();
PixelBox destPb = destBuffer.Lock(destRectangle, HardwareBuffer.LockOptions.HBL_NORMAL);
// The font texture buffer was created write only...so we cannot read it back :o). One solution is to copy the buffer instead of locking it. (Maybe there is a way to create a font texture which is not write_only ?)
// create a buffer
uint nBuffSize = fontBuffer.SizeInBytes;
IntPtr buffer = IntPtr.Zero;
buffer = Marshal.AllocHGlobal((int)nBuffSize);
// create pixel box using the copy of the buffer
PixelBox fontPb = new PixelBox(fontBuffer.Width, fontBuffer.Height,fontBuffer.Depth, fontBuffer.Format, buffer);
fontBuffer.BlitToMemory(fontPb);
IntPtr fontData = fontPb.data;
IntPtr destData = destPb.data;
uint fontPixelSize = PixelUtil.GetNumElemBytes(fontPb.format);
uint destPixelSize = PixelUtil.GetNumElemBytes(destPb.format);
uint fontRowPitchBytes = fontPb.rowPitch * fontPixelSize;
uint destRowPitchBytes = destPb.rowPitch * destPixelSize;
Box[] GlyphTexCoords = new Box[str.Length];
FloatRect glypheTexRect;
uint charheight = 0;
uint charwidth = 0;
for(int i = 0; i < str.Length; i++)
{
if ((str[i] != '\t') && (str[i] != '\n') && (str[i] != ' '))
{
glypheTexRect = font.GetGlyphTexCoords(str[i]);
GlyphTexCoords[i].left = (uint)glypheTexRect.left * fontTexture.SrcWidth;
GlyphTexCoords[i].top = (uint)glypheTexRect.top * fontTexture.SrcHeight;
GlyphTexCoords[i].right = (uint)glypheTexRect.right * fontTexture.SrcWidth;
GlyphTexCoords[i].bottom = (uint)glypheTexRect.bottom * fontTexture.SrcHeight;
if (GlyphTexCoords[i].Height > charheight)
charheight = GlyphTexCoords[i].Height;
if (GlyphTexCoords[i].Width > charwidth)
charwidth = GlyphTexCoords[i].Width;
}
}
uint cursorX = 0;
uint cursorY = 0;
uint lineend = destRectangle.Width;
bool carriagreturn = true;
for (int strindex = 0; strindex < str.Length; strindex++)
{
switch(str[strindex])
{
case ' ':
cursorX += charwidth;
break;
case '\t':
cursorX += charwidth * 3;
break;
case '\n':cursorY += charheight;
carriagreturn = true;
break;
default:
{
//wrapping
if ((cursorX + GlyphTexCoords[strindex].Width> lineend) && !carriagreturn )
{
cursorY += charheight;
carriagreturn = true;
}
//justify
if (carriagreturn)
{
int l = strindex;
uint textwidth = 0;
uint wordwidth = 0;
while( (l < str.Length ) && (str[l] != '\n'))
{
wordwidth = 0;
switch (str[l])
{
case ' ':
wordwidth = charwidth; ++l;
break;
case '\t':
wordwidth = charwidth *3;
++l;
break;
case '\n':
l = str.Length;
break;
}
if (wordwrap)
while((l < str.Length) && (str[l] != ' ') && (str[l] != '\t') && (str[l] != '\n'))
{
wordwidth += GlyphTexCoords[l].Width;
++l;
}
else
{
wordwidth += GlyphTexCoords[l].Width;
l++;
}
if ((textwidth + wordwidth) <= destRectangle.Width)
textwidth += (wordwidth);
else
break;
}
if ((textwidth == 0) && (wordwidth > destRectangle.Width))
textwidth = destRectangle.Width;
switch (justify)
{
case 'c':
cursorX = (destRectangle.Width - textwidth)/2;
lineend = destRectangle.Width - cursorX;
break;
case 'r':
cursorX = (destRectangle.Width - textwidth);
lineend = destRectangle.Width;
break;
default:
cursorX = 0;
lineend = textwidth;
break;
}
carriagreturn = false;
}
//abort - not enough space to draw
if ((cursorY + charheight) > destRectangle.Height)
goto stop;
//draw pixel by pixel
for (uint i = 0; i <= GlyphTexCoords[strindex].Height; i++ )
for (uint j = 0; j <= GlyphTexCoords[strindex].Width; j++)
{
int jalupa = (int)((i + GlyphTexCoords[strindex].top) * fontRowPitchBytes + (j + GlyphTexCoords[strindex].left) * fontPixelSize +1);
IntPtr farfe = Marshal.ReadIntPtr(fontData,jalupa);
float alpha = (float) (color.a * (farfe.ToInt32() / 255.0));
float invalpha = (float) 1.0 - alpha;
uint offset = (i + cursorY) * destRowPitchBytes + (j + cursorX) * destPixelSize;
ColourValue pix = ColourValue.Green;
void* destinyData = (void*)Marshal.ReadIntPtr(destData, (int)offset);
try
{
PixelUtil.UnpackColour(&pix, destPb.format, destinyData);
}
catch (AccessViolationException) { }
pix = (pix * invalpha) + (color * alpha);
try
{
PixelUtil.PackColour(pix, destPb.format, (void*)Marshal.ReadIntPtr(destData, (int)offset));
}
catch (AccessViolationException) { }
}
cursorX += GlyphTexCoords[strindex].Width;
}//default
break;
}//switch
}//for
stop:
destBuffer.Unlock();
// Free the memory allocated for the buffer
Marshal.FreeHGlobal(buffer);
}
but i have AcessViolationExceptions in both PixelUtil.UnpackColour() and PixelUtil.PackColour();
What am i doing wrong? Is there a easier way to write text on a texture? Did anyone managed to port this method?
Thanks in advanced