| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795 |
- /*
- ** Command & Conquer Generals(tm)
- ** Copyright 2025 Electronic Arts Inc.
- **
- ** This program is free software: you can redistribute it and/or modify
- ** it under the terms of the GNU General Public License as published by
- ** the Free Software Foundation, either version 3 of the License, or
- ** (at your option) any later version.
- **
- ** This program is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ** GNU General Public License for more details.
- **
- ** You should have received a copy of the GNU General Public License
- ** along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- /***********************************************************************************************
- *** 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 ***
- ***********************************************************************************************
- * *
- * Project Name : WW3D *
- * *
- * $Archive:: /Commando/Code/ww3d2/render2dsentence.cpp $*
- * *
- * $Author:: Patrick $*
- * *
- * $Modtime:: 8/29/01 11:16a $*
- * *
- * $Revision:: 13 $*
- * *
- *---------------------------------------------------------------------------------------------*
- * Functions: *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- #include "render2dsentence.h"
- #include "surfaceclass.h"
- #include "texture.h"
- #include "wwprofile.h"
- #include "wwmemlog.h"
- #include "dx8wrapper.h"
- #ifdef _INTERNAL
- // for occasional debugging...
- //#pragma optimize("", off)
- //#pragma message("************************************** WARNING, optimization disabled for debugging purposes")
- #endif
- ////////////////////////////////////////////////////////////////////////////////////
- // Local constants
- ////////////////////////////////////////////////////////////////////////////////////
- #define no_TEST_PLACEMENT 1 // Shows alignment markers for text.
- #define TEXTURE_OFFSET 2
- ////////////////////////////////////////////////////////////////////////////////////
- //
- // Render2DSentenceClass
- //
- ////////////////////////////////////////////////////////////////////////////////////
- Render2DSentenceClass::Render2DSentenceClass (void) :
- Font (NULL),
- Location (0.0F,0.0F),
- Cursor (0.0F,0.0F),
- TextureOffset (0, 0),
- TextureStartX (0),
- CurSurface (NULL),
- CurrTextureSize (0),
- MonoSpaced (false),
- IsClippedEnabled (false),
- ClipRect (0, 0, 0, 0),
- BaseLocation (0, 0),
- LockedPtr (NULL),
- LockedStride (0),
- TextureSizeHint (0),
- WrapWidth (0),
- Centered (false),
- DrawExtents (0, 0, 0, 0),
- ParseHotKey( false ),
- useHardWordWrap( false)
- {
- Shader = Render2DClass::Get_Default_Shader ();
- return ;
- }
- ////////////////////////////////////////////////////////////////////////////////////
- //
- // ~Render2DSentenceClass
- //
- ////////////////////////////////////////////////////////////////////////////////////
- Render2DSentenceClass::~Render2DSentenceClass (void)
- {
- REF_PTR_RELEASE (Font);
- Reset ();
- return ;
- }
- ////////////////////////////////////////////////////////////////////////////////////
- //
- // Set_Font
- //
- ////////////////////////////////////////////////////////////////////////////////////
- void
- Render2DSentenceClass::Set_Font (FontCharsClass *font)
- {
- Reset ();
- REF_PTR_SET (Font, font);
- return ;
- }
- ////////////////////////////////////////////////////////////////////////////////////
- //
- // Reset_Polys
- //
- ////////////////////////////////////////////////////////////////////////////////////
- void
- Render2DSentenceClass::Reset_Polys (void)
- {
- for (int index = 0; index < Renderers.Count (); index ++) {
- Renderers[index].Renderer->Reset ();
- }
- return ;
- }
- ////////////////////////////////////////////////////////////////////////////////////
- //
- // Reset
- //
- ////////////////////////////////////////////////////////////////////////////////////
- void
- Render2DSentenceClass::Reset (void)
- {
- //
- // Make sure we unlock the current surface (if necessary)
- //
- if (LockedPtr != NULL) {
- CurSurface->Unlock ();
- LockedPtr = NULL;
- }
- //
- // Release our hold on the current surface
- //
- REF_PTR_RELEASE (CurSurface);
- //
- // Free each renderer
- //
- while (Renderers.Count () > 0) {
- delete Renderers[0].Renderer;
- Renderers.Delete(0);
- }
- Cursor.Set (0, 0);
- MonoSpaced = false;
- ParseHotKey = false;
- Release_Pending_Surfaces ();
- Reset_Sentence_Data ();
- return ;
- }
- ////////////////////////////////////////////////////////////////////////////////////
- //
- // Make_Additive
- //
- ////////////////////////////////////////////////////////////////////////////////////
- void
- Render2DSentenceClass::Make_Additive (void)
- {
- Shader.Set_Dst_Blend_Func (ShaderClass::DSTBLEND_ONE);
- Shader.Set_Src_Blend_Func (ShaderClass::SRCBLEND_ONE);
- Shader.Set_Primary_Gradient (ShaderClass::GRADIENT_MODULATE);
- Shader.Set_Secondary_Gradient (ShaderClass::SECONDARY_GRADIENT_DISABLE);
- Set_Shader (Shader);
- return ;
- }
- ////////////////////////////////////////////////////////////////////////////////////
- //
- // Make_Additive
- //
- ////////////////////////////////////////////////////////////////////////////////////
- void
- Render2DSentenceClass::Set_Shader (ShaderClass shader)
- {
- Shader = shader;
- //
- // Change each renderer's shader
- //
- for (int i = 0; i < Renderers.Count (); i ++) {
- ShaderClass *curr_shader = Renderers[i].Renderer->Get_Shader ();
- (*curr_shader) = Shader;
- }
- return ;
- }
- ////////////////////////////////////////////////////////////////////////////////////
- //
- // Render
- //
- ////////////////////////////////////////////////////////////////////////////////////
- void
- Render2DSentenceClass::Render (void)
- {
- //
- // Build any textures that are pending
- //
- Build_Textures ();
- //
- // Ask each renderer to draw its contents
- //
- for (int i = 0; i < Renderers.Count (); i ++) {
- Renderers[i].Renderer->Render ();
- }
- return ;
- }
- ////////////////////////////////////////////////////////////////////////////////////
- //
- // Set_Base_Location
- //
- ////////////////////////////////////////////////////////////////////////////////////
- void
- Render2DSentenceClass::Set_Base_Location (const Vector2 &loc)
- {
- Vector2 dif = loc - BaseLocation;
- BaseLocation = loc;
- for (int i = 0; i < Renderers.Count (); i ++) {
- Renderers[i].Renderer->Move (dif);
- }
- return ;
- }
- ////////////////////////////////////////////////////////////////////////////////////
- //
- // Set_Location
- //
- ////////////////////////////////////////////////////////////////////////////////////
- void
- Render2DSentenceClass::Set_Location (const Vector2 &loc)
- {
- Location = loc;
- return ;
- }
- ////////////////////////////////////////////////////////////////////////////////////
- //
- // Get_Text_Extents
- //
- ////////////////////////////////////////////////////////////////////////////////////
- Vector2
- Render2DSentenceClass::Get_Text_Extents (const WCHAR *text)
- {
- Vector2 extent (0, Font->Get_Char_Height());
- while (*text) {
- WCHAR ch = *text++;
- if ( ch != (WCHAR)'\n' ) {
- extent.X += Font->Get_Char_Spacing( ch );
- }
- }
- return extent;
- }
- ////////////////////////////////////////////////////////////////////////////////////
- //
- // Get_Formatted_Text_Extents
- //
- ////////////////////////////////////////////////////////////////////////////////////
- Vector2
- Render2DSentenceClass::Get_Formatted_Text_Extents (const WCHAR *text)
- {
- return Build_Sentence_Not_Centered(text, NULL, NULL, true);
- }
- ////////////////////////////////////////////////////////////////////////////////////
- //
- // Reset_Sentence_Data
- //
- ////////////////////////////////////////////////////////////////////////////////////
- void
- Render2DSentenceClass::Reset_Sentence_Data (void)
- {
- //
- // Release our hold on each texture used in the sentence
- //
- for (int index = 0; index < SentenceData.Count (); index ++) {
- REF_PTR_RELEASE (SentenceData[index].Surface);
- }
- if (SentenceData.Count()>0) {
- SentenceData.Delete_All ();
- }
- return ;
- }
- ////////////////////////////////////////////////////////////////////////////////////
- //
- // Release_Pending_Surfaces
- //
- ////////////////////////////////////////////////////////////////////////////////////
- void
- Render2DSentenceClass::Release_Pending_Surfaces (void)
- {
- //
- // Release our hold on each pending surface
- //
- for (int index = 0; index < PendingSurfaces.Count (); index ++) {
- SurfaceClass *curr_surface = PendingSurfaces[index].Surface;
- REF_PTR_RELEASE (curr_surface);
- }
- if (PendingSurfaces.Count()>0) PendingSurfaces.Delete_All ();
- return;
- }
- ////////////////////////////////////////////////////////////////////////////////////
- //
- // Build_Textures
- //
- ////////////////////////////////////////////////////////////////////////////////////
- void
- Render2DSentenceClass::Build_Textures (void)
- {
- WWMEMLOG(MEM_TEXTURE);
- //
- // Make sure we unlock the current surface
- //
- if (LockedPtr != NULL) {
- CurSurface->Unlock ();
- LockedPtr = NULL;
- }
-
- //
- // Release our hold on the current surface
- //
- REF_PTR_RELEASE (CurSurface);
- TextureOffset.Set (0, 0);
- TextureStartX = 0;
- //
- // Convert all pending surfaces to textures
- //
- for (int index = 0; index < PendingSurfaces.Count (); index ++) {
- PendingSurfaceStruct &surface_info = PendingSurfaces[index];
- SurfaceClass *curr_surface = surface_info.Surface;
- //
- // Get the dimensions of the surface
- //
- SurfaceClass::SurfaceDescription desc;
- curr_surface->Get_Description (desc);
-
- //
- // Create the new texture
- //
- TextureClass *new_texture = W3DNEW TextureClass (desc.Width, desc.Width, WW3D_FORMAT_A4R4G4B4, TextureClass::MIP_LEVELS_1);
- SurfaceClass *texture_surface = new_texture->Get_Surface_Level ();
- new_texture->Set_U_Addr_Mode(TextureClass::TEXTURE_ADDRESS_CLAMP);
- new_texture->Set_V_Addr_Mode(TextureClass::TEXTURE_ADDRESS_CLAMP);
- new_texture->Set_Min_Filter (TextureClass::FILTER_TYPE_NONE);
- new_texture->Set_Mag_Filter (TextureClass::FILTER_TYPE_NONE);
- new_texture->Set_Mip_Mapping (TextureClass::FILTER_TYPE_NONE);
- //
- // Copy the contents of the texture from the surface
- //
- DX8Wrapper::_Copy_DX8_Rects (curr_surface->Peek_D3D_Surface (), NULL, 0, texture_surface->Peek_D3D_Surface (), NULL);
- REF_PTR_RELEASE (texture_surface);
-
- //
- // Assign this texture to any renderers that need it
- //
- for (int renderer_index = 0; renderer_index < surface_info.Renderers.Count (); renderer_index ++) {
- Render2DClass *renderer = surface_info.Renderers[renderer_index];
- renderer->Set_Texture (new_texture);
- }
- //
- // Release our hold on the objects
- //
- REF_PTR_RELEASE (new_texture);
- REF_PTR_RELEASE (curr_surface);
- }
- //
- // Reset the list
- //
- if (PendingSurfaces.Count()>0) {
- PendingSurfaces.Delete_All ();
- }
- return ;
- }
- ////////////////////////////////////////////////////////////////////////////////////
- //
- // Draw_Sentence
- //
- ////////////////////////////////////////////////////////////////////////////////////
- void
- Render2DSentenceClass::Draw_Sentence (uint32 color)
- {
- Render2DClass *curr_renderer = NULL;
- SurfaceClass *curr_surface = NULL;
- DrawExtents.Set (0, 0, 0, 0);
- int offset = 0;
- //
- // Loop over all the parts of the sentence
- //
- for (int index = 0; index < SentenceData.Count (); index ++) {
- SentenceDataStruct &data = SentenceData[index];
- //
- // Has the surface changed?
- //
- if (data.Surface != curr_surface) {
- curr_surface = data.Surface;
- //
- // Try to find a renderer that uses the same "texture"
- //
- bool found = false;
- for (int renderer_index = 0; renderer_index < Renderers.Count (); renderer_index ++) {
- if (Renderers[renderer_index].Surface == curr_surface) {
- found = true;
- curr_renderer = Renderers[renderer_index].Renderer;
- break;
- }
- }
-
- //
- // Create a new renderer if we couldn't find an appropriate one
- //
- if (found == false) {
- //
- // Allocate a new renderer
- //
- curr_renderer = W3DNEW Render2DClass;
- curr_renderer->Set_Coordinate_Range (Render2DClass::Get_Screen_Resolution ());
- ShaderClass *curr_shader = curr_renderer->Get_Shader ();
- (*curr_shader) = Shader;
-
- //
- // Add it to our list
- //
- RendererDataStruct render_info;
- render_info.Renderer = curr_renderer;
- render_info.Surface = curr_surface;
- Renderers.Add (render_info);
- //
- // Now, add this renderer to the surface pending list
- //
- for (int surface_index = 0; surface_index < PendingSurfaces.Count (); surface_index ++) {
- PendingSurfaceStruct &surface_info = PendingSurfaces[surface_index];
- if (surface_info.Surface == curr_surface) {
- surface_info.Renderers.Add (curr_renderer);
- }
- }
- }
- }
- //
- // Get the dimensions of the surface
- //
- SurfaceClass::SurfaceDescription desc;
- curr_surface->Get_Description (desc);
- //
- // Add a quad that contains this sentence chunk
- //
- RectClass screen_rect = data.ScreenRect;
- screen_rect += Location;
- RectClass uv_rect = data.UVRect;
- //
- // Clip the quad (as necessary)
- //
- bool add_quad = true;
- if (IsClippedEnabled) {
-
- //
- // Check for completely clipped
- //
- if ( screen_rect.Right <= ClipRect.Left ||
- screen_rect.Bottom <= ClipRect.Top)
- {
- add_quad = false;
- } else {
- //
- // Clip the polygons to the specified area
- //
- RectClass clipped_rect;
- clipped_rect.Left = max (screen_rect.Left, ClipRect.Left);
- clipped_rect.Right = min (screen_rect.Right, ClipRect.Right);
- clipped_rect.Top = max (screen_rect.Top, ClipRect.Top);
- clipped_rect.Bottom = min (screen_rect.Bottom, ClipRect.Bottom);
- //
- // Clip the texture to the specified area
- //
- RectClass clipped_uv_rect;
- float percent = ((clipped_rect.Left - screen_rect.Left) / screen_rect.Width ());
- clipped_uv_rect.Left = uv_rect.Left + (uv_rect.Width () * percent);
- percent = ((clipped_rect.Right - screen_rect.Left) / screen_rect.Width ());
- clipped_uv_rect.Right = uv_rect.Left + (uv_rect.Width () * percent);
- percent = ((clipped_rect.Top - screen_rect.Top) / screen_rect.Height ());
- clipped_uv_rect.Top = uv_rect.Top + (uv_rect.Height () * percent);
- percent = ((clipped_rect.Bottom - screen_rect.Top) / screen_rect.Height ());
- clipped_uv_rect.Bottom = uv_rect.Top + (uv_rect.Height () * percent);
- //
- // Use the clipped rectangles to render
- //
- screen_rect = clipped_rect;
- uv_rect = clipped_uv_rect;
- if (screen_rect.Right <= screen_rect.Left ||
- screen_rect.Bottom <= screen_rect.Top)
- {
- add_quad = false;
- }
- }
- }
- if (add_quad) {
- //uv_rect.Bottom += 0.5f;
- uv_rect *= 1.0F / ((float)desc.Width);
- #ifdef TEST_PLACEMENT
- screen_rect.Left += offset*3;
- screen_rect.Right += offset*3;
- #endif
- offset++;
- curr_renderer->Add_Quad (screen_rect, uv_rect, color);
- //
- // Add this rectangle to the total draw extents
- //
- if (DrawExtents.Width () == 0) {
- DrawExtents = screen_rect;
- } else {
- DrawExtents += screen_rect;
- }
- }
- }
- return ;
- }
- ////////////////////////////////////////////////////////////////////////////////////
- //
- // Record_Sentence_Chunk
- //
- ////////////////////////////////////////////////////////////////////////////////////
- void
- Render2DSentenceClass::Record_Sentence_Chunk (void)
- {
- //
- // Do we have anything to store?
- //
- int width = TextureOffset.I - TextureStartX;
- if (width > 0) {
- float char_height = Font->Get_Char_Height ();
-
- //
- // Build a structure that contains enough information
- // to hold this portion of the sentence
- //
- SentenceDataStruct sentence_data;
- sentence_data.Surface = CurSurface;
- sentence_data.Surface->Add_Ref ();
- sentence_data.ScreenRect.Left = Cursor.X;
- sentence_data.ScreenRect.Right = Cursor.X + width;
- sentence_data.ScreenRect.Top = Cursor.Y;
- sentence_data.ScreenRect.Bottom = Cursor.Y + char_height;
- sentence_data.UVRect.Left = TextureStartX;
- sentence_data.UVRect.Top = TextureOffset.J;
- sentence_data.UVRect.Right = TextureOffset.I;
- sentence_data.UVRect.Bottom = TextureOffset.J + char_height;
- //
- // Add this information to our list
- //
- SentenceData.Add (sentence_data);
- }
- return ;
- }
- ////////////////////////////////////////////////////////////////////////////////////
- //
- // Allocate_New_Surface
- //
- ////////////////////////////////////////////////////////////////////////////////////
- void
- Render2DSentenceClass::Allocate_New_Surface (const WCHAR *text, bool justCalcExtents)
- {
- if (!justCalcExtents)
- {
- //
- // Unlock the last surface (if necessary)
- //
- if (LockedPtr != NULL) {
- CurSurface->Unlock ();
- LockedPtr = NULL;
- }
- }
- //
- // Calculate the width of the text
- //
- int text_width = 0;
- for (int index = 0; text[index] != 0; index ++) {
- text_width += Font->Get_Char_Spacing (text[index]);
- }
-
- int char_height = Font->Get_Char_Height ();
- //
- // Find the best texture size for the remaining text
- //
- CurrTextureSize = 256;
- int best_tex_mem_usage = 999999999;
- for (int pow2 = 6; pow2 <= 8; pow2 ++) {
-
- int size = 1 << pow2;
- int row_count = (text_width / size) + 1;
- int rows_per_texture = size / (char_height + 1);
-
- //
- // Can we even fit one character on this texture?
- //
- if (rows_per_texture > 0) {
- //
- // How many textures (at this size) would it take to render
- // the remaining text?
- //
- int texture_count = row_count / rows_per_texture;
- texture_count = max (texture_count, 1);
- //
- // Is this the best usage of texture memory we've found yet?
- //
- int texture_mem_usage = (texture_count * size * size);
- if (texture_mem_usage < best_tex_mem_usage) {
- CurrTextureSize = size;
- best_tex_mem_usage = texture_mem_usage;
- }
- }
- }
- //
- // Use whichever is larger, the hint or the calculated size
- //
- CurrTextureSize = max (TextureSizeHint, CurrTextureSize);
- if (!justCalcExtents)
- {
- //
- // Release our extra hold on the old surface
- //
- REF_PTR_RELEASE (CurSurface);
- //
- // Create the new surface
- //
- CurSurface = NEW_REF (SurfaceClass, (CurrTextureSize, CurrTextureSize, WW3D_FORMAT_A4R4G4B4));
- WWASSERT (CurSurface != NULL);
- CurSurface->Add_Ref ();
- //
- // Add this surface to our list
- //
- PendingSurfaceStruct surface_info;
- surface_info.Surface = CurSurface;
- PendingSurfaces.Add (surface_info);
- }
- //
- // Reset to the upper left corner
- //
- TextureOffset.Set (0, 0);
- TextureStartX = 0;
- return ;
- }
- float FindStartingXPos( const WCHAR *text )
- {
- return 1;
- }
- ////////////////////////////////////////////////////////////////////////////////////
- //
- // Build_Sentence_Centered
- //
- ////////////////////////////////////////////////////////////////////////////////////
- void Render2DSentenceClass::Build_Sentence_Centered (const WCHAR *text, int *hkX, int *hkY)
- {
- float char_height = Font->Get_Char_Height ();
- int wordWidth = 0;
- int notCenteredHotkeyX = 0;
- int notCenteredHotkeyY = 0;
- Vector2 extent = Build_Sentence_Not_Centered(text,¬CenteredHotkeyX, ¬CenteredHotkeyY, TRUE); //Get_Formatted_Text_Extents(text);
-
- //
- // Start fresh
- //
- Reset_Sentence_Data ();
- Cursor.Set (0, 0);
-
- //
- // Ensure we have a surface to start with
- //
- if (CurSurface == NULL) {
- Allocate_New_Surface (text);
- }
-
-
-
- //
- // Loop over all the characters in the string
- //
- bool end = false;
- const WCHAR *word;
- int word_width = 0;
- int line_width = 0;
- int charCount = 0;
- int wordCount = 0;
- int hotKeyPosX = 0;
- int hotKeyPosY = 0;
- bool calcHotKeyX = false;
- bool dontBlit = false;
- while (!end)
- {
- //
- // Re-init everything for the next line
- //
- word = text;
- word_width = 0;
- line_width = 0;
- charCount = 0;
- wordCount = 0;
- //
- //first find the length of the line till we wrap
- //
- while ( 1 )
- {
- //
- // read a word
- //
- int charWidth = 0;
- while ((*word != 0) && (*word > L' ') && (*word != L'\n')) {
- if( ParseHotKey && (*word == L'&') && (*word+1 != 0) && (*word+1 > L' ') && (*word+1 != L'\n'))
- {
- int offset = 0;
- //Added By Saad
- if (word_width != 0 )
- {
- const WCHAR *word_back = word;
- *word_back--;
- if (*word_back == L' ')
- {
- line_width -= word_width;
- offset =-1;
- }
- }
- //
- *word++;
- calcHotKeyX = true;
- }
-
- charWidth = Font->Get_Char_Spacing (*word++);
- word_width += charWidth;
- wordCount++;
-
- if (WrapWidth > 0 && word_width >= WrapWidth && useHardWordWrap)
- break;
- }
- //
- // If this word is unworthy to be on the current line, decrement the space and break
- //
- if(WrapWidth > 0 && (line_width + word_width >= WrapWidth))
- {
- //
- //Take care of the case that the word is too big for the allocated space...
- //If that's the case, drop out and process the word anyway
- //
- if(charCount == 0)
- {
- charCount +=wordCount - 1;
- line_width += word_width - charWidth;
- if(*word == 0)
- end = true;
- break;
- }
- charCount--;
- break;
- }
- //
- // if we reached the end of the text, set the values and break, also set the end flag
- //
- if( *word == 0 )
- {
- charCount +=wordCount;
- line_width += word_width;
- end = true;
- break;
- }
- //
- // otherwise, increment the counts
- //
- charCount +=wordCount + 1;
- line_width += word_width;
- //
- // We were some a new line character break and process
- //
- if(*word != L' ')
- break;
- //
- // add the space to our width
- //
- word_width = Font->Get_Char_Spacing (*word++);
- wordCount = 0;
- //Added By Saad
- line_width += word_width;
- }
- //
- // we now hold the length of the line and it's width lets set our cursor position to center it
- //
- Cursor.X = (int)((extent.X - line_width) / 2);
- if(Cursor.X < 0)
- Cursor.X = 0;
- if(calcHotKeyX)
- {
- calcHotKeyX = false;
- hotKeyPosX = Cursor.X + notCenteredHotkeyX;
- }
-
- for(int i = 0; i <= charCount; i++) {
- WCHAR ch = *text++;
- dontBlit = false;
- //
- // Determine how much horizontal space this character requires
- //
- if(ParseHotKey && (ch == L'&') && (*text != 0) && (*text > L' ') && (*text != L'\n'))
- {
- ch = *text++;
- dontBlit = true;
- }
- float char_spacing = Font->Get_Char_Spacing (ch);
-
- bool exceeded_texture_width = ((TextureOffset.I + char_spacing) >= CurrTextureSize);
- bool encountered_break_char = (ch == L' ' || ch == L'\n' || ch == 0);
-
- //
- // Do we need to record this portion of the sentence to its own chunk?
- //
- if (exceeded_texture_width || encountered_break_char) {
- Record_Sentence_Chunk ();
-
- //
- // Adjust the positions
- //
- Cursor.X += (TextureOffset.I - TextureStartX);
- TextureStartX = TextureOffset.I;
-
- //
- // Adjust the output coordinates
- //
- if (ch == L' ') {
- Cursor.X += char_spacing;
- } else if ((ch == 0 )|| (ch == L'\n')) {
- break;
- }
-
- //
- // Did the text extend past the edge of the texture?
- //
- if (exceeded_texture_width) {
- TextureStartX = 0;
- TextureOffset.I = TextureStartX;
- TextureOffset.J += char_height;
-
- //
- // Did the text extent completely off the texture?
- //
- if ((TextureOffset.J + char_height) >= CurrTextureSize) {
- Allocate_New_Surface (text);
- }
- }
- }
- //
- // Adjust the output coordinates
- //
- if (ch != L'\n' && ch != L' ') {
-
- //
- // Ensure the surface is locked
- //
- if (LockedPtr == NULL) {
- LockedPtr = (uint16 *)CurSurface->Lock (&LockedStride);
- WWASSERT (LockedPtr != NULL);
- }
-
- //
- // Check to ensure the text will fit on this texture
- //
- WWASSERT (((TextureOffset.I + char_spacing) < CurrTextureSize) && ((TextureOffset.J + char_height) < CurrTextureSize));
-
- //
- // Blit the character to the surface
- //
- if(!dontBlit)
- Font->Blit_Char (ch, LockedPtr, LockedStride, TextureOffset.I, TextureOffset.J);
-
- if (dontBlit) {
- // we don't blit for a hot key character. So add extra spacing.
- char_spacing += Font->Get_Extra_Overlap();
- // Brutal hack #27 Gamma - Bolded M's are just a problem. jba.
- if (ch=='M') {
- char_spacing++;
- }
- }
-
- TextureOffset.I += char_spacing;
- }
- }
- //
- // reset our cursor and add a line of text to the cursor position
- //
- Cursor.X = 0;
- Cursor.Y += char_height;
- line_width = 0;
- }
-
- if(hkX)
- *hkX = hotKeyPosX;
- if(hkX)
- *hkY = hotKeyPosY;
- return ;
- }
- ////////////////////////////////////////////////////////////////////////////////////
- //
- // Build_Sentence_NotCentered
- //
- ////////////////////////////////////////////////////////////////////////////////////
- Vector2 Render2DSentenceClass::Build_Sentence_Not_Centered (const WCHAR *text, int *hkX, int *hkY, bool justCalcExtents)
- {
- Vector2 cursor = Cursor;
- int textureStartX = TextureStartX;
- float maxX = 0;
- int hotKeyPosX = 0;
- int hotKeyPosY = 0;
- bool calcHotKeyX = false;
- bool dontBlit = false;
- Vector2i textureOffset = TextureOffset;
- //
- // Start fresh
- //
- if (!justCalcExtents)
- {
- Reset_Sentence_Data ();
- }
- Cursor.Set (0, 0);
- //
- // Ensure we have a surface to start with
- //
- if (CurSurface == NULL) {
- Allocate_New_Surface (text, justCalcExtents);
- }
- TextureOffset.Set (TEXTURE_OFFSET, 0);
- TextureStartX = TEXTURE_OFFSET;
- float char_height = Font->Get_Char_Height ();
- //
- // Loop over all the characters in the string
- //
- while (text != NULL) {
- WCHAR ch = *text++;
- dontBlit = false;
- //
- // Determine how much horizontal space this character requires
- //
- if(ParseHotKey && (ch == L'&') && (*text != 0) && (*text > L' ') && (*text != L'\n'))
- {
- hotKeyPosY = Cursor.Y;
- if (calcHotKeyX)
- hotKeyPosX = 0;
- else
- hotKeyPosX = Cursor.X + TextureOffset.I -TextureStartX;//TextureOffset.I;
- ch = *text++;
- dontBlit = true;
- }
- float char_spacing = Font->Get_Char_Spacing (ch);
- bool exceeded_texture_width = ((TextureOffset.I + char_spacing) >= CurrTextureSize);
- bool encountered_break_char = (ch == L' ' || ch == L'\n' || ch == 0);
- bool wordBiggerThenLine = ((useHardWordWrap) && ( WrapWidth != 0 ) &&((Cursor.X + TextureOffset.I -TextureStartX + char_spacing) >= WrapWidth));
- //
- // Do we need to record this portion of the sentence to its own chunk?
- //
- if (exceeded_texture_width || encountered_break_char|| wordBiggerThenLine) {
- if (!justCalcExtents)
- {
- Record_Sentence_Chunk ();
- }
- //
- // Adjust the positions
- //
- Cursor.X += (TextureOffset.I - TextureStartX);
- maxX = max(maxX, Cursor.X);
- TextureStartX = TextureOffset.I;
- //
- // Adjust the output coordinates
- //
- if (ch == L' ') {
- //Cursor.X += char_spacing;
- //maxX = max(maxX, Cursor.X);
- //
- // Check to see if we need to wrap on this word-break
- //
- if (WrapWidth > 0) {
-
- //
- // Find the length of the next word
- //
- const WCHAR *word = text;
- float word_width = char_spacing;
- while ((*word != 0) && (*word > L' ')) {
- if(ParseHotKey && (*word == L'&') && (*word+1 != 0) && (*word+1 > L' ') && (*word+1 != L'\n'))
- *word++;
- word_width += Font->Get_Char_Spacing (*word++);
- }
- //
- // Should we wrap the next word?
- //
- if ((Cursor.X + word_width) >= WrapWidth) {
- Cursor.X = 0;
- Cursor.Y += char_height;
- calcHotKeyX = true;
- }
- }
- } else if (ch == L'\n') {
- Cursor.X = 0;
- Cursor.Y += char_height;
- } else if (ch == 0) {
- break;
- } else if (wordBiggerThenLine){ // we've entered this loop because we're greater then the wordwrap so we need to force a wordwrap
- Cursor.X = 0;
- Cursor.Y += char_height;
- }
-
- //
- // Did the text extend past the edge of the texture?
- //
- if (exceeded_texture_width) {
- TextureStartX = TEXTURE_OFFSET;
- TextureOffset.I = TextureStartX;
- TextureOffset.J += char_height;
- //
- // Did the text extent completely off the texture?
- //
- if ((TextureOffset.J + char_height) >= CurrTextureSize) {
- Allocate_New_Surface (text, justCalcExtents);
- }
- }
- }
-
- if (ch != L'\n' ) {
- //
- // Ensure the surface is locked
- //
- if (!justCalcExtents)
- {
- if (LockedPtr == NULL) {
- LockedPtr = (uint16 *)CurSurface->Lock (&LockedStride);
- WWASSERT (LockedPtr != NULL);
- }
- }
- //
- // Check to ensure the text will fit on this texture
- //
- WWASSERT (((TextureOffset.I + char_spacing) < CurrTextureSize) && ((TextureOffset.J + char_height) < CurrTextureSize));
- //
- // Blit the character to the surface
- //
- if (!justCalcExtents && !dontBlit )
- {
- Font->Blit_Char (ch, LockedPtr, LockedStride, TextureOffset.I, TextureOffset.J);
- }
- TextureOffset.I += char_spacing;
- }
- }
- Vector2 extent;
- extent.X = maxX + Font->Get_Extra_Overlap();
- extent.Y = Cursor.Y + char_height;
- Cursor = cursor;
- TextureOffset = textureOffset;
- TextureStartX = textureStartX;
-
- if(hkX)
- *hkX = hotKeyPosX;
- if(hkX)
- *hkY = hotKeyPosY;
- return extent;
- }
- ////////////////////////////////////////////////////////////////////////////////////
- //
- // Build_Sentence
- //
- ////////////////////////////////////////////////////////////////////////////////////
- void
- Render2DSentenceClass::Build_Sentence (const WCHAR *text, int *hkX, int *hkY)
- {
- if (text == NULL) {
- return ;
- }
- if(Centered && (WrapWidth > 0 || wcschr(text,L'\n')))
- Build_Sentence_Centered(text, hkX, hkY);
- else
- Build_Sentence_Not_Centered(text, hkX, hkY);
-
- return;
-
- }
- ////////////////////////////////////////////////////////////////////////////////////
- //
- // FontCharsClass
- //
- ////////////////////////////////////////////////////////////////////////////////////
- FontCharsClass::FontCharsClass (void) :
- OldGDIFont( NULL ),
- OldGDIBitmap( NULL ),
- GDIFont( NULL ),
- GDIBitmap( NULL ),
- GDIBitmapBits ( NULL ),
- MemDC( NULL ),
- CurrPixelOffset( 0 ),
- PointSize( 0 ),
- CharHeight( 0 ),
- UnicodeCharArray( NULL ),
- FirstUnicodeChar( 0xFFFF ),
- LastUnicodeChar( 0 ),
- IsBold (false)
- {
- AlternateUnicodeFont = NULL;
- ::memset( ASCIICharArray, 0, sizeof (ASCIICharArray) );
- return ;
- }
- ////////////////////////////////////////////////////////////////////////////////////
- //
- // ~FontCharsClass
- //
- ////////////////////////////////////////////////////////////////////////////////////
- FontCharsClass::~FontCharsClass (void)
- {
- while ( BufferList.Count() ) {
- delete [] BufferList[0];
- BufferList.Delete(0);
- }
- Free_GDI_Font();
- Free_Character_Arrays();
- return ;
- }
- ////////////////////////////////////////////////////////////////////////////////////
- //
- // Get_Char_Data
- //
- ////////////////////////////////////////////////////////////////////////////////////
- const FontCharsClassCharDataStruct *
- FontCharsClass::Get_Char_Data (WCHAR ch)
- {
- const FontCharsClassCharDataStruct *retval = NULL;
- if ( ch < 256 )
- {
- retval = ASCIICharArray[ch];
- }
- else if ( AlternateUnicodeFont && this != AlternateUnicodeFont )
- {
- return AlternateUnicodeFont->Get_Char_Data( ch );
- }
- else
- {
- Grow_Unicode_Array( ch );
- retval = UnicodeCharArray[ch - FirstUnicodeChar];
- }
- //
- // If the character wasn't found, then add it to our list
- //
- if ( retval == NULL ) {
- retval = Store_GDI_Char( ch );
- }
- WWASSERT( retval->Value == ch );
- return retval;
- }
- ////////////////////////////////////////////////////////////////////////////////////
- //
- // Get_Char_Width
- //
- ////////////////////////////////////////////////////////////////////////////////////
- int
- FontCharsClass::Get_Char_Width (WCHAR ch)
- {
- const FontCharsClassCharDataStruct * data = Get_Char_Data( ch );
- if ( data != NULL ) {
- return data->Width;
- }
- return 0;
- }
- ////////////////////////////////////////////////////////////////////////////////////
- //
- // Get_Char_Spacing
- //
- ////////////////////////////////////////////////////////////////////////////////////
- int
- FontCharsClass::Get_Char_Spacing (WCHAR ch)
- {
- const FontCharsClassCharDataStruct * data = Get_Char_Data( ch );
- if ( data != NULL ) {
- if ( data->Width != 0 ) {
- return data->Width - PixelOverlap - CharOverhang;
- }
- }
- return 0;
- }
- ////////////////////////////////////////////////////////////////////////////////////
- //
- // Blit_Char
- //
- ////////////////////////////////////////////////////////////////////////////////////
- void
- FontCharsClass::Blit_Char (WCHAR ch, uint16 *dest_ptr, int dest_stride, int x, int y)
- {
- const FontCharsClassCharDataStruct * data = Get_Char_Data( ch );
- if ( data != NULL && data->Width != 0 ) {
- //
- // Setup the src and destination pointers
- //
- int dest_inc = (dest_stride >> 1);
- uint16 *src_ptr = data->Buffer;
- dest_ptr += (dest_inc * y) + x;
- //
- // Simply copy the data from the src buffer to the destination
- //
- for ( int row = 0; row < CharHeight; row ++ ) {
- for ( int col = 0; col < data->Width; col ++ ) {
- uint16 curData = *src_ptr;
- if (col<PixelOverlap) {
- curData |= dest_ptr[col];
- }
- dest_ptr[col] = curData;
- src_ptr++;
- }
- dest_ptr += dest_inc;
- }
- }
- return ;
- }
- ////////////////////////////////////////////////////////////////////////////////////
- //
- // Store_GDI_Char
- //
- ////////////////////////////////////////////////////////////////////////////////////
- const FontCharsClassCharDataStruct *
- FontCharsClass::Store_GDI_Char (WCHAR ch)
- {
- int width = PointSize * 2;
- int height = PointSize * 2;
- //
- // Draw the character into the memory DC
- //
- RECT rect = { 0, 0, width, height };
- int xOrigin = 0;
- if (ch == 'W') {
- xOrigin = 1;
- }
- ::ExtTextOutW( MemDC, xOrigin, 0, ETO_OPAQUE, &rect, &ch, 1, NULL);
- //
- // Get the size of the character we just drew
- //
- SIZE char_size = { 0 };
- ::GetTextExtentPoint32W( MemDC, &ch, 1, &char_size );
- char_size.cx += PixelOverlap + xOrigin;
- //
- // Get a pointer to the surface that this character should use
- //
- Update_Current_Buffer( char_size.cx );
- uint16* curr_buffer_p = BufferList[BufferList.Count () - 1]->Buffer;
- curr_buffer_p += CurrPixelOffset;
-
- //
- // Copy the BMP contents to the buffer
- //
- int stride = (((width * 3) + 3) & ~3);
- for (int row = 0; row < char_size.cy; row ++) {
-
- //
- // Compute the indices into the BMP and surface
- //
- int index = (row * stride);
- //
- // Loop over each column
- //
- for (int col = 0; col < char_size.cx; col ++) {
-
- //
- // Get the pixel color at this location
- //
- uint8 pixel_value = GDIBitmapBits[index];
- index += 3;
- #ifdef TEST_PLACEMENT
- if (row==CharHeight-1&&col==0) {
- pixel_value = 0xff;
- }
- if (row==CharHeight-2&&col==1) {
- pixel_value = 0xff;
- }
- if (row==0&&col==0) {
- pixel_value = 0xff;
- }
- if (row==1&&col==1) {
- pixel_value = 0xff;
- }
- if (row==CharHeight-1&&col==char_size.cx-1-PixelOverlap) {
- pixel_value = 0xff;
- }
- if (row==CharHeight-2&&col==char_size.cx-2-PixelOverlap) {
- pixel_value = 0xff;
- }
- if (row==0&&col==char_size.cx-1-PixelOverlap) {
- pixel_value = 0xff;
- }
- if (row==1&&col==char_size.cx-2-PixelOverlap) {
- pixel_value = 0xff;
- }
- if (pixel_value == 0x00) {
- pixel_value = 0x40;
- }
- #endif
- uint16 pixel_color = 0;
- if (pixel_value != 0) {
- pixel_color = 0x0FFF;
- }
-
- //
- // Convert the pixel intensity from 8bit to 4bit and
- // store it in our buffer
- //
- uint8 alpha_value = ((pixel_value >> 4) & 0xF);
- *curr_buffer_p++ = pixel_color | (alpha_value << 12);
- }
- }
- //
- // Save information about this character in our list
- //
- FontCharsClassCharDataStruct *char_data = W3DNEW FontCharsClassCharDataStruct;
- char_data->Value = ch;
- char_data->Width = char_size.cx;
- char_data->Buffer = BufferList[BufferList.Count () - 1]->Buffer + CurrPixelOffset;
- //
- // Insert this character into our array
- //
- if ( ch < 256 ) {
- ASCIICharArray[ch] = char_data;
- } else {
- UnicodeCharArray[ch - FirstUnicodeChar] = char_data;
- }
- //
- // Advance the character position
- //
- CurrPixelOffset += ((char_size.cx+PixelOverlap) * CharHeight);
- //
- // Return the index of the entry we just added
- //
- return char_data;
- }
- ////////////////////////////////////////////////////////////////////////////////////
- //
- // Update_Current_Buffer
- //
- ////////////////////////////////////////////////////////////////////////////////////
- void
- FontCharsClass::Update_Current_Buffer (int char_width)
- {
- //
- // Check to see if we need to allocate a new buffer
- //
- bool needs_new_buffer = (BufferList.Count () == 0);
- if (needs_new_buffer == false) {
-
- //
- // Would we extend past this buffer?
- //
- if ( (CurrPixelOffset + (char_width * CharHeight)) > CHAR_BUFFER_LEN ) {
- needs_new_buffer = true;
- }
- }
- //
- // Do we need to create a new surface?
- //
- if (needs_new_buffer)
- {
- FontCharsBuffer* new_buffer = W3DNEW FontCharsBuffer;
- BufferList.Add( new_buffer );
- CurrPixelOffset = 0;
- }
- return ;
- }
- ////////////////////////////////////////////////////////////////////////////////////
- //
- // Create_GDI_Font
- //
- ////////////////////////////////////////////////////////////////////////////////////
- void
- FontCharsClass::Create_GDI_Font (const char *font_name)
- {
- HDC screen_dc = ::GetDC ((HWND)WW3D::Get_Window());
- const char *fontToUseForGenerals = "Arial";
- bool doingGenerals = false;
- if (strcmp(font_name, "Generals")==0) {
- font_name = fontToUseForGenerals;
- doingGenerals = true;
- }
- //
- // Calculate the height of the font in logical units
- //
- const int dotsPerInch = 96; // always use 96. jba.
- int font_height = -MulDiv (PointSize, dotsPerInch, 72);
- int fontWidth = 0; // use font default.
- if (doingGenerals) {
- //fontWidth = -font_height*0.35f; //2 pixels tighter.
- fontWidth = -font_height*0.40f; // one pixel tighter
- }
- PixelOverlap = (-font_height)/8;
- // Sanity check in case of perversion. :)
- if (PixelOverlap<0) PixelOverlap = 0;
- if (PixelOverlap>4) PixelOverlap = 4;
- //
- // Create the Windows font
- //
- DWORD bold = IsBold ? FW_BOLD : FW_NORMAL;
- DWORD italic = 0;
- GDIFont = ::CreateFont (font_height, fontWidth, 0, 0, bold, italic,
- FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
- CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY,
- VARIABLE_PITCH, font_name);
-
- //
- // Set-up the fields of the BITMAPINFOHEADER
- // Note: Top-down DIBs use negative height in Win32.
- //
- BITMAPINFOHEADER bitmap_info = { 0 };
- bitmap_info.biSize = sizeof (BITMAPINFOHEADER);
- bitmap_info.biWidth = PointSize * 2;
- bitmap_info.biHeight = -(PointSize * 2);
- bitmap_info.biPlanes = 1;
- bitmap_info.biBitCount = 24;
- bitmap_info.biCompression = BI_RGB;
- bitmap_info.biSizeImage = ((PointSize * PointSize * 4) * 3);
- bitmap_info.biXPelsPerMeter = 0;
- bitmap_info.biYPelsPerMeter = 0;
- bitmap_info.biClrUsed = 0;
- bitmap_info.biClrImportant = 0;
- //
- // Create a bitmap that we can access the bits directly of
- //
- GDIBitmap = ::CreateDIBSection ( screen_dc,
- (const BITMAPINFO *)&bitmap_info,
- DIB_RGB_COLORS,
- (void **)&GDIBitmapBits,
- NULL,
- 0L);
- //
- // Create a device context we can select the font and bitmap into
- //
- MemDC = ::CreateCompatibleDC (screen_dc);
- //
- // Release our temporary screen DC
- //
- ::ReleaseDC ((HWND)WW3D::Get_Window(), screen_dc);
- //
- // Now select the BMP and font into the DC
- //
- OldGDIBitmap = (HBITMAP)::SelectObject (MemDC, GDIBitmap);
- OldGDIFont = (HFONT)::SelectObject (MemDC, GDIFont);
- ::SetBkColor (MemDC, RGB (0, 0, 0));
- ::SetTextColor (MemDC, RGB (255, 255, 255));
- //
- // Lookup the pixel height of the font
- //
- TEXTMETRIC text_metric = { 0 };
- ::GetTextMetrics (MemDC, &text_metric);
- CharHeight = text_metric.tmHeight;
- CharAscent = text_metric.tmAscent;
- CharOverhang = text_metric.tmOverhang;
- if (doingGenerals) {
- CharOverhang = 0;
- }
- }
- ////////////////////////////////////////////////////////////////////////////////////
- //
- // Free_GDI_Font
- //
- ////////////////////////////////////////////////////////////////////////////////////
- void
- FontCharsClass::Free_GDI_Font (void)
- {
- //
- // Select the old font back into the DC and delete
- // our font object
- //
- if ( GDIFont != NULL ) {
- ::SelectObject( MemDC, OldGDIFont );
- ::DeleteObject( GDIFont );
- GDIFont = NULL;
- }
- //
- // Select the old bitmap back into the DC and delete
- // our bitmap object
- //
- if ( GDIBitmap != NULL ) {
- ::SelectObject( MemDC, OldGDIBitmap );
- ::DeleteObject( GDIBitmap );
- GDIBitmap = NULL;
- }
- //
- // Delete our memory DC
- //
- if ( MemDC != NULL ) {
- ::DeleteDC( MemDC );
- MemDC = NULL;
- }
- return ;
- }
- ////////////////////////////////////////////////////////////////////////////////////
- //
- // Initialize_GDI_Font
- //
- ////////////////////////////////////////////////////////////////////////////////////
- void
- FontCharsClass::Initialize_GDI_Font (const char *font_name, int point_size, bool is_bold)
- {
- //
- // Build a unique name from the font name and its size
- //
- Name.Format ("%s%d", font_name, point_size);
- //
- // Remember these settings
- //
- GDIFontName = font_name;
- PointSize = point_size;
- IsBold = is_bold;
- //
- // Create the actual font object
- //
- Create_GDI_Font (font_name);
- return ;
- }
- ////////////////////////////////////////////////////////////////////////////////////
- //
- // Is_Font
- //
- ////////////////////////////////////////////////////////////////////////////////////
- bool
- FontCharsClass::Is_Font (const char *font_name, int point_size, bool is_bold)
- {
- bool retval = false;
- //
- // Check to see if both the name and height matches...
- //
- if ( (GDIFontName.Compare_No_Case (font_name) == 0) &&
- (point_size == PointSize) &&
- (is_bold == IsBold))
- {
- retval = true;
- }
- return retval;
- }
- ////////////////////////////////////////////////////////////////////////////////////
- //
- // Grow_Unicode_Array
- //
- ////////////////////////////////////////////////////////////////////////////////////
- void
- FontCharsClass::Grow_Unicode_Array (WCHAR ch)
- {
- //
- // Don't do anything if character is in the ASCII range
- //
- if ( ch < 256 ) {
- return ;
- }
- //
- // Don't do anything if character is in the currently allocated range
- //
- if ( ch >= FirstUnicodeChar && ch <= LastUnicodeChar ) {
- return ;
- }
- uint16 first_index = min( FirstUnicodeChar, ch );
- uint16 last_index = max( LastUnicodeChar, ch );
- uint16 count = (last_index - first_index) + 1;
- //
- // Allocate enough memory to hold the new cells
- //
- FontCharsClassCharDataStruct **new_array = W3DNEWARRAY FontCharsClassCharDataStruct *[count];
- ::memset (new_array, 0, sizeof (FontCharsClassCharDataStruct *) * count);
- //
- // Copy the contents of the old array into the new array
- //
- if ( UnicodeCharArray != NULL ) {
- int start_offset = (FirstUnicodeChar - first_index);
- int old_count = (LastUnicodeChar - FirstUnicodeChar) + 1;
- ::memcpy (&new_array[start_offset], UnicodeCharArray, sizeof (FontCharsClassCharDataStruct *) * old_count);
- //
- // Delete the old array
- //
- delete [] UnicodeCharArray;
- UnicodeCharArray = NULL;
- }
- FirstUnicodeChar = first_index;
- LastUnicodeChar = last_index;
- UnicodeCharArray = new_array;
- return ;
- }
- ////////////////////////////////////////////////////////////////////////////////////
- //
- // Free_Character_Arrays
- //
- ////////////////////////////////////////////////////////////////////////////////////
- void
- FontCharsClass::Free_Character_Arrays (void)
- {
- if ( UnicodeCharArray != NULL ) {
- int count = (LastUnicodeChar - FirstUnicodeChar) + 1;
-
- //
- // Delete each member of the unicode array
- //
- for (int index = 0; index < count; index ++) {
- if ( UnicodeCharArray[index] != NULL ) {
- delete UnicodeCharArray[index];
- UnicodeCharArray[index] = NULL;
- }
- }
- //
- // Delete the array itself
- //
- delete [] UnicodeCharArray;
- UnicodeCharArray = NULL;
- }
- //
- // Delete each member of the ascii character array
- //
- for (int index = 0; index < 256; index ++) {
- if ( ASCIICharArray[index] != NULL ) {
- delete ASCIICharArray[index];
- ASCIICharArray[index] = NULL;
- }
- }
-
- return ;
- }
|