Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

407 lines
10 KiB

  1. // Copyright Electonic Arts(C) 2006 - All Rights Reserved
  2. #include "filesystem.h"
  3. #include "CTLFont.h"
  4. #include "t2k.h"
  5. #include "tlfont/fusionrasterizer.h"
  6. #include <FontAux/AllocatorAdapters.h>
  7. #include "MemMgr/inc/MemMgr.h"
  8. // CTLFontManager and CTLFont act as a wrapper for Font Fusion. It uses the TLFont
  9. // wrapper for rasterizing with Font Fusion. We ignore all the other systems provided
  10. // by TLFont (caching, drawlists, rendering, etc).
  11. // MARLETT:
  12. // Marlett causes some problems with Font Fusion. It renders the glyphs correctly,
  13. // but can return incorrect metric information. In particular, the descent is always
  14. // 0 and ascent is the height of the glyph; the maximum height calculated from
  15. // the ascent and descent does not always indicate the highest glyph - it is possible
  16. // to render a glyph heigher than (ascent+descent).
  17. //
  18. // For some reason, you need to offset any marlett character codes by 0xf000 otherwise
  19. // Font Fusion will just render invalid glyphs.
  20. using namespace TLFont;
  21. //#define DISABLE_FONT
  22. CTLFontManager::CTLFontManager(IFileSystem *pFileSystem)
  23. {
  24. #ifndef DISABLE_FONT
  25. // The allocator that uses MemMgr
  26. static MemMgr_ICoreAllocator_Adapter memMgrAdapter;
  27. SetAllocator(&memMgrAdapter);
  28. FontFusionMemObject::SetAllocatorCallbacks(FontFusionAlloc, FontFusionFree, 0);
  29. // Load the filesystem
  30. m_pFileSystem = pFileSystem;
  31. ASSERT(m_pFileSystem);
  32. // Reset the font data cache
  33. for (int i = 0; i < MAX_FONTDATACACHE; ++i)
  34. {
  35. memset(m_fontDataCache[i].m_dataName, 0, 256);
  36. m_fontDataCache[i].m_dataMem = NULL;
  37. m_fontDataCache[i].m_dataSize = 0;
  38. m_fontDataCache[i].m_refCount = 0;
  39. }
  40. #endif
  41. }
  42. CTLFontManager::~CTLFontManager()
  43. {
  44. // Clean the cache
  45. for (int i = 0; i < MAX_FONTDATACACHE; ++i)
  46. {
  47. if ( m_fontDataCache[i].m_dataMem )
  48. {
  49. //delete m_fontDataCache[i].m_dataMem;//Now allocated permanently
  50. m_fontDataCache[i].m_dataMem = NULL;
  51. m_fontDataCache[i].m_refCount = 0;
  52. }
  53. }
  54. }
  55. unsigned char* CTLFontManager::LoadFontFile(const char *pFontPath, unsigned int *pDataSize)
  56. {
  57. #if 1
  58. Assert(!"<Sergiy> - temporarily disabling this");
  59. return NULL;
  60. #else
  61. #ifndef DISABLE_FONT
  62. unsigned char *pData = NULL;
  63. unsigned int dataSize = 0;
  64. MEM_ALLOC_CREDIT_("CTLFontManager::LoadFontFile");
  65. // Load a new font file
  66. FileHandle_t hFont = m_pFileSystem->Open(pFontPath, "rb");
  67. if(hFont == NULL)
  68. {
  69. ASSERT(hFont);
  70. return NULL;
  71. }
  72. dataSize = m_pFileSystem->Size(hFont);
  73. if(dataSize == 0)
  74. {
  75. // error getting the file size
  76. ASSERT(dataSize > 0);
  77. return NULL;
  78. }
  79. //pData = new unsigned char[dataSize];
  80. pData= ( unsigned char * )gMemMgr.PermanentAlloc(dataSize);// This is an alloc thats never freed (gives us some flexibility to reuse scraps of memory)
  81. ASSERT(pData);
  82. //printf("LoadFontFile(%s) allocating %d",pFontPath,dataSize);
  83. int ret = m_pFileSystem->Read(pData, dataSize, hFont);
  84. if(pDataSize)
  85. {
  86. *pDataSize = dataSize;
  87. }
  88. m_pFileSystem->Close(hFont);
  89. return pData;
  90. #else
  91. return NULL;
  92. #endif
  93. #endif
  94. }
  95. CTLFont *CTLFontManager::CreateFont(const char *pName, const char *pFontPath, int tall, int weight)
  96. {
  97. #ifndef DISABLE_FONT
  98. unsigned int dataSize = 0;
  99. unsigned char *pData = NULL;
  100. // Check the cache if we have already loaded this font
  101. for (int i = 0; i < MAX_FONTDATACACHE; ++i)
  102. {
  103. if ( m_fontDataCache[i].m_dataMem )
  104. {
  105. if ( strncmp(pName, m_fontDataCache[i].m_dataName, strlen(pName)) == 0 )
  106. {
  107. //printf("CTLFontManager::CreateFont(%s) - found in cache\n",pName);
  108. pData = m_fontDataCache[i].m_dataMem;
  109. dataSize = m_fontDataCache[i].m_dataSize;
  110. m_fontDataCache[i].m_refCount++;
  111. break;
  112. }
  113. }
  114. else
  115. {
  116. // Load the TTF font from disk
  117. //printf("CTLFontManager::CreateFont(%s) - loading from disk\n",pName);
  118. m_fontDataCache[i].m_dataMem = LoadFontFile(pFontPath, &m_fontDataCache[i].m_dataSize);
  119. pData = m_fontDataCache[i].m_dataMem;
  120. dataSize = m_fontDataCache[i].m_dataSize;
  121. Q_strncpy(m_fontDataCache[i].m_dataName, pName, strlen(pName)+1);
  122. m_fontDataCache[i].m_refCount=1;
  123. break;
  124. }
  125. }
  126. if(pData == NULL || dataSize == 0)
  127. {
  128. Assert(0);
  129. return NULL;
  130. }
  131. // Simply allocate a new font and return it. One could, potentially, have a more complex way
  132. // of handling the fonts memory management.
  133. CTLFont *pFont = new CTLFont(pName, pData, dataSize, tall, weight);
  134. ASSERT(pFont);
  135. return pFont;
  136. #else
  137. return NULL;
  138. #endif
  139. }
  140. void CTLFontManager::DestroyFont(CTLFont *pFont)
  141. {
  142. #ifndef DISABLE_FONT
  143. size_t size;
  144. void* pData;
  145. pData=pFont->GetData(&size);
  146. //printf("CTLFontManager::DestroyFont(%s)\n",pFont->GetName());
  147. //Delete CTLFont
  148. delete pFont;
  149. //Update refcount in m_fontDataCache
  150. for (int i = 0; i < MAX_FONTDATACACHE; ++i)
  151. {
  152. if (pData==m_fontDataCache[i].m_dataMem)
  153. {
  154. m_fontDataCache[i].m_refCount--;
  155. break;
  156. }
  157. }
  158. #endif
  159. }
  160. CTLFont::CTLFont(const char *pName, unsigned char *pData, unsigned int dataSize, int tall, int weight)
  161. {
  162. // Font name
  163. int len = strlen(pName);
  164. if(len >= MAX_NAME)
  165. {
  166. memcpy(m_name, pName, (MAX_NAME-2));
  167. m_name[MAX_NAME-1] = 0;
  168. }
  169. else
  170. {
  171. // include the null terminator
  172. memcpy(m_name, pName, len+1);
  173. }
  174. // Dimensions
  175. //note: Point and Logical Size values should be the same, unless you start scaling things.
  176. m_tall = tall;
  177. m_weight = weight;
  178. // empirically derived factor to achieve desired cell height
  179. m_pointSize = m_tall * 0.82f;
  180. // Load the TTF file into memory
  181. m_pData = pData;
  182. m_dataSize = dataSize;
  183. ASSERT(m_pData);
  184. ASSERT(m_dataSize > 0);
  185. // The rasterizer
  186. #ifndef DISABLE_FONT
  187. m_pRasterizer = new FusionRasterizer(m_pData,
  188. m_dataSize,
  189. FONTFILE_TTF,
  190. NULL,
  191. 0.0f,
  192. 1.0f,
  193. 72, 72,
  194. 0, // padding must be zero
  195. m_weight);
  196. ASSERT(m_pRasterizer);
  197. #endif
  198. // Gross marlett hack!
  199. m_charOffset = 0;
  200. if(stricmp(m_name, "Marlett") == 0)
  201. {
  202. m_charOffset = 0xf000;
  203. }
  204. }
  205. CTLFont::~CTLFont()
  206. {
  207. delete m_pRasterizer;
  208. }
  209. void CTLFont::RenderToBuffer(int ch, int offsetx, int width, int height, unsigned char *pBuffer)
  210. {
  211. #ifndef DISABLE_FONT
  212. IRasterizer::RasterizationResult res;
  213. FixedAngle angle(0.0f);
  214. GlyphImage *pImage = m_pRasterizer->Rasterize(ch+m_charOffset, 1.0f, m_pointSize, angle, res);
  215. // Return if we try and render a character we don't understand. This can include white spaces
  216. // and other special control characters.
  217. if(pImage == NULL ||
  218. pImage->GetFormat() == GlyphImage::GLYPHIMAGE_INVALID ||
  219. res == IRasterizer::RASTERIZE_FAILURE)
  220. {
  221. memset(pBuffer, 0x00, (width*height*4));
  222. return;
  223. }
  224. // Image dimensions
  225. unsigned int imageWidth, imageHeight;
  226. pImage->GetGlyphDimensions(imageWidth, imageHeight);
  227. // Marlett can be slightly bigger than the maximum height calculated by adding
  228. // the ascent and descent values together.
  229. if(imageHeight > height)
  230. {
  231. imageHeight = height;
  232. }
  233. // The offset from the baseline..
  234. int xOffset, yOffset;
  235. pImage->GetGlyphOffset(xOffset, yOffset);
  236. // Determine the baseline of the image (using the ascent and descent values)
  237. int ascent = (int)ceil(m_pRasterizer->GetAscent(m_pointSize));
  238. int descent = (int)ceil(m_pRasterizer->GetDescent(m_pointSize));
  239. int maxHeight = (descent + ascent);
  240. int baseOffset = maxHeight - (descent + yOffset);
  241. if(baseOffset < 0)
  242. {
  243. // Marlett can produce a negative offset, which is BAD, so we correct this.
  244. baseOffset = 0;
  245. }
  246. ASSERT((imageHeight+baseOffset) <= height);
  247. // We only support copying of an alpha-only image
  248. ASSERT(pImage->GetFormat() == GlyphImage::GLYPHIMAGE_A8);
  249. if(pImage->GetFormat() == GlyphImage::GLYPHIMAGE_A8)
  250. {
  251. // The rasterized image is stored as single bytes; we need to copy
  252. // this into a 32-bit image.
  253. for(int h = 0; h < imageHeight; h++)
  254. {
  255. unsigned char *pSrc = (unsigned char *)pImage->GetBitmap() + h*imageWidth;
  256. unsigned int *pDst = (unsigned int *)pBuffer + ( (baseOffset+h) * width );
  257. for(int w = 0; w < imageWidth; w++)
  258. {
  259. unsigned char val = pSrc[w];
  260. pDst[w + offsetx] = (0xff << 24) | (0xff << 16) | (0xff << 8) | val;
  261. }
  262. }
  263. }
  264. delete pImage;
  265. #endif
  266. }
  267. // This is a slow function. You should use it with care; possibly implement a basic
  268. // caching system to prevent it being called all the time.
  269. bool CTLFont::GetCharABCWidth(int ch, int &a, int &b, int &c)
  270. {
  271. #ifndef DISABLE_FONT
  272. IRasterizer::RasterizationResult res;
  273. FixedAngle angle(0.0f);
  274. GlyphImage *pImage = m_pRasterizer->Rasterize(ch+m_charOffset, 1.0f, m_pointSize, angle, res);
  275. // Return if we try and render a character we don't understand. This can include white spaces
  276. // and other special control characters.
  277. if(pImage == NULL ||
  278. res == IRasterizer::RASTERIZE_FAILURE)
  279. {
  280. a = 0;
  281. b = 0;
  282. c = 0;
  283. return false;
  284. }
  285. unsigned int width, height;
  286. pImage->GetGlyphDimensions(width, height);
  287. int offsetX, offsetY;
  288. pImage->GetGlyphOffset(offsetX, offsetY);
  289. int advance = pImage->GetGlyphAdvance();
  290. ASSERT((int)width >= 0);
  291. // We simply provide the advance distance as the glyph width, because 'a' and 'c'
  292. // have some special meaning to the Source engine..
  293. b = width;
  294. a = offsetX;
  295. c = advance - ((int)width + offsetX);
  296. // In case the advance value is smaller than the glyph width
  297. if(c < 0)
  298. {
  299. c = 0;
  300. }
  301. delete pImage;
  302. return true;
  303. #else
  304. return false;
  305. #endif
  306. }
  307. int CTLFont::GetMaxHeight()
  308. {
  309. #ifndef DISABLE_FONT
  310. float ascent = m_pRasterizer->GetAscent(m_pointSize);
  311. float descent = m_pRasterizer->GetDescent(m_pointSize);
  312. return (int)(ceil(ascent) + ceil(descent));
  313. #else
  314. return 0;
  315. #endif
  316. }
  317. int CTLFont::GetMaxWidth()
  318. {
  319. // Unimplemented
  320. //ASSERT(0);
  321. return 0;
  322. }
  323. int CTLFont::GetAscent()
  324. {
  325. #ifndef DISABLE_FONT
  326. float ascent = m_pRasterizer->GetAscent(m_pointSize);
  327. return (int)ceil(ascent);
  328. #else
  329. return 0;
  330. #endif
  331. }
  332. void* CTLFont::GetData(size_t * pSizeOut)
  333. {
  334. if (pSizeOut) *pSizeOut=m_dataSize;
  335. return m_pData;
  336. }
  337. const char * CTLFont::GetName()
  338. {
  339. return m_name;
  340. }