ICONCACH.CPP 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609
  1. /*
  2. ** Command & Conquer Red Alert(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 : Drawbuff - Westwood win95 library *
  23. * *
  24. * File Name : Iconcach.CPP *
  25. * *
  26. * Programmer : Steve Tall *
  27. * *
  28. * Start Date : November 8th, 1995 *
  29. * *
  30. * Last Update : November 13th, 1995 [ST] *
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Overview: This file cantains members of the IconCacheClass and associated non member *
  34. * functions. All functions are to do with caching individual icons from icon sets *
  35. * into video memory to improve the speed of subsequent drawing *
  36. * *
  37. * Functions: *
  38. * Cache_New_Icon -- Call the Cache_It member to cache a registered icon to video memory *
  39. * Invalidate_Cached_Icons -- Uncache all the icons *
  40. * Restore_Cached_Icons -- restore cached icons after a focus loss *
  41. * Register_Icon_Set -- register an icon set as cachable *
  42. * Get_Free_Cache_Slot -- find an empty cache slot *
  43. * IconCacheClass::IconCacheClass -- IconCacheClass constructor *
  44. * IconCacheClass::~IconCacheClass -- IconCacheClass destructor *
  45. * IconCacheClass::Restore -- restore the icons surface and recache it *
  46. * IconCacheClass::Cache_It -- cache an icon into video memory *
  47. * IconCacheClass::Uncache_It -- restore the video memory used by a cached icon *
  48. * IconCacheClass::Draw_It -- use the blitter to draw the cached icon *
  49. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  50. #define WIN32_LEAN_AND_MEAN
  51. #define _WIN32
  52. #include <windows.h>
  53. #include "ddraw.h"
  54. #include "misc.h"
  55. #include "iconcach.h"
  56. #include "gbuffer.h"
  57. static DDSURFACEDESC VideoSurfaceDescription;
  58. IconCacheClass CachedIcons[MAX_CACHED_ICONS];
  59. extern "C"{
  60. IconSetType IconSetList[MAX_ICON_SETS];
  61. short IconCacheLookup[MAX_LOOKUP_ENTRIES];
  62. }
  63. int CachedIconsDrawn=0; //Counter of number of cache hits
  64. int UnCachedIconsDrawn=0; //Counter of number of cache misses
  65. BOOL CacheMemoryExhausted; //Flag set if we have run out of video RAM
  66. /***********************************************************************************************
  67. * Optimise_Video_Memory_Cache -- optimises usage of video memory *
  68. * *
  69. * *
  70. * *
  71. * INPUT: Nothing *
  72. * *
  73. * OUTPUT: TRUE if memory was freed up *
  74. * *
  75. * WARNINGS: None *
  76. * *
  77. * HISTORY: *
  78. * 11/29/95 12:47PM ST : Created *
  79. *=============================================================================================*/
  80. BOOL Optimize_Video_Memory_Cache (void)
  81. {
  82. if (CacheMemoryExhausted &&
  83. (UnCachedIconsDrawn+CachedIconsDrawn > 1000) &&
  84. UnCachedIconsDrawn > CachedIconsDrawn){
  85. int cache_misses[MAX_CACHED_ICONS];
  86. int cache_hits[MAX_CACHED_ICONS];
  87. int total_cache_misses=0;
  88. int total_cache_hits=0;
  89. int counter;
  90. int i;
  91. int j;
  92. int temp;
  93. BOOL swapped;
  94. /*
  95. ** make list of icons that have failed to cache more than 5 times
  96. */
  97. for (counter=0 ; counter<MAX_CACHED_ICONS ; counter++){
  98. if (CachedIcons[counter].TimesFailed>5){
  99. cache_misses[total_cache_misses++] = counter;
  100. }
  101. }
  102. /*
  103. ** Make list of icons that have been drawn less than 3 times
  104. */
  105. for (counter=0 ; counter<MAX_CACHED_ICONS ; counter++){
  106. if (CachedIcons[counter].TimesDrawn<3){
  107. cache_hits[total_cache_hits++] = counter;
  108. }
  109. }
  110. /*
  111. ** Sort drawn icons into order
  112. */
  113. if (total_cache_hits > 1){
  114. for (i = 0 ; i<total_cache_hits ; i++){
  115. swapped=FALSE;
  116. for (j=0 ; j<total_cache_hits-1 ; j++){
  117. if (CachedIcons[cache_hits[j]].TimesDrawn > CachedIcons[cache_hits[j+1]].TimesDrawn){
  118. temp=cache_hits[j];
  119. cache_hits[j]=cache_hits[j+1];
  120. cache_hits[j+1]=temp;
  121. swapped = TRUE;
  122. }
  123. }
  124. if (!swapped) break;
  125. }
  126. }
  127. /*
  128. ** Uncache icons up to the number of failed icons
  129. */
  130. for (counter=0 ; counter<total_cache_misses && counter<total_cache_hits; counter++){
  131. CachedIcons[cache_hits[counter]].Uncache_It();
  132. }
  133. CacheMemoryExhausted=FALSE;
  134. CachedIconsDrawn=0;
  135. UnCachedIconsDrawn=0;
  136. return (TRUE);
  137. }
  138. return (FALSE);
  139. }
  140. /***********************************************************************************************
  141. * Cache_New_Icon -- cache a registered icon to video memory *
  142. * *
  143. * *
  144. * *
  145. * INPUT: icon_index -- index into registered icon table of icon to cache *
  146. * icon_ptr -- ptr to icon data *
  147. * *
  148. * OUTPUT: BOOL success *
  149. * *
  150. * WARNINGS: icon must already have been registered and assigned an index *
  151. * *
  152. * HISTORY: *
  153. * 11/13/95 9:36AM ST : Created *
  154. *=============================================================================================*/
  155. BOOL Cache_New_Icon (int icon_index, void *icon_ptr)
  156. {
  157. if (!CacheMemoryExhausted){
  158. return (CachedIcons[icon_index].Cache_It(icon_ptr));
  159. } else {
  160. CachedIcons[icon_index].TimesFailed++;
  161. if (Optimize_Video_Memory_Cache()){
  162. return (CachedIcons[icon_index].Cache_It(icon_ptr));
  163. } else {
  164. return (FALSE);
  165. }
  166. }
  167. }
  168. /***********************************************************************************************
  169. * Invalidat_Cached_Icons -- used to release any icons that have been cached *
  170. * *
  171. * *
  172. * *
  173. * INPUT: Nothing *
  174. * *
  175. * OUTPUT: Nothing *
  176. * *
  177. * WARNINGS: None *
  178. * *
  179. * HISTORY: *
  180. * 11/13/95 9:37AM ST : Created *
  181. *=============================================================================================*/
  182. void Invalidate_Cached_Icons (void)
  183. {
  184. for (int i=0 ; i<MAX_CACHED_ICONS ; i++){
  185. CachedIcons[i].Uncache_It();
  186. }
  187. memset (&IconCacheLookup[0] , -1 ,MAX_LOOKUP_ENTRIES*sizeof(IconCacheLookup[0]));
  188. for (i=0 ; i<MAX_ICON_SETS ; i++){
  189. IconSetList[i].IconSetPtr=NULL;
  190. }
  191. CacheMemoryExhausted=FALSE;
  192. }
  193. /***********************************************************************************************
  194. * Restore_Cached_Icons -- re-cache icons into video memory after a loss of focus *
  195. * *
  196. * *
  197. * *
  198. * INPUT: Nothing *
  199. * *
  200. * OUTPUT: Nothing *
  201. * *
  202. * WARNINGS: Assumes that the pointers that were originally used to cache the icons *
  203. * are still valid. *
  204. * *
  205. * HISTORY: *
  206. * 11/13/95 9:38AM ST : Created *
  207. *=============================================================================================*/
  208. void Restore_Cached_Icons (void)
  209. {
  210. for (int i=0 ; i<MAX_CACHED_ICONS ; i++){
  211. CachedIcons[i].Restore();
  212. }
  213. CacheMemoryExhausted=FALSE;
  214. }
  215. /***********************************************************************************************
  216. * Register_Icon_Set -- used to register an icon set as cachable *
  217. * *
  218. * *
  219. * *
  220. * INPUT: icon_data - ptr to icon set *
  221. * pre_cache -- should we pre-cache the icon data? *
  222. * *
  223. * OUTPUT: Nothing *
  224. * *
  225. * WARNINGS: None *
  226. * *
  227. * HISTORY: *
  228. * 11/13/95 9:39AM ST : Created *
  229. *=============================================================================================*/
  230. void Register_Icon_Set (void *icon_data , BOOL pre_cache)
  231. {
  232. for (int i=0 ; i<MAX_ICON_SETS ; i++){
  233. if (!IconSetList[i].IconSetPtr){
  234. IconSetList[i].IconSetPtr = (IControl_Type*)icon_data;
  235. if (i){
  236. IControl_Type *previous_set = IconSetList[i-1].IconSetPtr;
  237. IconSetList[i].IconListOffset = IconSetList[i-1].IconListOffset + ((int)previous_set->Count)*2;
  238. if (IconSetList[i].IconListOffset > MAX_LOOKUP_ENTRIES*2){
  239. IconSetList[i].IconSetPtr = NULL;
  240. }
  241. } else {
  242. IconSetList[i].IconListOffset = 0;
  243. }
  244. if (pre_cache){
  245. for (i=0 ; i<256 ; i++){
  246. Is_Icon_Cached(icon_data,i);
  247. }
  248. }
  249. return;
  250. }
  251. }
  252. }
  253. /***********************************************************************************************
  254. * Get_Free_Cache_Slot -- find a free slot in which to cache an icon *
  255. * *
  256. * *
  257. * *
  258. * INPUT: Nothing *
  259. * *
  260. * OUTPUT: int - icon index *
  261. * *
  262. * WARNINGS: None *
  263. * *
  264. * HISTORY: *
  265. * 11/13/95 9:40AM ST : Created *
  266. *=============================================================================================*/
  267. int Get_Free_Cache_Slot (void)
  268. {
  269. for (int i=0 ; i<MAX_CACHED_ICONS ; i++){
  270. if (!CachedIcons[i].Get_Is_Cached()){
  271. return (i);
  272. }
  273. }
  274. return (-1);
  275. }
  276. /***********************************************************************************************
  277. * ICC::IconCacheClass -- constructor for icon cache class *
  278. * *
  279. * *
  280. * *
  281. * INPUT: Nothing *
  282. * *
  283. * OUTPUT: Nothing *
  284. * *
  285. * WARNINGS: None *
  286. * *
  287. * HISTORY: *
  288. * 11/13/95 9:41AM ST : Created *
  289. *=============================================================================================*/
  290. IconCacheClass::IconCacheClass (void)
  291. {
  292. IsCached =FALSE;
  293. SurfaceLost =FALSE;
  294. DrawFrequency =0;
  295. CacheSurface =NULL;
  296. IconSource =NULL;
  297. }
  298. /***********************************************************************************************
  299. * ICC::~IconCacheClass -- destructor for icon cache class *
  300. * *
  301. * *
  302. * *
  303. * INPUT: Nothing *
  304. * *
  305. * OUTPUT: Nothing *
  306. * *
  307. * WARNINGS: None *
  308. * *
  309. * HISTORY: *
  310. * 11/13/95 9:41AM ST : Created *
  311. *=============================================================================================*/
  312. IconCacheClass::~IconCacheClass (void)
  313. {
  314. if (IsCached && CacheSurface){
  315. CacheSurface->Release();
  316. }
  317. }
  318. /***********************************************************************************************
  319. * ICC::Restore -- Restores the icons video surface memory and reloads it based on the original*
  320. * icon pointer *
  321. * *
  322. * *
  323. * INPUT: Nothing *
  324. * *
  325. * OUTPUT: Nothing *
  326. * *
  327. * WARNINGS: Relies on the icons original pointer still being valie *
  328. * *
  329. * HISTORY: *
  330. * 11/13/95 9:43AM ST : Created *
  331. *=============================================================================================*/
  332. void IconCacheClass::Restore (void)
  333. {
  334. if (IsCached && CacheSurface){
  335. CacheSurface->Restore();
  336. if (IconSource){
  337. Cache_It(IconSource);
  338. }
  339. }
  340. }
  341. /***********************************************************************************************
  342. * ICC::Cache_It -- allocate video memory and copy an icon to it *
  343. * *
  344. * *
  345. * *
  346. * INPUT: icon_ptr -- ptr to icon data *
  347. * *
  348. * OUTPUT: bool -- success? *
  349. * *
  350. * WARNINGS: None *
  351. * *
  352. * HISTORY: *
  353. * 11/13/95 9:44AM ST : Created *
  354. *=============================================================================================*/
  355. BOOL IconCacheClass::Cache_It (void *icon_ptr)
  356. {
  357. DDSCAPS surface_capabilities;
  358. BOOL return_value;
  359. /*
  360. ** If we dont have a direct draw interface yet then just fail
  361. */
  362. if (!DirectDrawObject) return(FALSE);
  363. /*
  364. ** Set up the description of the surface we want to create
  365. */
  366. memset (&VideoSurfaceDescription , 0 , sizeof ( VideoSurfaceDescription ));
  367. VideoSurfaceDescription.dwSize = sizeof( VideoSurfaceDescription );
  368. VideoSurfaceDescription.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
  369. VideoSurfaceDescription.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
  370. VideoSurfaceDescription.dwHeight = ICON_WIDTH;
  371. VideoSurfaceDescription.dwWidth = ICON_HEIGHT;
  372. /*
  373. ** If this cache object doesnt already have a surface then create one
  374. */
  375. if (!CacheSurface){
  376. if (DD_OK!=DirectDrawObject->CreateSurface( &VideoSurfaceDescription , &CacheSurface , NULL)){
  377. CacheMemoryExhausted = TRUE;
  378. return(FALSE);
  379. }
  380. }
  381. /*
  382. ** Make sure the surface we created isnt really in system memory
  383. */
  384. if (DD_OK != CacheSurface->GetCaps(&surface_capabilities)){
  385. return(FALSE);
  386. }
  387. if ((DDSCAPS_SYSTEMMEMORY & surface_capabilities.dwCaps) == DDSCAPS_SYSTEMMEMORY){
  388. CacheSurface->Release();
  389. return(FALSE);
  390. }
  391. return_value=FALSE;
  392. /*
  393. ** Lock the surface so we can copy the icon to it
  394. */
  395. if (DD_OK== CacheSurface->Lock ( NULL
  396. , &(VideoSurfaceDescription)
  397. , DDLOCK_WAIT
  398. , NULL)){
  399. /*
  400. ** Copy the icon to the surface and flag that icon is cached
  401. */
  402. Cache_Copy_Icon (icon_ptr , VideoSurfaceDescription.lpSurface , VideoSurfaceDescription.lPitch);
  403. IsCached=TRUE;
  404. SurfaceLost=FALSE;
  405. IconSource=icon_ptr;
  406. return_value=TRUE;
  407. }
  408. CacheSurface->Unlock(NULL);
  409. return (return_value);
  410. }
  411. /***********************************************************************************************
  412. * ICC::Uncache_It -- release the video memory used to cache an icon *
  413. * *
  414. * *
  415. * *
  416. * INPUT: Nothing *
  417. * *
  418. * OUTPUT: Nothing *
  419. * *
  420. * WARNINGS: None *
  421. * *
  422. * HISTORY: *
  423. * 11/13/95 9:48AM ST : Created *
  424. *=============================================================================================*/
  425. void IconCacheClass::Uncache_It(void)
  426. {
  427. if (IsCached && CacheSurface){
  428. CacheSurface->Release();
  429. IsCached=FALSE;
  430. CacheSurface=NULL;
  431. IconSource=NULL;
  432. CacheMemoryExhausted=FALSE;
  433. }
  434. }
  435. /***********************************************************************************************
  436. * ICC::Draw_It -- use the blitter to draw a cached icon *
  437. * *
  438. * *
  439. * *
  440. * INPUT: surface to draw to *
  441. * x coord to draw to (relative to window) *
  442. * y coord to draw to (relative to window) *
  443. * window left coord *
  444. * window top coord *
  445. * window width *
  446. * window height *
  447. * *
  448. * OUTPUT: Nothing *
  449. * *
  450. * WARNINGS: None *
  451. * *
  452. * HISTORY: *
  453. * 11/13/95 9:48AM ST : Created *
  454. *=============================================================================================*/
  455. void IconCacheClass::Draw_It (LPDIRECTDRAWSURFACE dest_surface , int x_pixel, int y_pixel, int window_left , int window_top , int window_width , int window_height)
  456. {
  457. RECT source_rectangle;
  458. RECT dest_rectangle;
  459. int clip;
  460. HRESULT return_code;
  461. /*
  462. ** Set up the source and destination coordinates as required by direct draw
  463. */
  464. source_rectangle.left = 0;
  465. source_rectangle.top = 0;
  466. source_rectangle.right = ICON_WIDTH;
  467. source_rectangle.bottom = ICON_HEIGHT;
  468. dest_rectangle.left = window_left+x_pixel;
  469. dest_rectangle.top = window_top+y_pixel;
  470. dest_rectangle.right = dest_rectangle.left+ICON_WIDTH;
  471. dest_rectangle.bottom = dest_rectangle.top+ICON_HEIGHT;
  472. /*
  473. ** Clip the coordinates to the window
  474. */
  475. if (dest_rectangle.left<window_left){
  476. source_rectangle.left += window_left-dest_rectangle.left;
  477. dest_rectangle.left=window_left;
  478. }
  479. if (dest_rectangle.right>=window_left+window_width){
  480. clip = dest_rectangle.right-(window_left+window_width);
  481. source_rectangle.right -= clip;
  482. dest_rectangle.right -= clip;
  483. }
  484. if (dest_rectangle.top<window_top){
  485. source_rectangle.top += window_top-dest_rectangle.top;
  486. dest_rectangle.top=window_top;
  487. }
  488. if (dest_rectangle.bottom>=window_top+window_height){
  489. clip = dest_rectangle.bottom-(window_top+window_height);
  490. source_rectangle.bottom -= clip;
  491. dest_rectangle.bottom -= clip;
  492. }
  493. if (source_rectangle.left>=source_rectangle.right){
  494. return;
  495. }
  496. if (source_rectangle.top>=source_rectangle.bottom){
  497. return;
  498. }
  499. /*
  500. ** Do the blit
  501. */
  502. return_code = dest_surface->Blt (&dest_rectangle ,
  503. CacheSurface ,
  504. &source_rectangle ,
  505. DDBLT_WAIT |
  506. DDBLT_ASYNC ,
  507. NULL);
  508. if (return_code == DDERR_SURFACELOST && Gbuffer_Focus_Loss_Function){
  509. Gbuffer_Focus_Loss_Function();
  510. }
  511. if ( return_code != DDERR_SURFACELOST && return_code != DD_OK ) {
  512. char temp[100];
  513. sprintf(temp,"DD Error code %d\n", return_code & 0xFFFF);
  514. OutputDebugString(temp);
  515. }
  516. TimesDrawn++;
  517. }