/*
** Command & Conquer Red Alert(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 .
*/
/***********************************************************************************************
*** 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 : Drawbuff - Westwood win95 library *
* *
* File Name : Iconcach.CPP *
* *
* Programmer : Steve Tall *
* *
* Start Date : November 8th, 1995 *
* *
* Last Update : November 13th, 1995 [ST] *
* *
*---------------------------------------------------------------------------------------------*
* Overview: This file cantains members of the IconCacheClass and associated non member *
* functions. All functions are to do with caching individual icons from icon sets *
* into video memory to improve the speed of subsequent drawing *
* *
* Functions: *
* Cache_New_Icon -- Call the Cache_It member to cache a registered icon to video memory *
* Invalidate_Cached_Icons -- Uncache all the icons *
* Restore_Cached_Icons -- restore cached icons after a focus loss *
* Register_Icon_Set -- register an icon set as cachable *
* Get_Free_Cache_Slot -- find an empty cache slot *
* IconCacheClass::IconCacheClass -- IconCacheClass constructor *
* IconCacheClass::~IconCacheClass -- IconCacheClass destructor *
* IconCacheClass::Restore -- restore the icons surface and recache it *
* IconCacheClass::Cache_It -- cache an icon into video memory *
* IconCacheClass::Uncache_It -- restore the video memory used by a cached icon *
* IconCacheClass::Draw_It -- use the blitter to draw the cached icon *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#define WIN32_LEAN_AND_MEAN
#define _WIN32
#include
#include "ddraw.h"
#include "misc.h"
#include "iconcach.h"
#include "gbuffer.h"
static DDSURFACEDESC VideoSurfaceDescription;
IconCacheClass CachedIcons[MAX_CACHED_ICONS];
extern "C"{
IconSetType IconSetList[MAX_ICON_SETS];
short IconCacheLookup[MAX_LOOKUP_ENTRIES];
}
int CachedIconsDrawn=0; //Counter of number of cache hits
int UnCachedIconsDrawn=0; //Counter of number of cache misses
BOOL CacheMemoryExhausted; //Flag set if we have run out of video RAM
/***********************************************************************************************
* Optimise_Video_Memory_Cache -- optimises usage of video memory *
* *
* *
* *
* INPUT: Nothing *
* *
* OUTPUT: TRUE if memory was freed up *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 11/29/95 12:47PM ST : Created *
*=============================================================================================*/
BOOL Optimize_Video_Memory_Cache (void)
{
if (CacheMemoryExhausted &&
(UnCachedIconsDrawn+CachedIconsDrawn > 1000) &&
UnCachedIconsDrawn > CachedIconsDrawn){
int cache_misses[MAX_CACHED_ICONS];
int cache_hits[MAX_CACHED_ICONS];
int total_cache_misses=0;
int total_cache_hits=0;
int counter;
int i;
int j;
int temp;
BOOL swapped;
/*
** make list of icons that have failed to cache more than 5 times
*/
for (counter=0 ; counter5){
cache_misses[total_cache_misses++] = counter;
}
}
/*
** Make list of icons that have been drawn less than 3 times
*/
for (counter=0 ; counter 1){
for (i = 0 ; i CachedIcons[cache_hits[j+1]].TimesDrawn){
temp=cache_hits[j];
cache_hits[j]=cache_hits[j+1];
cache_hits[j+1]=temp;
swapped = TRUE;
}
}
if (!swapped) break;
}
}
/*
** Uncache icons up to the number of failed icons
*/
for (counter=0 ; counterCount)*2;
if (IconSetList[i].IconListOffset > MAX_LOOKUP_ENTRIES*2){
IconSetList[i].IconSetPtr = NULL;
}
} else {
IconSetList[i].IconListOffset = 0;
}
if (pre_cache){
for (i=0 ; i<256 ; i++){
Is_Icon_Cached(icon_data,i);
}
}
return;
}
}
}
/***********************************************************************************************
* Get_Free_Cache_Slot -- find a free slot in which to cache an icon *
* *
* *
* *
* INPUT: Nothing *
* *
* OUTPUT: int - icon index *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 11/13/95 9:40AM ST : Created *
*=============================================================================================*/
int Get_Free_Cache_Slot (void)
{
for (int i=0 ; iRelease();
}
}
/***********************************************************************************************
* ICC::Restore -- Restores the icons video surface memory and reloads it based on the original*
* icon pointer *
* *
* *
* INPUT: Nothing *
* *
* OUTPUT: Nothing *
* *
* WARNINGS: Relies on the icons original pointer still being valie *
* *
* HISTORY: *
* 11/13/95 9:43AM ST : Created *
*=============================================================================================*/
void IconCacheClass::Restore (void)
{
if (IsCached && CacheSurface){
CacheSurface->Restore();
if (IconSource){
Cache_It(IconSource);
}
}
}
/***********************************************************************************************
* ICC::Cache_It -- allocate video memory and copy an icon to it *
* *
* *
* *
* INPUT: icon_ptr -- ptr to icon data *
* *
* OUTPUT: bool -- success? *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 11/13/95 9:44AM ST : Created *
*=============================================================================================*/
BOOL IconCacheClass::Cache_It (void *icon_ptr)
{
DDSCAPS surface_capabilities;
BOOL return_value;
/*
** If we dont have a direct draw interface yet then just fail
*/
if (!DirectDrawObject) return(FALSE);
/*
** Set up the description of the surface we want to create
*/
memset (&VideoSurfaceDescription , 0 , sizeof ( VideoSurfaceDescription ));
VideoSurfaceDescription.dwSize = sizeof( VideoSurfaceDescription );
VideoSurfaceDescription.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
VideoSurfaceDescription.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
VideoSurfaceDescription.dwHeight = ICON_WIDTH;
VideoSurfaceDescription.dwWidth = ICON_HEIGHT;
/*
** If this cache object doesnt already have a surface then create one
*/
if (!CacheSurface){
if (DD_OK!=DirectDrawObject->CreateSurface( &VideoSurfaceDescription , &CacheSurface , NULL)){
CacheMemoryExhausted = TRUE;
return(FALSE);
}
}
/*
** Make sure the surface we created isnt really in system memory
*/
if (DD_OK != CacheSurface->GetCaps(&surface_capabilities)){
return(FALSE);
}
if ((DDSCAPS_SYSTEMMEMORY & surface_capabilities.dwCaps) == DDSCAPS_SYSTEMMEMORY){
CacheSurface->Release();
return(FALSE);
}
return_value=FALSE;
/*
** Lock the surface so we can copy the icon to it
*/
if (DD_OK== CacheSurface->Lock ( NULL
, &(VideoSurfaceDescription)
, DDLOCK_WAIT
, NULL)){
/*
** Copy the icon to the surface and flag that icon is cached
*/
Cache_Copy_Icon (icon_ptr , VideoSurfaceDescription.lpSurface , VideoSurfaceDescription.lPitch);
IsCached=TRUE;
SurfaceLost=FALSE;
IconSource=icon_ptr;
return_value=TRUE;
}
CacheSurface->Unlock(NULL);
return (return_value);
}
/***********************************************************************************************
* ICC::Uncache_It -- release the video memory used to cache an icon *
* *
* *
* *
* INPUT: Nothing *
* *
* OUTPUT: Nothing *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 11/13/95 9:48AM ST : Created *
*=============================================================================================*/
void IconCacheClass::Uncache_It(void)
{
if (IsCached && CacheSurface){
CacheSurface->Release();
IsCached=FALSE;
CacheSurface=NULL;
IconSource=NULL;
CacheMemoryExhausted=FALSE;
}
}
/***********************************************************************************************
* ICC::Draw_It -- use the blitter to draw a cached icon *
* *
* *
* *
* INPUT: surface to draw to *
* x coord to draw to (relative to window) *
* y coord to draw to (relative to window) *
* window left coord *
* window top coord *
* window width *
* window height *
* *
* OUTPUT: Nothing *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 11/13/95 9:48AM ST : Created *
*=============================================================================================*/
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)
{
RECT source_rectangle;
RECT dest_rectangle;
int clip;
HRESULT return_code;
/*
** Set up the source and destination coordinates as required by direct draw
*/
source_rectangle.left = 0;
source_rectangle.top = 0;
source_rectangle.right = ICON_WIDTH;
source_rectangle.bottom = ICON_HEIGHT;
dest_rectangle.left = window_left+x_pixel;
dest_rectangle.top = window_top+y_pixel;
dest_rectangle.right = dest_rectangle.left+ICON_WIDTH;
dest_rectangle.bottom = dest_rectangle.top+ICON_HEIGHT;
/*
** Clip the coordinates to the window
*/
if (dest_rectangle.left=window_left+window_width){
clip = dest_rectangle.right-(window_left+window_width);
source_rectangle.right -= clip;
dest_rectangle.right -= clip;
}
if (dest_rectangle.top=window_top+window_height){
clip = dest_rectangle.bottom-(window_top+window_height);
source_rectangle.bottom -= clip;
dest_rectangle.bottom -= clip;
}
if (source_rectangle.left>=source_rectangle.right){
return;
}
if (source_rectangle.top>=source_rectangle.bottom){
return;
}
/*
** Do the blit
*/
return_code = dest_surface->Blt (&dest_rectangle ,
CacheSurface ,
&source_rectangle ,
DDBLT_WAIT |
DDBLT_ASYNC ,
NULL);
if (return_code == DDERR_SURFACELOST && Gbuffer_Focus_Loss_Function){
Gbuffer_Focus_Loss_Function();
}
if ( return_code != DDERR_SURFACELOST && return_code != DD_OK ) {
char temp[100];
sprintf(temp,"DD Error code %d\n", return_code & 0xFFFF);
OutputDebugString(temp);
}
TimesDrawn++;
}