Click here to Skip to main content
15,895,746 members
Articles / Mobile Apps

Bunnyaruga: GAPI, Hekkus, Basics of Deployment

Rate me:
Please Sign up or sign in to vote.
3.63/5 (15 votes)
25 Apr 2004CPOL14 min read 54.1K   247   20  
This article shows an example of a game that uses the GAPI and Hekkus libraries. It also shows a nice and free way of deploying your games/applications without requiring the .NET Framework installed on the end user machines.
using System;
using System.IO;
using System.Reflection;
using System.Drawing;

namespace GXGraphicsLibrary
{
	/// <summary>
	/// Encapsulates the functionality of loading and displaying .fnt font
	/// data.
	/// </summary>
	public class GXFont
	{
		/// <summary>
		/// Definition of an unimplemented character.  Fonts can implement as few
		/// or as many characters as they want.  Unsupported characters will be
		/// ignored during drawing.
		/// </summary>
		protected const ushort kUnsupportedCharacter = 0xffff;

		/// <summary>
		/// The amount of horizontal pixels that a space character ' ' will take up.
		/// </summary>
		protected int m_spaceWidth;

		/// <summary>
		/// The amount of vertical pixels to add to a carriage return.  This is in
		/// addition to the height of the characters, thus resulting in defining the
		/// number of pixels between the rows of text.
		/// </summary>
		protected int m_vertOffset;

		/// <summary>
		/// The amount of horizontal pixels to add between characters.
		/// </summary>
		protected int m_horOffset;

		/// <summary>
		/// The height of this font.  All fonts are uniform so all characters are
		/// considered the same height.
		/// </summary>
		public int Height { get { return m_height; } }
		protected int m_height;

		/// <summary>
		/// Number of bytes in a row of pixels embedded in the font file format.
		/// </summary>
		protected int m_bytesPerRow;

		/// <summary>
		/// The pixel offset of each text character.  If the offset is set to
		/// kUnsupportedCharacter then it is not supported by this font.  There will
		/// be one for each character (256) plus one that is uses to determine the width
		/// of the last character for a total of 257.
		/// </summary>
		protected ushort[] m_xOffset = null;

		/// <summary>
		/// Image data from the font file.  This data is a 1 bit per pixel bitmap.
		/// </summary>
		protected byte[] m_image = null;

		/// <summary>
		/// Create a font from a stream that is associated with a .fnt file.
		/// </summary>
		/// <param name="strm">Stream containing .fnt data</param>
		public GXFont(Stream strm)
		{
			BinaryReader rdr = new BinaryReader(strm);

			// Read in the variables stored at the head of the file
			m_spaceWidth = rdr.ReadInt32();
			m_vertOffset = rdr.ReadInt32();
			m_horOffset = rdr.ReadInt32();
			m_height = rdr.ReadInt32();
			m_bytesPerRow = rdr.ReadInt32();

			// There will always be 257 pixel offsets.
			m_xOffset = new ushort[257];

			// Read in each offset
			for (int i = 0; i < 257; i++)
			{
				m_xOffset[i] = rdr.ReadUInt16();
			}

			// Allocate space for the 1 bit "bitmap" section of the file and load it
			m_image = new byte[rdr.BaseStream.Length - rdr.BaseStream.Position];
			m_image = rdr.ReadBytes((int)(rdr.BaseStream.Length - rdr.BaseStream.Position));
		}

		/// <summary>
		/// Draw some text to the specified bitmap.
		/// </summary>
		/// <param name="gx">Valid GXGraphics object</param>
		/// <param name="dstBitmap">Destination GXBitmap of the draw</param>
		/// <param name="strText">Text to be displayed</param>
		/// <param name="color">Color of text</param>
		/// <param name="x">X pixel location to start text</param>
		/// <param name="y">Y pixel location to start text</param>
		public void DrawString(GXGraphics gx, GXBitmap dstBitmap, string strText, Color color, int x, int y)
		{
			// Track the x and y pixel offsets of the previously drawn character.
			// This is like a cursor.
			int prevXOffset = 0;
			int prevYOffset = 0;

			// Convert the color to the proper pixel format 
			ushort rgb = gx.PixelConverter.ColorToPixel(color);

			// Cache the current draw modes
			bool bAlpha = gx.CheckDrawModes(GXGraphics.DrawFlags.kModeAlphaBlending);
			bool bSrcKey = gx.CheckDrawModes(GXGraphics.DrawFlags.kModeSrcKeyTransparency);
			bool bDstKey = gx.CheckDrawModes(GXGraphics.DrawFlags.kModeDstKeyTransparency);

			ushort rSrc = 0;
			ushort gSrc = 0;
			ushort bSrc = 0;
			ushort rDst = 0;
			ushort gDst = 0;
			ushort bDst = 0;
			ushort dAlpha = (ushort)(255 - gx.Alpha);

			// If alpha blending is set then initialize the data
			if (bAlpha)
			{
				gx.PixelConverter.PixelToBGR(rgb, ref bSrc, ref gSrc, ref rSrc);
				rSrc = (ushort)(gx.Alpha * rSrc);
				gSrc = (ushort)(gx.Alpha * gSrc);
				bSrc = (ushort)(gx.Alpha * bSrc);
			}

			// Cache the transparency keys in case they are used
			ushort sourceKey = gx.SourceKey;
			ushort destinationKey = gx.DestinationKey;

			// Loop through each character in the string
			for (int i = 0; i < strText.Length; i++)
			{
				if (strText[i] == ' ')
				{
					// If the character is a space then move the cursor in the
					// x direction
					prevXOffset += m_spaceWidth;
				}
				else if (strText[i] == '\r')
				{
					// If the character is a carriage return then move the cursor
					// in the y direction and set it back to the starting x location
					prevYOffset += m_height + m_vertOffset;
					prevXOffset = 0;
				}

				// If this is an unsupported character then skip it
				if (m_xOffset[strText[i]] == kUnsupportedCharacter)
					continue;

				// Find the offset of the next character in the font file
				// to determine the extent of the current character
				int nextCharIndex = strText[i] + 1;
				ushort nextCharXOffset = m_xOffset[nextCharIndex];
				while (nextCharXOffset == kUnsupportedCharacter)
				{
					nextCharXOffset = m_xOffset[nextCharIndex++];
				}

				int cStart = m_xOffset[strText[i]];
				int cEnd = nextCharXOffset;

				int xDstPitch = gx.DrawSurface.xPixelPitch;
				int yDstPitch = gx.DrawSurface.yPixelPitch;

				// Draw the character
				unsafe
				{
					// Set up the starting pixel of the destination draw
					ushort* pCurDstLine = (ushort*)dstBitmap.Pixels.ToInt32() + (x + prevXOffset) * xDstPitch + (y + prevYOffset) * yDstPitch;

					// Loop through each row of pixels in the font file
					for (int r = 0; r < m_height; r++)
					{
						ushort* pCurDstPixel = pCurDstLine;

						if (y + prevYOffset + r >= gx.ScreenHeight)
							break;

						// Loop through each column of pixels in the current character
						for (int c = cStart; c < cEnd; c++)
						{
							if (x + prevXOffset + cEnd - c >= gx.ScreenWidth)
								break;

							// The data in the font file is 1 bit so 8 characters are
							// packed into a byte.  Access the proper byte and determine
							// which bit corresponds to the current character
							byte curByte = m_image[r * m_bytesPerRow + c / 8];
							int curBit = c % 8;

							// If the bit that represents this character is set then
							// draw the pixel with the desired color.
							if ((curByte & (0x80 >> curBit)) != 0)
							{
								if (!(bSrcKey && rgb == sourceKey) &&
									!(bDstKey && *pCurDstPixel == destinationKey))
								{
									if (bAlpha)
									{
										gx.PixelConverter.PixelToBGR(*pCurDstPixel, ref bDst, ref gDst, ref rDst);

										rDst = (ushort)((rSrc + rDst * dAlpha) >> 8);
										gDst = (ushort)((gSrc + gDst * dAlpha) >> 8);
										bDst = (ushort)((bSrc + bDst * dAlpha) >> 8);

										*pCurDstPixel = gx.PixelConverter.BGRToPixelNoShift((byte)bDst, (byte)gDst, (byte)rDst);
									}
									else
									{
										*pCurDstPixel = rgb;
									}
								}
							}
							pCurDstPixel += xDstPitch;
						}

						pCurDstLine += yDstPitch;
					}
				}

				// Increment the current location of the cursor by the width
				// of the character and the offset between characters
				prevXOffset += cEnd - cStart + m_horOffset;
			}
		}

		/// <summary>
		/// Returns the location, width and heigh of the string if it were drawn.
		/// </summary>
		/// <param name="rExtents">The rectangle encaspulating the text, filled in by this function</param>
		/// <param name="strText">The text to be measured</param>
		/// <param name="x">The starting x location of the text</param>
		/// <param name="y">The starting y location of the text</param>
		public void GetTextExtents(ref Rectangle rExtents, string strText, int x, int y)
		{
			// Set the start location of the draw to the x,y location
			rExtents.X = x;
			rExtents.Y = y;

			// Track the maximum x size of a draw
			int maxX = 0;

			// Keep track of the cursor location
			int prevXOffset = 0;
			int prevYOffset = 0;

			// Loop through each character in the text
			for (int i = 0; i < strText.Length; i++)
			{
				if (strText[i] == ' ')
				{
					prevXOffset += m_spaceWidth;
				}
				else if (strText[i] == '\r')
				{
					// If a carriage return is detected then check if this is
					// the longest line thus far
					if (prevXOffset > maxX)
						maxX = prevXOffset;

					prevYOffset += m_height + m_vertOffset;
					prevXOffset = x;
				}

				if (m_xOffset[strText[i]] == kUnsupportedCharacter)
					continue;

				int nextCharIndex = strText[i] + 1;
				ushort nextCharXOffset = m_xOffset[nextCharIndex];
				while (nextCharXOffset == kUnsupportedCharacter)
				{
					nextCharXOffset = m_xOffset[nextCharIndex++];
				}

				int cStart = m_xOffset[strText[i]];
				int cEnd = nextCharXOffset;

				prevXOffset += cEnd - cStart + m_horOffset;
			}

			if (prevXOffset > maxX)
				maxX = prevXOffset;

			rExtents.Width = maxX;
			rExtents.Height = prevYOffset;
		}
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
Canada Canada
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions