render2dsentence.cpp 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600
  1. /*
  2. ** Command & Conquer Renegade(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /***********************************************************************************************
  19. *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : WW3D *
  23. * *
  24. * $Archive:: /Commando/Code/ww3d2/render2dsentence.cpp $*
  25. * *
  26. * $Author:: Steve_t $*
  27. * *
  28. * $Modtime:: 8/26/02 3:18p $*
  29. * *
  30. * $Revision:: 27 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. #include "render2dsentence.h"
  36. #include "surfaceclass.h"
  37. #include "texture.h"
  38. #include "wwprofile.h"
  39. #include "wwmemlog.h"
  40. #include "dx8wrapper.h"
  41. ////////////////////////////////////////////////////////////////////////////////////
  42. // Local constants
  43. ////////////////////////////////////////////////////////////////////////////////////
  44. const int CHAR_TEXTURE_SIZE = 256;
  45. const int CHAR_BUFFER_LEN = 32768;
  46. // Macros.
  47. // NOTE 0: Word wrap logic does not apply to Han characters (Chinese, Japanese & Korean).
  48. // Therefore treat each of these characters as a word which can be preceeded by a line break.
  49. // NOTE 1: This is a simplification. Some Korean characters should not be line break characters.
  50. #define IS_BREAK_CHAR(ch) ((ch == L' ') || ((ch >= 0x3000) && (ch <= 0xdfff)))
  51. ////////////////////////////////////////////////////////////////////////////////////
  52. //
  53. // Render2DSentenceClass
  54. //
  55. ////////////////////////////////////////////////////////////////////////////////////
  56. Render2DSentenceClass::Render2DSentenceClass (void) :
  57. Font (NULL),
  58. Location (0.0F,0.0F),
  59. Cursor (0.0F,0.0F),
  60. TextureOffset (0, 0),
  61. TextureStartX (0),
  62. CurSurface (NULL),
  63. CurrTextureSize (0),
  64. MonoSpaced (false),
  65. IsClippedEnabled (false),
  66. ClipRect (0, 0, 0, 0),
  67. BaseLocation (0, 0),
  68. LockedPtr (NULL),
  69. LockedStride (0),
  70. TextureSizeHint (0),
  71. WrapWidth (0),
  72. TabStop (5.0),
  73. DrawExtents (0, 0, 0, 0),
  74. Renderers(sizeof(PreAllocatedRenderers)/sizeof(RendererDataStruct),PreAllocatedRenderers)
  75. {
  76. Shader = Render2DClass::Get_Default_Shader ();
  77. return ;
  78. }
  79. ////////////////////////////////////////////////////////////////////////////////////
  80. //
  81. // ~Render2DSentenceClass
  82. //
  83. ////////////////////////////////////////////////////////////////////////////////////
  84. Render2DSentenceClass::~Render2DSentenceClass (void)
  85. {
  86. REF_PTR_RELEASE (Font);
  87. Reset ();
  88. return ;
  89. }
  90. ////////////////////////////////////////////////////////////////////////////////////
  91. //
  92. // Set_Font
  93. //
  94. ////////////////////////////////////////////////////////////////////////////////////
  95. void
  96. Render2DSentenceClass::Set_Font (FontCharsClass *font)
  97. {
  98. Reset ();
  99. REF_PTR_SET (Font, font);
  100. return ;
  101. }
  102. ////////////////////////////////////////////////////////////////////////////////////
  103. //
  104. // Reset_Polys
  105. //
  106. ////////////////////////////////////////////////////////////////////////////////////
  107. void
  108. Render2DSentenceClass::Reset_Polys (void)
  109. {
  110. for (int index = 0; index < Renderers.Count (); index ++) {
  111. Renderers[index].Renderer->Reset ();
  112. }
  113. return ;
  114. }
  115. ////////////////////////////////////////////////////////////////////////////////////
  116. //
  117. // Reset
  118. //
  119. ////////////////////////////////////////////////////////////////////////////////////
  120. void
  121. Render2DSentenceClass::Reset (void)
  122. {
  123. //
  124. // Make sure we unlock the current surface (if necessary)
  125. //
  126. if (LockedPtr != NULL) {
  127. CurSurface->Unlock ();
  128. LockedPtr = NULL;
  129. }
  130. //
  131. // Release our hold on the current surface
  132. //
  133. REF_PTR_RELEASE (CurSurface);
  134. //
  135. // Free each renderer
  136. //
  137. for (int i=0;i<Renderers.Count();++i) {
  138. delete Renderers[i].Renderer;
  139. }
  140. Renderers.Reset_Active();
  141. Cursor.Set (0, 0);
  142. MonoSpaced = false;
  143. Release_Pending_Surfaces ();
  144. Reset_Sentence_Data ();
  145. return ;
  146. }
  147. ////////////////////////////////////////////////////////////////////////////////////
  148. //
  149. // Make_Additive
  150. //
  151. ////////////////////////////////////////////////////////////////////////////////////
  152. void
  153. Render2DSentenceClass::Make_Additive (void)
  154. {
  155. Shader.Set_Dst_Blend_Func (ShaderClass::DSTBLEND_ONE);
  156. Shader.Set_Src_Blend_Func (ShaderClass::SRCBLEND_ONE);
  157. Shader.Set_Primary_Gradient (ShaderClass::GRADIENT_MODULATE);
  158. Shader.Set_Secondary_Gradient (ShaderClass::SECONDARY_GRADIENT_DISABLE);
  159. Set_Shader (Shader);
  160. return ;
  161. }
  162. ////////////////////////////////////////////////////////////////////////////////////
  163. //
  164. // Make_Additive
  165. //
  166. ////////////////////////////////////////////////////////////////////////////////////
  167. void
  168. Render2DSentenceClass::Set_Shader (ShaderClass shader)
  169. {
  170. Shader = shader;
  171. //
  172. // Change each renderer's shader
  173. //
  174. for (int i = 0; i < Renderers.Count (); i ++) {
  175. ShaderClass *curr_shader = Renderers[i].Renderer->Get_Shader ();
  176. (*curr_shader) = Shader;
  177. }
  178. return ;
  179. }
  180. ////////////////////////////////////////////////////////////////////////////////////
  181. //
  182. // Render
  183. //
  184. ////////////////////////////////////////////////////////////////////////////////////
  185. void
  186. Render2DSentenceClass::Render (void)
  187. {
  188. if (DX8Wrapper::Is_Device_Lost() || !DX8Wrapper::Is_Initted()) return;
  189. //
  190. // Build any textures that are pending
  191. //
  192. Build_Textures ();
  193. //
  194. // Ask each renderer to draw its contents
  195. //
  196. for (int i = 0; i < Renderers.Count (); i ++) {
  197. Renderers[i].Renderer->Render ();
  198. }
  199. return ;
  200. }
  201. ////////////////////////////////////////////////////////////////////////////////////
  202. //
  203. // Set_Base_Location
  204. //
  205. ////////////////////////////////////////////////////////////////////////////////////
  206. void
  207. Render2DSentenceClass::Set_Base_Location (const Vector2 &loc)
  208. {
  209. Vector2 dif = loc - BaseLocation;
  210. BaseLocation = loc;
  211. for (int i = 0; i < Renderers.Count (); i ++) {
  212. Renderers[i].Renderer->Move (dif);
  213. }
  214. return ;
  215. }
  216. ////////////////////////////////////////////////////////////////////////////////////
  217. //
  218. // Set_Location
  219. //
  220. ////////////////////////////////////////////////////////////////////////////////////
  221. void
  222. Render2DSentenceClass::Set_Location (const Vector2 &loc)
  223. {
  224. Location = loc;
  225. return ;
  226. }
  227. void
  228. Render2DSentenceClass::Set_Tabstop(float stop)
  229. {
  230. if (stop > 0.0) {
  231. TabStop = stop;
  232. } else {
  233. TabStop = 1.0;
  234. }
  235. }
  236. ////////////////////////////////////////////////////////////////////////////////////
  237. //
  238. // Get_Text_Extents
  239. //
  240. ////////////////////////////////////////////////////////////////////////////////////
  241. Vector2
  242. Render2DSentenceClass::Get_Text_Extents (const WCHAR *text)
  243. {
  244. if (!DX8Wrapper::Is_Initted()) {
  245. Vector2 temp(0,0);
  246. return(temp);
  247. }
  248. Vector2 extent (0, Font->Get_Char_Height());
  249. while (*text) {
  250. WCHAR ch = *text++;
  251. if ( ch != (WCHAR)'\n' ) {
  252. extent.X += Font->Get_Char_Spacing( ch );
  253. }
  254. }
  255. return extent;
  256. }
  257. ////////////////////////////////////////////////////////////////////////////////////
  258. //
  259. // Find_Row_Start
  260. //
  261. ////////////////////////////////////////////////////////////////////////////////////
  262. const WCHAR *
  263. Render2DSentenceClass::Find_Row_Start( const WCHAR * text, int row_index )
  264. {
  265. if (row_index == 0) {
  266. return text;
  267. }
  268. if (!DX8Wrapper::Is_Initted()) {
  269. return text;
  270. }
  271. const WCHAR *retval = NULL;
  272. float max_x_pos = 0;
  273. float x_pos = 0;
  274. float y_pos = Font->Get_Char_Height ();
  275. int row_counter = 0;
  276. while (*text) {
  277. WCHAR ch = *text++;
  278. bool is_wrapped = false;
  279. //
  280. // Check to see if we need to wrap on this word-break
  281. //
  282. if (IS_BREAK_CHAR (ch) && WrapWidth > 0) {
  283. //
  284. // Find the width of the next word
  285. //
  286. const WCHAR *word = text;
  287. float word_width = Font->Get_Char_Spacing (ch);
  288. while ((*word != 0) && ((*word > L' ') && !IS_BREAK_CHAR (*word))) {
  289. word_width += Font->Get_Char_Spacing (*word++);
  290. }
  291. //
  292. // Did the word extend past the wrap width?
  293. //
  294. if ((x_pos + word_width) >= WrapWidth) {
  295. is_wrapped = true;
  296. }
  297. } else if (ch == L'\n') {
  298. is_wrapped = true;
  299. }
  300. //
  301. // Handle line wrapping
  302. //
  303. if (is_wrapped) {
  304. max_x_pos = max (max_x_pos, x_pos);
  305. x_pos = 0;
  306. y_pos += Font->Get_Char_Height ();
  307. //
  308. // Is this the line we're looking for?
  309. //
  310. row_counter ++;
  311. if (row_counter == row_index) {
  312. retval = (ch == L' ' || ch == L'\n') ? text : text - 1;
  313. break;
  314. }
  315. }
  316. if (ch != (WCHAR)'\n') {
  317. x_pos += Font->Get_Char_Spacing (ch);
  318. }
  319. }
  320. return retval;
  321. }
  322. ////////////////////////////////////////////////////////////////////////////////////
  323. //
  324. // Get_Formatted_Text_Extents
  325. //
  326. ////////////////////////////////////////////////////////////////////////////////////
  327. Vector2
  328. Render2DSentenceClass::Get_Formatted_Text_Extents (const WCHAR *text, int *row_count)
  329. {
  330. if (!DX8Wrapper::Is_Initted()) {
  331. Vector2 temp(0,0);
  332. return(temp);
  333. }
  334. float max_x_pos = 0;
  335. float x_pos = 0;
  336. float y_pos = Font->Get_Char_Height ();
  337. int row_counter = 0;
  338. while (*text) {
  339. WCHAR ch = *text++;
  340. bool is_wrapped = false;
  341. //
  342. // Check to see if we need to wrap on this word-break
  343. //
  344. if (IS_BREAK_CHAR (ch) && WrapWidth > 0) {
  345. //
  346. // Find the width of the next word
  347. //
  348. const WCHAR *word = text;
  349. float word_width = Font->Get_Char_Spacing (ch);
  350. while ((*word != 0) && ((*word > L' ') && !IS_BREAK_CHAR (*word))) {
  351. word_width += Font->Get_Char_Spacing (*word++);
  352. }
  353. //
  354. // Did the word extend past the wrap width?
  355. //
  356. if ((x_pos + word_width) >= WrapWidth) {
  357. is_wrapped = true;
  358. }
  359. } else if (ch == L'\n') {
  360. is_wrapped = true;
  361. }
  362. //
  363. // Handle line wrapping
  364. //
  365. if (is_wrapped) {
  366. max_x_pos = max (max_x_pos, x_pos);
  367. x_pos = 0;
  368. y_pos += Font->Get_Char_Height ();
  369. row_counter ++;
  370. }
  371. if (ch != (WCHAR)'\n') {
  372. x_pos += Font->Get_Char_Spacing (ch);
  373. }
  374. }
  375. //
  376. // Build a Vector2 out of our extents
  377. //
  378. Vector2 extent;
  379. extent.X = max (max_x_pos, x_pos);
  380. extent.Y = y_pos;
  381. //
  382. // Return the row count to the caller (if necessary)
  383. //
  384. if (row_count != NULL) {
  385. (*row_count) = row_counter + 1;
  386. }
  387. return extent;
  388. }
  389. ////////////////////////////////////////////////////////////////////////////////////
  390. //
  391. // Reset_Sentence_Data
  392. //
  393. ////////////////////////////////////////////////////////////////////////////////////
  394. void
  395. Render2DSentenceClass::Reset_Sentence_Data (void)
  396. {
  397. //
  398. // Release our hold on each texture used in the sentence
  399. //
  400. for (int index = 0; index < SentenceData.Count (); index ++) {
  401. REF_PTR_RELEASE (SentenceData[index].Surface);
  402. }
  403. SentenceData.Reset_Active();
  404. return ;
  405. }
  406. ////////////////////////////////////////////////////////////////////////////////////
  407. //
  408. // Release_Pending_Surfaces
  409. //
  410. ////////////////////////////////////////////////////////////////////////////////////
  411. void
  412. Render2DSentenceClass::Release_Pending_Surfaces (void)
  413. {
  414. //
  415. // Release our hold on each pending surface
  416. //
  417. for (int index = 0; index < PendingSurfaces.Count (); index ++) {
  418. SurfaceClass *curr_surface = PendingSurfaces[index].Surface;
  419. REF_PTR_RELEASE (curr_surface);
  420. }
  421. PendingSurfaces.Reset_Active();
  422. return;
  423. }
  424. ////////////////////////////////////////////////////////////////////////////////////
  425. //
  426. // Build_Textures
  427. //
  428. ////////////////////////////////////////////////////////////////////////////////////
  429. void
  430. Render2DSentenceClass::Build_Textures (void)
  431. {
  432. WWMEMLOG(MEM_TEXTURE);
  433. //
  434. // Make sure we unlock the current surface
  435. //
  436. if (LockedPtr != NULL) {
  437. CurSurface->Unlock ();
  438. LockedPtr = NULL;
  439. }
  440. //
  441. // Release our hold on the current surface
  442. //
  443. REF_PTR_RELEASE (CurSurface);
  444. TextureOffset.Set (0, 0);
  445. TextureStartX = 0;
  446. //
  447. // Convert all pending surfaces to textures
  448. //
  449. for (int index = 0; index < PendingSurfaces.Count (); index ++) {
  450. PendingSurfaceStruct &surface_info = PendingSurfaces[index];
  451. SurfaceClass *curr_surface = surface_info.Surface;
  452. //
  453. // Get the dimensions of the surface
  454. //
  455. SurfaceClass::SurfaceDescription desc;
  456. curr_surface->Get_Description (desc);
  457. //
  458. // Create the new texture
  459. //
  460. TextureClass *new_texture = new TextureClass (desc.Width, desc.Width, WW3D_FORMAT_A4R4G4B4, TextureClass::MIP_LEVELS_1);
  461. SurfaceClass *texture_surface = new_texture->Get_Surface_Level ();
  462. //
  463. // Copy the contents of the texture from the surface
  464. //
  465. DX8Wrapper::_Copy_DX8_Rects (curr_surface->Peek_D3D_Surface (), NULL, 0, texture_surface->Peek_D3D_Surface (), NULL);
  466. REF_PTR_RELEASE (texture_surface);
  467. //
  468. // Assign this texture to any renderers that need it
  469. //
  470. for (int renderer_index = 0; renderer_index < surface_info.Renderers.Count (); renderer_index ++) {
  471. Render2DClass *renderer = surface_info.Renderers[renderer_index];
  472. renderer->Set_Texture (new_texture);
  473. }
  474. //
  475. // Release our hold on the objects
  476. //
  477. REF_PTR_RELEASE (new_texture);
  478. REF_PTR_RELEASE (curr_surface);
  479. }
  480. //
  481. // Reset the list
  482. //
  483. PendingSurfaces.Reset_Active();
  484. return ;
  485. }
  486. ////////////////////////////////////////////////////////////////////////////////////
  487. //
  488. // Draw_Sentence
  489. //
  490. ////////////////////////////////////////////////////////////////////////////////////
  491. void
  492. Render2DSentenceClass::Draw_Sentence (uint32 color)
  493. {
  494. Render2DClass *curr_renderer = NULL;
  495. SurfaceClass *curr_surface = NULL;
  496. DrawExtents.Set (0, 0, 0, 0);
  497. //
  498. // Loop over all the parts of the sentence
  499. //
  500. for (int index = 0; index < SentenceData.Count (); index ++) {
  501. SentenceDataStruct &data = SentenceData[index];
  502. //
  503. // Has the surface changed?
  504. //
  505. if (data.Surface != curr_surface) {
  506. curr_surface = data.Surface;
  507. //
  508. // Try to find a renderer that uses the same "texture"
  509. //
  510. bool found = false;
  511. for (int renderer_index = 0; renderer_index < Renderers.Count (); renderer_index ++) {
  512. if (Renderers[renderer_index].Surface == curr_surface) {
  513. found = true;
  514. curr_renderer = Renderers[renderer_index].Renderer;
  515. break;
  516. }
  517. }
  518. //
  519. // Create a new renderer if we couldn't find an appropriate one
  520. //
  521. if (found == false) {
  522. //
  523. // Allocate a new renderer
  524. //
  525. curr_renderer = new Render2DClass;
  526. curr_renderer->Set_Coordinate_Range (Render2DClass::Get_Screen_Resolution ());
  527. ShaderClass *curr_shader = curr_renderer->Get_Shader ();
  528. (*curr_shader) = Shader;
  529. //
  530. // Add it to our list
  531. //
  532. RendererDataStruct render_info;
  533. render_info.Renderer = curr_renderer;
  534. render_info.Surface = curr_surface;
  535. Renderers.Add (render_info);
  536. //
  537. // Now, add this renderer to the surface pending list
  538. //
  539. for (int surface_index = 0; surface_index < PendingSurfaces.Count (); surface_index ++) {
  540. PendingSurfaceStruct &surface_info = PendingSurfaces[surface_index];
  541. if (surface_info.Surface == curr_surface) {
  542. surface_info.Renderers.Add (curr_renderer);
  543. }
  544. }
  545. }
  546. }
  547. //
  548. // Get the dimensions of the surface
  549. //
  550. SurfaceClass::SurfaceDescription desc;
  551. curr_surface->Get_Description (desc);
  552. //
  553. // Add a quad that contains this sentence chunk
  554. //
  555. RectClass screen_rect = data.ScreenRect;
  556. screen_rect += Location;
  557. RectClass uv_rect = data.UVRect;
  558. //
  559. // Clip the quad (as necessary)
  560. //
  561. bool add_quad = true;
  562. if (IsClippedEnabled) {
  563. //
  564. // Check for completely clipped
  565. //
  566. if ( screen_rect.Right <= ClipRect.Left ||
  567. screen_rect.Bottom <= ClipRect.Top)
  568. {
  569. add_quad = false;
  570. /*} else if ( screen_rect.Top < ClipRect.Top ||
  571. screen_rect.Bottom > ClipRect.Bottom)
  572. {
  573. add_quad = false;*/
  574. } else {
  575. //
  576. // Clip the polygons to the specified area
  577. //
  578. RectClass clipped_rect;
  579. clipped_rect.Left = max (screen_rect.Left, ClipRect.Left);
  580. clipped_rect.Right = min (screen_rect.Right, ClipRect.Right);
  581. clipped_rect.Top = max (screen_rect.Top, ClipRect.Top);
  582. clipped_rect.Bottom = min (screen_rect.Bottom, ClipRect.Bottom);
  583. //
  584. // Clip the texture to the specified area
  585. //
  586. RectClass clipped_uv_rect;
  587. float percent = ((clipped_rect.Left - screen_rect.Left) / screen_rect.Width ());
  588. clipped_uv_rect.Left = uv_rect.Left + (uv_rect.Width () * percent);
  589. percent = ((clipped_rect.Right - screen_rect.Left) / screen_rect.Width ());
  590. clipped_uv_rect.Right = uv_rect.Left + (uv_rect.Width () * percent);
  591. percent = ((clipped_rect.Top - screen_rect.Top) / screen_rect.Height ());
  592. clipped_uv_rect.Top = uv_rect.Top + (uv_rect.Height () * percent);
  593. percent = ((clipped_rect.Bottom - screen_rect.Top) / screen_rect.Height ());
  594. clipped_uv_rect.Bottom = uv_rect.Top + (uv_rect.Height () * percent);
  595. //
  596. // Use the clipped rectangles to render
  597. //
  598. screen_rect = clipped_rect;
  599. uv_rect = clipped_uv_rect;
  600. }
  601. }
  602. if (add_quad) {
  603. uv_rect *= 1.0F / ((float)desc.Width);
  604. curr_renderer->Add_Quad (screen_rect, uv_rect, color);
  605. //
  606. // Add this rectangle to the total draw extents
  607. //
  608. if (DrawExtents.Width () == 0) {
  609. DrawExtents = screen_rect;
  610. } else {
  611. DrawExtents += screen_rect;
  612. }
  613. }
  614. }
  615. return ;
  616. }
  617. ////////////////////////////////////////////////////////////////////////////////////
  618. //
  619. // Record_Sentence_Chunk
  620. //
  621. ////////////////////////////////////////////////////////////////////////////////////
  622. void
  623. Render2DSentenceClass::Record_Sentence_Chunk (void)
  624. {
  625. //
  626. // Do we have anything to store?
  627. //
  628. int width = TextureOffset.I - TextureStartX;
  629. if (width > 0) {
  630. float char_height = Font->Get_Char_Height ();
  631. //
  632. // Build a structure that contains enough information
  633. // to hold this portion of the sentence
  634. //
  635. SentenceDataStruct sentence_data;
  636. sentence_data.Surface = CurSurface;
  637. sentence_data.Surface->Add_Ref ();
  638. sentence_data.ScreenRect.Left = Cursor.X;
  639. sentence_data.ScreenRect.Right = Cursor.X + width;
  640. sentence_data.ScreenRect.Top = Cursor.Y;
  641. sentence_data.ScreenRect.Bottom = Cursor.Y + char_height;
  642. sentence_data.UVRect.Left = TextureStartX;
  643. sentence_data.UVRect.Top = TextureOffset.J;
  644. sentence_data.UVRect.Right = TextureOffset.I;
  645. sentence_data.UVRect.Bottom = TextureOffset.J + char_height;
  646. //
  647. // Add this information to our list
  648. //
  649. SentenceData.Add (sentence_data);
  650. }
  651. return ;
  652. }
  653. ////////////////////////////////////////////////////////////////////////////////////
  654. //
  655. // Allocate_New_Surface
  656. //
  657. ////////////////////////////////////////////////////////////////////////////////////
  658. void
  659. Render2DSentenceClass::Allocate_New_Surface (const WCHAR *text)
  660. {
  661. //
  662. // Unlock the last surface (if necessary)
  663. //
  664. if (LockedPtr != NULL) {
  665. CurSurface->Unlock ();
  666. LockedPtr = NULL;
  667. }
  668. //
  669. // Calculate the width of the text
  670. //
  671. int text_width = 0;
  672. for (int index = 0; text[index] != 0; index ++) {
  673. text_width += Font->Get_Char_Spacing (text[index]);
  674. }
  675. int char_height = Font->Get_Char_Height ();
  676. //
  677. // Find the best texture size for the remaining text
  678. //
  679. CurrTextureSize = 256;
  680. int best_tex_mem_usage = 999999999;
  681. for (int pow2 = 6; pow2 <= 8; pow2 ++) {
  682. int size = 1 << pow2;
  683. int row_count = (text_width / size) + 1;
  684. int rows_per_texture = size / (char_height + 1);
  685. //
  686. // Can we even fit one character on this texture?
  687. //
  688. if (rows_per_texture > 0) {
  689. //
  690. // How many textures (at this size) would it take to render
  691. // the remaining text?
  692. //
  693. int texture_count = row_count / rows_per_texture;
  694. texture_count = max (texture_count, 1);
  695. //
  696. // Is this the best usage of texture memory we've found yet?
  697. //
  698. int texture_mem_usage = (texture_count * size * size);
  699. if (texture_mem_usage < best_tex_mem_usage) {
  700. CurrTextureSize = size;
  701. best_tex_mem_usage = texture_mem_usage;
  702. }
  703. }
  704. }
  705. //
  706. // Use whichever is larger, the hint or the calculated size
  707. //
  708. CurrTextureSize = max (TextureSizeHint, CurrTextureSize);
  709. //
  710. // Release our extra hold on the old surface
  711. //
  712. REF_PTR_RELEASE (CurSurface);
  713. //
  714. // Create the new surface
  715. //
  716. CurSurface = NEW_REF (SurfaceClass, (CurrTextureSize, CurrTextureSize, WW3D_FORMAT_A4R4G4B4));
  717. WWASSERT (CurSurface != NULL);
  718. CurSurface->Add_Ref ();
  719. //
  720. // Add this surface to our list
  721. //
  722. PendingSurfaceStruct surface_info;
  723. surface_info.Surface = CurSurface;
  724. PendingSurfaces.Add (surface_info);
  725. //
  726. // Reset to the upper left corner
  727. //
  728. TextureOffset.Set (0, 0);
  729. TextureStartX = 0;
  730. return ;
  731. }
  732. ////////////////////////////////////////////////////////////////////////////////////
  733. //
  734. // Build_Sentence
  735. //
  736. ////////////////////////////////////////////////////////////////////////////////////
  737. void
  738. Render2DSentenceClass::Build_Sentence (const WCHAR *text)
  739. {
  740. if (text == NULL) {
  741. return ;
  742. }
  743. if (!DX8Wrapper::Is_Initted()) {
  744. return;
  745. }
  746. //
  747. // Start fresh
  748. //
  749. Reset_Sentence_Data ();
  750. Cursor.Set (0, 0);
  751. //
  752. // Ensure we have a surface to start with
  753. //
  754. if (CurSurface == NULL) {
  755. Allocate_New_Surface (text);
  756. }
  757. float char_height = Font->Get_Char_Height ();
  758. //
  759. // Loop over all the characters in the string
  760. //
  761. while (text != NULL) {
  762. WCHAR ch = *text++;
  763. //
  764. // Determine how much horizontal space this character requires
  765. //
  766. float char_spacing = Font->Get_Char_Spacing (ch);
  767. bool exceeded_texture_width = ((TextureOffset.I + char_spacing) >= CurrTextureSize);
  768. bool encountered_break_char = (IS_BREAK_CHAR (ch) || ch == L'\n' || ch == 0 || ch == L'\t');
  769. //
  770. // Do we need to record this portion of the sentence to its own chunk?
  771. //
  772. if (exceeded_texture_width || encountered_break_char) {
  773. Record_Sentence_Chunk ();
  774. //
  775. // Adjust the positions
  776. //
  777. Cursor.X += (TextureOffset.I - TextureStartX);
  778. TextureStartX = TextureOffset.I;
  779. //
  780. // Adjust the output coordinates
  781. //
  782. if (IS_BREAK_CHAR (ch)) {
  783. if (ch == L' ') {
  784. Cursor.X += char_spacing;
  785. }
  786. //
  787. // Check to see if we need to wrap on this word-break
  788. //
  789. if (WrapWidth > 0) {
  790. //
  791. // Find the length of the next word
  792. //
  793. const WCHAR *word = text;
  794. float word_width = (ch == L' ') ? 0 : char_spacing;
  795. while ((*word != 0) && ((*word > L' ') && !IS_BREAK_CHAR (*word))) {
  796. word_width += Font->Get_Char_Spacing (*word++);
  797. }
  798. //
  799. // Should we wrap the next word?
  800. //
  801. if ((Cursor.X + word_width) >= WrapWidth) {
  802. Cursor.X = 0;
  803. Cursor.Y += char_height;
  804. }
  805. }
  806. } else if (ch == L'\n') {
  807. Cursor.X = 0;
  808. Cursor.Y += char_height;
  809. } else if (ch == 0) {
  810. break;
  811. } else if (ch == L'\t') {
  812. float tab_spacing = (char_spacing * TabStop);
  813. float tab_pos = (floor(Cursor.X / tab_spacing) * tab_spacing);
  814. Cursor.X = (tab_pos + tab_spacing);
  815. }
  816. //
  817. // Did the text extend past the edge of the texture?
  818. //
  819. if (exceeded_texture_width) {
  820. TextureStartX = 0;
  821. TextureOffset.I = TextureStartX;
  822. TextureOffset.J += char_height;
  823. //
  824. // Did the text extent completely off the texture?
  825. //
  826. if ((TextureOffset.J + char_height) >= CurrTextureSize) {
  827. Allocate_New_Surface (text);
  828. }
  829. }
  830. }
  831. if (ch != L'\n' && ch != L' ' && ch != L'\t') {
  832. //
  833. // Ensure the surface is locked
  834. //
  835. if (LockedPtr == NULL) {
  836. LockedPtr = (uint16 *)CurSurface->Lock (&LockedStride);
  837. WWASSERT (LockedPtr != NULL);
  838. }
  839. //
  840. // Check to ensure the text will fit on this texture
  841. //
  842. WWASSERT (((TextureOffset.I + char_spacing) < CurrTextureSize) && ((TextureOffset.J + char_height) < CurrTextureSize));
  843. //
  844. // Blit the character to the surface
  845. //
  846. Font->Blit_Char (ch, LockedPtr, LockedStride, TextureOffset.I, TextureOffset.J);
  847. TextureOffset.I += char_spacing;
  848. }
  849. }
  850. return ;
  851. }
  852. ////////////////////////////////////////////////////////////////////////////////////
  853. ////////////////////////////////////////////////////////////////////////////////////
  854. void Render2DSentenceClass::Force_Alpha( float alpha )
  855. {
  856. for (int i = 0; i < Renderers.Count (); i ++) {
  857. Renderers[i].Renderer->Force_Alpha( alpha );
  858. }
  859. }
  860. ////////////////////////////////////////////////////////////////////////////////////
  861. //
  862. // FontCharsClass
  863. //
  864. ////////////////////////////////////////////////////////////////////////////////////
  865. FontCharsClass::FontCharsClass (void) :
  866. OldGDIFont( NULL ),
  867. OldGDIBitmap( NULL ),
  868. GDIFont( NULL ),
  869. GDIBitmap( NULL ),
  870. GDIBitmapBits ( NULL ),
  871. MemDC( NULL ),
  872. CurrPixelOffset( 0 ),
  873. PointSize( 0 ),
  874. CharHeight( 0 ),
  875. UnicodeCharArray( NULL ),
  876. FirstUnicodeChar( 0xFFFF ),
  877. LastUnicodeChar( 0 ),
  878. IsBold (false),
  879. BufferList(sizeof(PreAllocatedBufferList)/sizeof(uint16*),PreAllocatedBufferList)
  880. {
  881. ::memset( ASCIICharArray, 0, sizeof (ASCIICharArray) );
  882. return ;
  883. }
  884. ////////////////////////////////////////////////////////////////////////////////////
  885. //
  886. // ~FontCharsClass
  887. //
  888. ////////////////////////////////////////////////////////////////////////////////////
  889. FontCharsClass::~FontCharsClass (void)
  890. {
  891. for (int i=0;i<BufferList.Count(); ++i) {
  892. delete [] BufferList[i];
  893. }
  894. BufferList.Reset_Active();
  895. Free_GDI_Font();
  896. Free_Character_Arrays();
  897. return ;
  898. }
  899. ////////////////////////////////////////////////////////////////////////////////////
  900. //
  901. // Get_Char_Data
  902. //
  903. ////////////////////////////////////////////////////////////////////////////////////
  904. const FontCharsClass::CharDataStruct *
  905. FontCharsClass::Get_Char_Data (WCHAR ch)
  906. {
  907. const CharDataStruct *retval = NULL;
  908. if ( ch < 256 ) {
  909. retval = ASCIICharArray[ch];
  910. } else {
  911. Grow_Unicode_Array( ch );
  912. retval = UnicodeCharArray[ch - FirstUnicodeChar];
  913. }
  914. //
  915. // If the character wasn't found, then add it to our list
  916. //
  917. if ( retval == NULL ) {
  918. retval = Store_GDI_Char( ch );
  919. }
  920. WWASSERT( retval->Value == ch );
  921. return retval;
  922. }
  923. ////////////////////////////////////////////////////////////////////////////////////
  924. //
  925. // Get_Char_Width
  926. //
  927. ////////////////////////////////////////////////////////////////////////////////////
  928. int
  929. FontCharsClass::Get_Char_Width (WCHAR ch)
  930. {
  931. const CharDataStruct * data = Get_Char_Data( ch );
  932. if ( data != NULL ) {
  933. return data->Width;
  934. }
  935. return 0;
  936. }
  937. ////////////////////////////////////////////////////////////////////////////////////
  938. //
  939. // Get_Char_Spacing
  940. //
  941. ////////////////////////////////////////////////////////////////////////////////////
  942. int
  943. FontCharsClass::Get_Char_Spacing (WCHAR ch)
  944. {
  945. const CharDataStruct * data = Get_Char_Data( ch );
  946. if ( data != NULL ) {
  947. if ( data->Width != 0 ) {
  948. return data->Width + 1;
  949. }
  950. }
  951. return 0;
  952. }
  953. ////////////////////////////////////////////////////////////////////////////////////
  954. //
  955. // Blit_Char
  956. //
  957. ////////////////////////////////////////////////////////////////////////////////////
  958. void
  959. FontCharsClass::Blit_Char (WCHAR ch, uint16 *dest_ptr, int dest_stride, int x, int y)
  960. {
  961. const CharDataStruct * data = Get_Char_Data( ch );
  962. if ( data != NULL && data->Width != 0 ) {
  963. //
  964. // Setup the src and destination pointers
  965. //
  966. int dest_inc = (dest_stride >> 1);
  967. uint16 *src_ptr = data->Buffer;
  968. dest_ptr += (dest_inc * y) + x;
  969. //
  970. // Simply copy the data from the src buffer to the destination
  971. //
  972. for ( int row = 0; row < CharHeight; row ++ ) {
  973. for ( int col = 0; col < data->Width; col ++ ) {
  974. dest_ptr[col] = *src_ptr++;
  975. }
  976. dest_ptr += dest_inc;
  977. }
  978. }
  979. return ;
  980. }
  981. ////////////////////////////////////////////////////////////////////////////////////
  982. //
  983. // Store_GDI_Char
  984. //
  985. ////////////////////////////////////////////////////////////////////////////////////
  986. const FontCharsClass::CharDataStruct *
  987. FontCharsClass::Store_GDI_Char (WCHAR ch)
  988. {
  989. int width = PointSize * 2;
  990. int height = PointSize * 2;
  991. //
  992. // Get the size of the character we just drew
  993. //
  994. SIZE char_size = { 0 };
  995. ::GetTextExtentPoint32W( MemDC, &ch, 1, &char_size );
  996. int x_pos = 0;
  997. //
  998. // HACK HACK -- With the default font that Renegade uses the
  999. // W and V characters need to be moved over one pixel.
  1000. //
  1001. if ( (ch == 'W' || ch == 'V') && (GDIFontName.Compare_No_Case ("Arial MT") == 0) ) {
  1002. x_pos = 1;
  1003. char_size.cx += 1;
  1004. }
  1005. //
  1006. // Draw the character into the memory DC
  1007. //
  1008. RECT rect = { 0, 0, width, height };
  1009. ::ExtTextOutW( MemDC, x_pos, 0, ETO_OPAQUE, &rect, &ch, 1, NULL);
  1010. //
  1011. // Get a pointer to the surface that this character should use
  1012. //
  1013. Update_Current_Buffer( char_size.cx );
  1014. uint16 *curr_buffer = BufferList[BufferList.Count () - 1];
  1015. curr_buffer += CurrPixelOffset;
  1016. //
  1017. // Copy the BMP contents to the buffer
  1018. //
  1019. int stride = (((width * 3) + 3) & ~3);
  1020. for (int row = 0; row < char_size.cy; row ++) {
  1021. //
  1022. // Compute the indices into the BMP and surface
  1023. //
  1024. int index = (row * stride);
  1025. //
  1026. // Loop over each column
  1027. //
  1028. for (int col = 0; col < char_size.cx; col ++) {
  1029. //
  1030. // Get the pixel color at this location
  1031. //
  1032. uint8 pixel_value = GDIBitmapBits[index];
  1033. index += 3;
  1034. uint16 pixel_color = 0;
  1035. if (pixel_value != 0) {
  1036. pixel_color = 0x0FFF;
  1037. }
  1038. //
  1039. // Convert the pixel intensity from 8bit to 4bit and
  1040. // store it in our buffer
  1041. //
  1042. uint8 alpha_value = ((pixel_value >> 4) & 0xF);
  1043. *curr_buffer ++ = pixel_color | (alpha_value << 12);
  1044. }
  1045. }
  1046. //
  1047. // Save information about this character in our list
  1048. //
  1049. CharDataStruct *char_data = new CharDataStruct;
  1050. char_data->Value = ch;
  1051. char_data->Width = char_size.cx;
  1052. char_data->Buffer = BufferList[BufferList.Count () - 1] + CurrPixelOffset;
  1053. //
  1054. // Insert this character into our array
  1055. //
  1056. if ( ch < 256 ) {
  1057. ASCIICharArray[ch] = char_data;
  1058. } else {
  1059. UnicodeCharArray[ch - FirstUnicodeChar] = char_data;
  1060. }
  1061. //
  1062. // Advance the character position
  1063. //
  1064. CurrPixelOffset += (char_size.cx * CharHeight);
  1065. //
  1066. // Return the index of the entry we just added
  1067. //
  1068. return char_data;
  1069. }
  1070. ////////////////////////////////////////////////////////////////////////////////////
  1071. //
  1072. // Update_Current_Buffer
  1073. //
  1074. ////////////////////////////////////////////////////////////////////////////////////
  1075. void
  1076. FontCharsClass::Update_Current_Buffer (int char_width)
  1077. {
  1078. //
  1079. // Check to see if we need to allocate a new buffer
  1080. //
  1081. bool needs_new_buffer = (BufferList.Count () == 0);
  1082. if (needs_new_buffer == false) {
  1083. //
  1084. // Would we extend past this buffer?
  1085. //
  1086. if ( (CurrPixelOffset + (char_width * CharHeight)) > CHAR_BUFFER_LEN ) {
  1087. needs_new_buffer = true;
  1088. }
  1089. }
  1090. //
  1091. // Do we need to create a new surface?
  1092. //
  1093. if (needs_new_buffer) {
  1094. uint16 *new_buffer = new uint16[CHAR_BUFFER_LEN];
  1095. BufferList.Add( new_buffer );
  1096. CurrPixelOffset = 0;
  1097. }
  1098. return ;
  1099. }
  1100. ////////////////////////////////////////////////////////////////////////////////////
  1101. //
  1102. // Create_GDI_Font
  1103. //
  1104. ////////////////////////////////////////////////////////////////////////////////////
  1105. void
  1106. FontCharsClass::Create_GDI_Font (const char *font_name)
  1107. {
  1108. HDC screen_dc = ::GetDC (NULL);
  1109. //
  1110. // Calculate the height of the font in logical units
  1111. //
  1112. int font_height = -MulDiv (PointSize, ::GetDeviceCaps (screen_dc, LOGPIXELSY), 72);
  1113. //
  1114. // Create the Windows font
  1115. //
  1116. DWORD bold = IsBold ? FW_BOLD : FW_NORMAL;
  1117. DWORD italic = 0;
  1118. DWORD charset;
  1119. // Map the current code page to a font character set.
  1120. switch (GetACP()) {
  1121. // Chinese.
  1122. case 936:
  1123. case 950:
  1124. charset = CHINESEBIG5_CHARSET;
  1125. break;
  1126. // Japanese.
  1127. case 932:
  1128. charset = SHIFTJIS_CHARSET;
  1129. break;
  1130. // Korean.
  1131. case 949:
  1132. charset = HANGUL_CHARSET;
  1133. break;
  1134. // Anything else.
  1135. default:
  1136. charset = DEFAULT_CHARSET;
  1137. break;
  1138. }
  1139. GDIFont = ::CreateFont (font_height, 0, 0, 0, bold, italic,
  1140. FALSE, FALSE, charset, OUT_DEFAULT_PRECIS,
  1141. CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY,
  1142. VARIABLE_PITCH, font_name);
  1143. //
  1144. // Set-up the fields of the BITMAPINFOHEADER
  1145. // Note: Top-down DIBs use negative height in Win32.
  1146. //
  1147. BITMAPINFOHEADER bitmap_info = { 0 };
  1148. bitmap_info.biSize = sizeof (BITMAPINFOHEADER);
  1149. bitmap_info.biWidth = PointSize * 2;
  1150. bitmap_info.biHeight = -(PointSize * 2);
  1151. bitmap_info.biPlanes = 1;
  1152. bitmap_info.biBitCount = 24;
  1153. bitmap_info.biCompression = BI_RGB;
  1154. bitmap_info.biSizeImage = ((PointSize * PointSize * 4) * 3);
  1155. bitmap_info.biXPelsPerMeter = 0;
  1156. bitmap_info.biYPelsPerMeter = 0;
  1157. bitmap_info.biClrUsed = 0;
  1158. bitmap_info.biClrImportant = 0;
  1159. //
  1160. // Create a bitmap that we can access the bits directly of
  1161. //
  1162. GDIBitmap = ::CreateDIBSection ( screen_dc,
  1163. (const BITMAPINFO *)&bitmap_info,
  1164. DIB_RGB_COLORS,
  1165. (void **)&GDIBitmapBits,
  1166. NULL,
  1167. 0L);
  1168. //
  1169. // Create a device context we can select the font and bitmap into
  1170. //
  1171. MemDC = ::CreateCompatibleDC (NULL);
  1172. //
  1173. // Now select the BMP and font into the DC
  1174. //
  1175. OldGDIBitmap = (HBITMAP)::SelectObject (MemDC, GDIBitmap);
  1176. OldGDIFont = (HFONT)::SelectObject (MemDC, GDIFont);
  1177. ::SetBkColor (MemDC, RGB (0, 0, 0));
  1178. ::SetTextColor (MemDC, RGB (255, 255, 255));
  1179. //
  1180. // Lookup the pixel height of the font
  1181. //
  1182. TEXTMETRIC text_metric = { 0 };
  1183. ::GetTextMetrics (MemDC, &text_metric);
  1184. CharHeight = text_metric.tmHeight;
  1185. //
  1186. // Release our temporary screen DC
  1187. //
  1188. ::ReleaseDC (NULL, screen_dc);
  1189. return ;
  1190. }
  1191. ////////////////////////////////////////////////////////////////////////////////////
  1192. //
  1193. // Free_GDI_Font
  1194. //
  1195. ////////////////////////////////////////////////////////////////////////////////////
  1196. void
  1197. FontCharsClass::Free_GDI_Font (void)
  1198. {
  1199. //
  1200. // Select the old font back into the DC and delete
  1201. // our font object
  1202. //
  1203. if ( GDIFont != NULL ) {
  1204. ::SelectObject( MemDC, OldGDIFont );
  1205. ::DeleteObject( GDIFont );
  1206. GDIFont = NULL;
  1207. }
  1208. //
  1209. // Select the old bitmap back into the DC and delete
  1210. // our bitmap object
  1211. //
  1212. if ( GDIBitmap != NULL ) {
  1213. ::SelectObject( MemDC, OldGDIBitmap );
  1214. ::DeleteObject( GDIBitmap );
  1215. GDIBitmap = NULL;
  1216. }
  1217. //
  1218. // Delete our memory DC
  1219. //
  1220. if ( MemDC != NULL ) {
  1221. ::DeleteDC( MemDC );
  1222. MemDC = NULL;
  1223. }
  1224. return ;
  1225. }
  1226. ////////////////////////////////////////////////////////////////////////////////////
  1227. //
  1228. // Initialize_GDI_Font
  1229. //
  1230. ////////////////////////////////////////////////////////////////////////////////////
  1231. void
  1232. FontCharsClass::Initialize_GDI_Font (const char *font_name, int point_size, bool is_bold)
  1233. {
  1234. //
  1235. // Build a unique name from the font name and its size
  1236. //
  1237. Name.Format ("%s%d", font_name, point_size);
  1238. //
  1239. // Remember these settings
  1240. //
  1241. GDIFontName = font_name;
  1242. PointSize = point_size;
  1243. IsBold = is_bold;
  1244. //
  1245. // Create the actual font object
  1246. //
  1247. Create_GDI_Font (font_name);
  1248. return ;
  1249. }
  1250. ////////////////////////////////////////////////////////////////////////////////////
  1251. //
  1252. // Is_Font
  1253. //
  1254. ////////////////////////////////////////////////////////////////////////////////////
  1255. bool
  1256. FontCharsClass::Is_Font (const char *font_name, int point_size, bool is_bold)
  1257. {
  1258. bool retval = false;
  1259. //
  1260. // Check to see if both the name and height matches...
  1261. //
  1262. if ( (GDIFontName.Compare_No_Case (font_name) == 0) &&
  1263. (point_size == PointSize) &&
  1264. (is_bold == IsBold))
  1265. {
  1266. retval = true;
  1267. }
  1268. return retval;
  1269. }
  1270. ////////////////////////////////////////////////////////////////////////////////////
  1271. //
  1272. // Grow_Unicode_Array
  1273. //
  1274. ////////////////////////////////////////////////////////////////////////////////////
  1275. void
  1276. FontCharsClass::Grow_Unicode_Array (WCHAR ch)
  1277. {
  1278. //
  1279. // Don't do anything if character is in the ASCII range
  1280. //
  1281. if ( ch < 256 ) {
  1282. return ;
  1283. }
  1284. //
  1285. // Don't do anything if character is in the currently allocated range
  1286. //
  1287. if ( ch >= FirstUnicodeChar && ch <= LastUnicodeChar ) {
  1288. return ;
  1289. }
  1290. uint16 first_index = min( FirstUnicodeChar, ch );
  1291. uint16 last_index = max( LastUnicodeChar, ch );
  1292. uint16 count = (last_index - first_index) + 1;
  1293. //
  1294. // Allocate enough memory to hold the new cells
  1295. //
  1296. CharDataStruct **new_array = new CharDataStruct *[count];
  1297. ::memset (new_array, 0, sizeof (CharDataStruct *) * count);
  1298. //
  1299. // Copy the contents of the old array into the new array
  1300. //
  1301. if ( UnicodeCharArray != NULL ) {
  1302. int start_offset = (FirstUnicodeChar - first_index);
  1303. int old_count = (LastUnicodeChar - FirstUnicodeChar) + 1;
  1304. ::memcpy (&new_array[start_offset], UnicodeCharArray, sizeof (CharDataStruct *) * old_count);
  1305. //
  1306. // Delete the old array
  1307. //
  1308. delete [] UnicodeCharArray;
  1309. UnicodeCharArray = NULL;
  1310. }
  1311. FirstUnicodeChar = first_index;
  1312. LastUnicodeChar = last_index;
  1313. UnicodeCharArray = new_array;
  1314. return ;
  1315. }
  1316. ////////////////////////////////////////////////////////////////////////////////////
  1317. //
  1318. // Free_Character_Arrays
  1319. //
  1320. ////////////////////////////////////////////////////////////////////////////////////
  1321. void
  1322. FontCharsClass::Free_Character_Arrays (void)
  1323. {
  1324. if ( UnicodeCharArray != NULL ) {
  1325. int count = (LastUnicodeChar - FirstUnicodeChar) + 1;
  1326. //
  1327. // Delete each member of the unicode array
  1328. //
  1329. for (int index = 0; index < count; index ++) {
  1330. if ( UnicodeCharArray[index] != NULL ) {
  1331. delete UnicodeCharArray[index];
  1332. UnicodeCharArray[index] = NULL;
  1333. }
  1334. }
  1335. //
  1336. // Delete the array itself
  1337. //
  1338. delete [] UnicodeCharArray;
  1339. UnicodeCharArray = NULL;
  1340. }
  1341. //
  1342. // Delete each member of the ascii character array
  1343. //
  1344. for (int index = 0; index < 256; index ++) {
  1345. if ( ASCIICharArray[index] != NULL ) {
  1346. delete ASCIICharArray[index];
  1347. ASCIICharArray[index] = NULL;
  1348. }
  1349. }
  1350. return ;
  1351. }