If you have comments or questions concerning this source file, discuss them in the forum.
/*
Copyright (c) 2002 Nicolai Haehnle
See the license.txt for details. If that file was not included in the
source distributions, please email <prefect@rtts.org>
*/
// hal_common.cpp - base class implementations
#include "library.h"
#include "hal.h"
#include "hal_sdlgl.h"
HAL *hal;
/*
==============================================================================
HPicture IMPLEMENTATION
==============================================================================
*/
HPicture *HPicture::m_pList = 0;
/*
==============
HPicture::HPicture
Initialize the picture structure with zero values
==============
*/
HPicture::HPicture(const char *name, int type, u32 colorkey)
{
#ifdef DEBUG
// L_Printf("Create %s\n", name);
#endif
xstrcpy(m_szName, sizeof(m_szName), name);
m_iType = type;
m_colorkey = colorkey;
m_pImpl = 0;
bitmask = 0;
m_iUsed = 1;
m_iCacheCycle = HAL::cachecycle;
m_ppPrev = &m_pList;
m_pNext = m_pList;
if (m_pNext)
m_pNext->m_ppPrev = &m_pNext;
m_pList = this;
}
/*
==============
HPicture::~HPicture
Free allocated memory
==============
*/
HPicture::~HPicture()
{
if (m_pImpl)
hal->UnloadPicture(this);
if (m_pNext)
m_pNext->m_ppPrev = m_ppPrev;
*m_ppPrev = m_pNext;
}
/*
==============
HPicture::Get
Lookup the picture in the cache or load it
==============
*/
HPicture *HPicture::Get(const char *name, int type, u32 colorkey)
{
HPicture *pic;
for(pic = m_pList; pic; pic = pic->m_pNext) {
if (!strcmp(pic->m_szName, name)) {
pic->AddRef();
pic->m_iCacheCycle = HAL::cachecycle;
return pic;
}
}
pic = new HPicture(name, type, colorkey);
try {
hal->LoadPicture(pic);
} catch(...) {
delete pic;
throw;
}
return pic;
}
/*
==============
HPicture::CacheCycle
Evict unused pictures
==============
*/
void HPicture::CacheCycle()
{
HPicture *next, *pic;
next = m_pList;
while(next) {
pic = next;
next = next->m_pNext;
if (pic->m_iUsed)
pic->m_iCacheCycle = HAL::cachecycle;
else {
if (HAL::cachecycle-pic->m_iCacheCycle > 2)
delete pic;
}
}
}
/*
==============
HPicture::UnloadAll
This is called before a HAL change
==============
*/
void HPicture::UnloadAll()
{
HPicture *pic;
for(pic = m_pList; pic; pic = pic->m_pNext)
hal->UnloadPicture(pic);
}
/*
==============
HPicture::LoadAll
Called after a HAL change
==============
*/
void HPicture::LoadAll()
{
HPicture *pic;
for(pic = m_pList; pic; pic = pic->m_pNext)
hal->LoadPicture(pic);
}
/*
==============
HPicture::Cleanup
Complain about potential picture leaks, free all cached pics
==============
*/
void HPicture::Cleanup()
{
while(m_pList) {
if (m_pList->m_iUsed)
L_Printf("%s: picture leak\n", m_pList->m_szName);
delete m_pList;
}
}
/*
==============================================================================
COMMON HAL FUNCTIONS
==============================================================================
*/
int HAL::cachecycle = 0;
/*
==============
HAL::HAL
==============
*/
HAL::HAL()
{
scrsize[0] = 0;
scrsize[1] = 0;
framestart = 0;
frametime = 0;
}
HAL::~HAL()
{
}
/*
==============
HAL::CacheCycle
Call subsystems' CacheCycle functions
==============
*/
void HAL::CacheCycle()
{
cachecycle++;
SPR_CacheCycle();
HFont::CacheCycle();
HPicture::CacheCycle();
}
#include "keynames.h"
/*
==============
HAL_NameForKey
Use the keynames lookup table
==============
*/
const char *HAL_NameForKey(int code)
{
keynamecode_t *kc;
for(kc = keynames; kc->name; kc++)
if (kc->code == code)
return kc->name;
return "bad";
}
/*
==============
HAL_Start
Load a HAL, with parameters read from cfg.
Can also be used to replace the current hal with a new one.
==============
*/
void HAL_Start(LConfig *cfg)
{
bool cycle;
if (hal) {
hal->CacheCycle(); // to reduce potentially unnecessary re-loading time
HPicture::UnloadAll();
hal->Shutdown();
delete hal;
hal = 0;
cycle = true;
} else
cycle = false;
hal = new HAL_SdlGl(cfg);
hal->Init();
if (cycle)
HPicture::LoadAll();
}
/*
==============
HAL_Shutdown
Closes the HAL down, frees all resources
==============
*/
void HAL_Shutdown()
{
SPR_Cleanup();
HFont::Cleanup();
HPicture::Cleanup();
hal->Shutdown();
delete hal;
hal = 0;
}
/*
==============
HAL_Screenshot
Automatically get a screenshot and save it in an xxxx????.bmp,
where ???? is an integer, starting with 0000
==============
*/
void HAL_Screenshot(const char *basename)
{
char path[MAX_OSPATH];
int num;
int size[2];
byte *data;
num = 0;
for(;;) {
snprintf(path, sizeof(path), "%s%04i.bmp", basename, num);
if (!L_FileExists(path))
break;
num++;
}
data = hal->Screenshot(size);
try {
WriteBMP(path, size, 0, data, false);
} catch(...) {
L_Free(data);
throw;
}
L_Free(data);
}
/*
==============
HAL_CanonicalBitmapLoad
Load any bitmap as 32 bit with colorkey etc... applied
==============
*/
byte *HAL_CanonicalBitmapLoad(const char *fname, int *size, int *ptype,
unsigned int colorkey)
{
char path[MAX_OSPATH];
byte *palette, *pixels, *scan;
int pxls, i;
int x, y;
int type;
type = *ptype;
// Load the bitmap
snprintf(path, sizeof(path), "%s.bmp", fname);
LoadBMP(path, size, &palette, &pixels);
pxls = size[0] * size[1];
// Convert 8 bit to 32 bit
if (palette) {
u32 *buf = (u32 *)L_Malloc(4 * pxls, TAG_HAL);
for(i = 0; i < pxls; i++) {
byte idx = pixels[i];
if (type & __pic_palkey && idx == 255) // transparent
buf[i] = 0;
else
buf[i] = ((u32 *)palette)[idx];
}
L_Free(palette);
L_Free(pixels);
pixels = (byte *)buf;
}
// Check the transparency settings
type &= ~__pic_alpha;
type |= __pic_maskonly;
scan = pixels;
for(i = 0; i < pxls; i++, scan += 4) {
if (type & __pic_colorkey) {
if ((*(unsigned int *)scan & 0xffffff) == colorkey)
scan[3] = 0;
}
if (type & __pic_redalpha) {
scan[3] = scan[0];
scan[0] = scan[1] = scan[2] = 255;
}
if (scan[3] != 255) {
type |= __pic_alpha;
if (scan[3] != 0)
type &= ~__pic_maskonly;
}
}
// Fill the transparent border pixels with the bordering color
// This is to avoid a pink color at the border of objects with
// subpixel-accurate rendering
if ((type & (__pic_alpha|__pic_colorkey)) == (__pic_alpha|__pic_colorkey) &&
!(type & __pic_onlyalpha))
{
// L_Printf("alpha fill\n");
scan = pixels;
for(y = 0; y < size[1]; y++) {
static const int offset[8][2] = {
{ -1, -1 }, { 0, -1 }, { 1, -1 },
{ -1, 0 }, { 1, 0 },
{ -1, 1 }, { 0, 1 }, { 1, 1 }
};
byte basemask, mask, bits;
if (!y)
basemask = 0xf8;
else if (y+1 >= size[1])
basemask = 0x1f;
else
basemask = 0xff;
for(x = 0; x < size[0]; x++, scan += 4) {
int color[3];
byte *src;
byte c;
if (scan[3])
continue; // not a transparent pixel
if (!x)
mask = basemask & 0xD6;
else if (x+1 >= size[0])
mask = basemask & 0x6B;
else
mask = basemask;
color[0] = color[1] = color[2] = 0;
c = 0;
for(i = 0, bits = 1; i < 8; i++, bits <<= 1) {
int dx, dy;
if (!(mask & bits))
continue;
dx = x+offset[i][0];
dy = y+offset[i][1];
if (dx < 0 || dx >= size[0] || dy < 0 || dy >= size[1])
throw LError(" %i %i (%i %i)\n", dx, dy, size[0], size[1]);
src = &pixels[4 * (dy * size[0] + dx)];
if (!src[3])
continue;
color[0] += src[0];
color[1] += src[1];
color[2] += src[2];
c++;
}
if (c) {
scan[0] = color[0] / c;
scan[1] = color[1] / c;
scan[2] = color[2] / c;
}
}
}
}
if (!(type & __pic_alpha))
type &= ~__pic_maskonly;
*ptype = type;
return pixels;
}