// main.cpp
#include "common.h"
bool Themes_Init (void)
{
// this function (re)builds the themes array and loads all the themes' data
wchar_t search_pattern[256];
WIN32_FIND_DATA wfd;
HANDLE hFind;
int selectedtheme_index;
// start by resetting the themes array
themes = NULL;
theme_count = 0;
// the selected them isn't known yet
selectedtheme_index = -1;
// build the search pattern string out of the path
swprintf_s (search_pattern, WCHAR_SIZEOF (search_pattern), L"%s\\themes\\*.*", app_path);
// initiate the search from that point
hFind = FindFirstFile (search_pattern, &wfd);
if (hFind != INVALID_HANDLE_VALUE)
{
// start doing this...
do
{
// is it this directory or the parent directory ?
if ((wcscmp (wfd.cFileName, L".") == 0) || (wcscmp (wfd.cFileName, L"..") == 0))
continue; // skip that entry
// is it a directory ?
if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
// reallocate space for one theme more (zero out the allocated space) and copy it in place
themes = (theme_t *) SAFE_realloc (themes, theme_count, theme_count + 1, sizeof (theme_t), true);
wcscpy_s (themes[theme_count].name, WCHAR_SIZEOF (themes[theme_count].name), wfd.cFileName);
theme_count++; // we know now one theme more
// is it the selected theme ?
if (_wcsicmp (wfd.cFileName, wantedtheme_name) == 0)
{
Theme_Load (&themes[theme_count - 1], true); // load ALL the theme data from this directory
selectedtheme_index = theme_count - 1; // remember the selected theme is this one
}
}
} while (FindNextFile (hFind, &wfd)); // ...and don't stop as long as there are files to go
FindClose (hFind); // close the search handle
}
// consistency check (this is not the real reason for the error, but who cares)
if (theme_count == 0)
{
MessageBox (NULL, LOCALIZE (L"Error_UnableToAddTextureD3DXCreateTextureFromFileFailed"), LOCALIZE (L"FatalError"), MB_ICONERROR | MB_OK);
return (false); // if none of these extensions match, bomb out
}
// have we found the selected theme ?
if (selectedtheme_index != -1)
theme = &themes[selectedtheme_index]; // found it, so link it
else
{
Theme_Load (&themes[0], true); // not found, so load the first available theme
theme = &themes[0]; // and link selected theme to it
}
// if we have a custom background specified, load it too
if (custombackground_pathname[0] != 0)
Background_LoadImage (&custombg, custombackground_pathname);
return (true); // at least one theme has been loaded successfully, return TRUE
}
void Themes_Shutdown (void)
{
// helper function to release the themes structures array
int theme_index;
// before freeing the themes array, backup our theme's name
wcscpy_s (wantedtheme_name, WCHAR_SIZEOF (wantedtheme_name), theme->name);
// for each theme, free its mallocated data
for (theme_index = 0; theme_index < theme_count; theme_index++)
{
SAFE_free ((void **) &theme->description); // free its description
SAFE_free ((void **) &themes[theme_index].illum.lights); // free the lights array
themes[theme_index].illum.light_count = 0;
}
// free the themes array
SAFE_free ((void **) &themes);
theme_count = 0;
return; // nothing to do
}
void Theme_Load (theme_t *theme, bool want_all)
{
// this function loads a particular theme out of a theme subdirectory's files
struct _stat fileinfo;
char *desc_buffer;
wchar_t filename[256];
wchar_t section_name[32];
wchar_t value[128];
light_t light;
void *inifile;
int light_index;
int light_count;
int red;
int green;
int blue;
FILE *fp;
// allocate space for and load its description
swprintf_s (filename, WCHAR_SIZEOF (filename), L"themes/%s/readme.txt", theme->name);
if (_wstat (filename, &fileinfo) == 0)
{
desc_buffer = (char *) SAFE_malloc (fileinfo.st_size, sizeof (char), false);
_wfopen_s (&fp, filename, L"rb");
fread (desc_buffer, fileinfo.st_size, 1, fp); // read file in whole in ASCII form
fclose (fp); // close it and then convert it to wide char
theme->description = (wchar_t *) SAFE_malloc (fileinfo.st_size, sizeof (wchar_t), false);
ConvertToWideChar (theme->description, fileinfo.st_size, desc_buffer);
SAFE_free ((void **) &desc_buffer); // we no longer need the ASCII buffer
}
else
theme->description = NULL; // this theme has no description
// load its background image
if ((theme->load_index == 0) || (want_all && (theme->load_index < 1)))
{
swprintf_s (filename, WCHAR_SIZEOF (filename), L"themes/%s/background/background.*", theme->name);
Background_LoadImage (&theme->bg, filename);
}
// load board meshes
if ((theme->load_index == 1) || (want_all && (theme->load_index < 2)))
theme->board_meshindex = Render_LoadMesh (L"themes/%s/models/board.*", theme->name);
if ((theme->load_index == 2) || (want_all && (theme->load_index < 3)))
theme->table_meshindex = Render_LoadMesh (L"themes/%s/models/table.*", theme->name);
if ((theme->load_index == 3) || (want_all && (theme->load_index < 4)))
theme->trim_meshindex = Render_LoadMesh (L"themes/%s/models/trim.*", theme->name);
if ((theme->load_index == 4) || (want_all && (theme->load_index < 5)))
theme->tile_meshindex = Render_LoadMesh (L"themes/%s/models/tile.*", theme->name);
// load part meshes
if ((theme->load_index == 5) || (want_all && (theme->load_index < 6)))
theme->part_meshes[PART_KING] = Render_LoadMesh (L"themes/%s/models/king.*", theme->name);
if ((theme->load_index == 6) || (want_all && (theme->load_index < 7)))
theme->part_meshes[PART_QUEEN] = Render_LoadMesh (L"themes/%s/models/queen.*", theme->name);
if ((theme->load_index == 7) || (want_all && (theme->load_index < 8)))
theme->part_meshes[PART_BISHOP] = Render_LoadMesh (L"themes/%s/models/bishop.*", theme->name);
if ((theme->load_index == 8) || (want_all && (theme->load_index < 9)))
theme->part_meshes[PART_KNIGHT] = Render_LoadMesh (L"themes/%s/models/knight.*", theme->name);
if ((theme->load_index == 9) || (want_all && (theme->load_index < 10)))
theme->part_meshes[PART_ROOK] = Render_LoadMesh (L"themes/%s/models/rook.*", theme->name);
if ((theme->load_index == 10) || (want_all && (theme->load_index < 11)))
theme->part_meshes[PART_PAWN] = Render_LoadMesh (L"themes/%s/models/pawn.*", theme->name);
// load part textures
if ((theme->load_index == 11) || (want_all && (theme->load_index < 12)))
theme->part_colors[COLOR_BLACK].texture = Render_LoadTexture (L"themes/%s/models/part-black.*", theme->name);
if ((theme->load_index == 12) || (want_all && (theme->load_index < 13)))
theme->part_colors[COLOR_WHITE].texture = Render_LoadTexture (L"themes/%s/models/part-white.*", theme->name);
// load board, table, grid and trim textures
if ((theme->load_index == 13) || (want_all && (theme->load_index < 14)))
theme->board_texture = Render_LoadTexture (L"themes/%s/models/board.*", theme->name);
if ((theme->load_index == 14) || (want_all && (theme->load_index < 15)))
theme->table_texture = Render_LoadTexture (L"themes/%s/models/table.*", theme->name);
if ((theme->load_index == 15) || (want_all && (theme->load_index < 16)))
theme->trim_texture = Render_LoadTexture (L"themes/%s/models/trim.*", theme->name);
if ((theme->load_index == 16) || (want_all && (theme->load_index < 17)))
theme->grid_texture = Render_LoadTexture (L"themes/%s/models/grid.*", theme->name);
// load overlay textures
if ((theme->load_index == 17) || (want_all && (theme->load_index < 18)))
theme->shadow_textureindex = Render_LoadTexture (L"themes/%s/shadow.*", theme->name);
if ((theme->load_index == 18) || (want_all && (theme->load_index < 19)))
theme->hovered_textureindex = Render_LoadTexture (L"themes/%s/hovered.*", theme->name);
if ((theme->load_index == 19) || (want_all && (theme->load_index < 20)))
theme->check_textureindex = Render_LoadTexture (L"themes/%s/check.*", theme->name);
if ((theme->load_index == 20) || (want_all && (theme->load_index < 21)))
theme->threat_textureindex = Render_LoadTexture (L"themes/%s/takeable.*", theme->name);
if ((theme->load_index == 21) || (want_all && (theme->load_index < 22)))
theme->lastmovesource_textureindex = Render_LoadTexture (L"themes/%s/lastmovesource.*", theme->name);
if ((theme->load_index == 22) || (want_all && (theme->load_index < 23)))
theme->lastmovetarget_textureindex = Render_LoadTexture (L"themes/%s/lastmovetarget.*", theme->name);
if ((theme->load_index == 23) || (want_all && (theme->load_index < 24)))
theme->selected_textureindex = Render_LoadTexture (L"themes/%s/selected.*", theme->name);
if ((theme->load_index == 24) || (want_all && (theme->load_index < 25)))
theme->possiblemove_textureindex = Render_LoadTexture (L"themes/%s/possiblemove.*", theme->name);
if ((theme->load_index == 25) || (want_all && (theme->load_index < 26)))
theme->takeable_textureindex = Render_LoadTexture (L"themes/%s/takeable.*", theme->name);
// load sprites
if ((theme->load_index == 26) || (want_all && (theme->load_index < 27)))
theme->flatsprites[COLOR_WHITE][PART_PAWN] = Render_LoadSprite (L"themes/%s/parts/pawn-white.*", theme->name);
if ((theme->load_index == 27) || (want_all && (theme->load_index < 28)))
theme->flatsprites[COLOR_WHITE][PART_ROOK] = Render_LoadSprite (L"themes/%s/parts/rook-white.*", theme->name);
if ((theme->load_index == 28) || (want_all && (theme->load_index < 29)))
theme->flatsprites[COLOR_WHITE][PART_KNIGHT] = Render_LoadSprite (L"themes/%s/parts/knight-white.*", theme->name);
if ((theme->load_index == 29) || (want_all && (theme->load_index < 30)))
theme->flatsprites[COLOR_WHITE][PART_BISHOP] = Render_LoadSprite (L"themes/%s/parts/bishop-white.*", theme->name);
if ((theme->load_index == 30) || (want_all && (theme->load_index < 31)))
theme->flatsprites[COLOR_WHITE][PART_QUEEN] = Render_LoadSprite (L"themes/%s/parts/queen-white.*", theme->name);
if ((theme->load_index == 31) || (want_all && (theme->load_index < 32)))
theme->flatsprites[COLOR_WHITE][PART_KING] = Render_LoadSprite (L"themes/%s/parts/king-white.*", theme->name);
if ((theme->load_index == 32) || (want_all && (theme->load_index < 33)))
theme->flatsprites[COLOR_BLACK][PART_PAWN] = Render_LoadSprite (L"themes/%s/parts/pawn-black.*", theme->name);
if ((theme->load_index == 33) || (want_all && (theme->load_index < 34)))
theme->flatsprites[COLOR_BLACK][PART_ROOK] = Render_LoadSprite (L"themes/%s/parts/rook-black.*", theme->name);
if ((theme->load_index == 34) || (want_all && (theme->load_index < 35)))
theme->flatsprites[COLOR_BLACK][PART_KNIGHT] = Render_LoadSprite (L"themes/%s/parts/knight-black.*", theme->name);
if ((theme->load_index == 35) || (want_all && (theme->load_index < 36)))
theme->flatsprites[COLOR_BLACK][PART_BISHOP] = Render_LoadSprite (L"themes/%s/parts/bishop-black.*", theme->name);
if ((theme->load_index == 36) || (want_all && (theme->load_index < 37)))
theme->flatsprites[COLOR_BLACK][PART_QUEEN] = Render_LoadSprite (L"themes/%s/parts/queen-black.*", theme->name);
if ((theme->load_index == 37) || (want_all && (theme->load_index < 38)))
theme->flatsprites[COLOR_BLACK][PART_KING] = Render_LoadSprite (L"themes/%s/parts/king-black.*", theme->name);
if ((theme->load_index == 38) || (want_all && (theme->load_index < 39)))
theme->lastmovesource_spriteindex = Render_LoadSprite (L"themes/%s/lastmovesource.*", theme->name);
if ((theme->load_index == 39) || (want_all && (theme->load_index < 40)))
theme->lastmovetarget_spriteindex = Render_LoadSprite (L"themes/%s/lastmovetarget.*", theme->name);
// load the flat pieces textures
if ((theme->load_index == 40) || (want_all && (theme->load_index < 41)))
theme->flattextures[COLOR_WHITE][PART_PAWN] = Render_LoadTexture (L"themes/%s/parts/pawn-white.*", theme->name);
if ((theme->load_index == 41) || (want_all && (theme->load_index < 42)))
theme->flattextures[COLOR_WHITE][PART_ROOK] = Render_LoadTexture (L"themes/%s/parts/rook-white.*", theme->name);
if ((theme->load_index == 42) || (want_all && (theme->load_index < 43)))
theme->flattextures[COLOR_WHITE][PART_KNIGHT] = Render_LoadTexture (L"themes/%s/parts/knight-white.*", theme->name);
if ((theme->load_index == 43) || (want_all && (theme->load_index < 44)))
theme->flattextures[COLOR_WHITE][PART_BISHOP] = Render_LoadTexture (L"themes/%s/parts/bishop-white.*", theme->name);
if ((theme->load_index == 44) || (want_all && (theme->load_index < 45)))
theme->flattextures[COLOR_WHITE][PART_QUEEN] = Render_LoadTexture (L"themes/%s/parts/queen-white.*", theme->name);
if ((theme->load_index == 45) || (want_all && (theme->load_index < 46)))
theme->flattextures[COLOR_WHITE][PART_KING] = Render_LoadTexture (L"themes/%s/parts/king-white.*", theme->name);
if ((theme->load_index == 46) || (want_all && (theme->load_index < 47)))
theme->flattextures[COLOR_BLACK][PART_PAWN] = Render_LoadTexture (L"themes/%s/parts/pawn-black.*", theme->name);
if ((theme->load_index == 47) || (want_all && (theme->load_index < 48)))
theme->flattextures[COLOR_BLACK][PART_ROOK] = Render_LoadTexture (L"themes/%s/parts/rook-black.*", theme->name);
if ((theme->load_index == 48) || (want_all && (theme->load_index < 49)))
theme->flattextures[COLOR_BLACK][PART_KNIGHT] = Render_LoadTexture (L"themes/%s/parts/knight-black.*", theme->name);
if ((theme->load_index == 49) || (want_all && (theme->load_index < 50)))
theme->flattextures[COLOR_BLACK][PART_BISHOP] = Render_LoadTexture (L"themes/%s/parts/bishop-black.*", theme->name);
if ((theme->load_index == 50) || (want_all && (theme->load_index < 51)))
theme->flattextures[COLOR_BLACK][PART_QUEEN] = Render_LoadTexture (L"themes/%s/parts/queen-black.*", theme->name);
if ((theme->load_index == 51) || (want_all && (theme->load_index < 52)))
theme->flattextures[COLOR_BLACK][PART_KING] = Render_LoadTexture (L"themes/%s/parts/king-black.*", theme->name);
//////////////////////////////
// read scene lights from file
if ((theme->load_index == 52) || (want_all && (theme->load_index < 53)))
{
theme->illum.lights = NULL; // no lights for the scene so far
theme->illum.light_count = 0; // reset the known lights count
// open the INI file
swprintf_s (filename, WCHAR_SIZEOF (filename), L"themes/%s/lights.ini", theme->name);
inifile = INIFile_LoadINIFile (filename);
// read the global light values and the parts illumination values
swscanf_s (INIFile_ReadEntryAsString (inifile, L"global", L"ambient light", L"50, 50, 50"), L"%d , %d , %d", &red, &green, &blue);
theme->illum.ambient_light = RGB_TO_RGBACOLOR (red, green, blue);
theme->board_material = Render_MaterialIndexOf (INIFile_ReadEntryAsString (inifile, L"global", L"board material", L"default"));
theme->table_material = Render_MaterialIndexOf (INIFile_ReadEntryAsString (inifile, L"global", L"table material", L"default"));
theme->trim_material = -1; // TODO: make customizable
theme->reflection_alpha = (unsigned char) INIFile_ReadEntryAsLong (inifile, L"global", L"table reflection alpha", 50);
theme->part_colors[COLOR_BLACK].material = Render_MaterialIndexOf (INIFile_ReadEntryAsString (inifile, L"global", L"black material", L"default"));
theme->part_colors[COLOR_WHITE].material = Render_MaterialIndexOf (INIFile_ReadEntryAsString (inifile, L"global", L"white material", L"default"));
// figure out the number of lights in this file
light_count = INIFile_GetNumberOfSections (inifile) - 1; // deduce the [global] section
// for each light section...
for (light_index = 0; light_index < light_count; light_index++)
{
swprintf_s (section_name, WCHAR_SIZEOF (section_name), L"light %d", light_index + 1); // build section name
memset (&light, 0, sizeof (light)); // wipe out temporary light structure
// get this light parameters
wcscpy_s (value, WCHAR_SIZEOF (value), INIFile_ReadEntryAsString (inifile, section_name, L"type", L""));
if (_wcsicmp (value, L"directional") == 0)
light.type = LIGHT_DIRECTIONAL;
else if (_wcsicmp (value, L"point") == 0)
light.type = LIGHT_POINT;
else if (_wcsicmp (value, L"spot") == 0)
light.type = LIGHT_SPOT;
else
continue; // on invalid data, skip this section
swscanf_s (INIFile_ReadEntryAsString (inifile, section_name, L"color", L"0, 0, 0"), L"%d , %d , %d", &red, &green, &blue);
light.color = RGB_TO_RGBACOLOR (red, green, blue);
swscanf_s (INIFile_ReadEntryAsString (inifile, section_name, L"source", L"0.0, 0.0, 0.0"), L"%f , %f , %f", &light.pos_x, &light.pos_y, &light.pos_z);
swscanf_s (INIFile_ReadEntryAsString (inifile, section_name, L"direction", L"0.0, 0.0, 0.0"), L"%f , %f , %f", &light.direction_x, &light.direction_y, &light.direction_z);
light.range = (float) INIFile_ReadEntryAsDouble (inifile, section_name, L"range", 0.0);
swscanf_s (INIFile_ReadEntryAsString (inifile, section_name, L"attenuation", L"0.0, 0.0, 0.0"), L"%f , %f , %f", &light.attenuation_constant, &light.attenuation_proportional, &light.attenuation_square);
swscanf_s (INIFile_ReadEntryAsString (inifile, section_name, L"cone", L"0.0, 0.0"), L"%f , %f", &light.cone_inner, &light.cone_outer);
// reallocate the lights array to hold one light more
theme->illum.lights = (light_t *) SAFE_realloc (theme->illum.lights, theme->illum.light_count, theme->illum.light_count + 1, sizeof (light_t), false);
memcpy (&theme->illum.lights[theme->illum.light_count], &light, sizeof (light_t)); // copy light in place
theme->illum.light_count++; // we know now one light more
}
// close the INI file
INIFile_FreeINIFile (inifile);
}
theme->load_index++; // this bit has been loaded
if (theme->load_index == 53)
theme->is_loaded = true; // when everything has been loaded, remember this theme is now usable
return; // finished, theme data is loaded a bit more
}
void Background_LoadImage (backgroundsprite_t *bg, const wchar_t *image_pathname)
{
// this function loads the specified background image for the specified theme
int width;
int height;
// does the background file look like an image we can comprehend ? try to get its width and height
if (GetImageSize (image_pathname, &width, &height))
{
// yes it is, so load it as our background and round its size to the highest multiple of two
bg->sprite_width = 2;
while (bg->sprite_width < width)
bg->sprite_width *= 2; // save them rounded to the next power of two
bg->sprite_height = 2;
while (bg->sprite_height < height)
bg->sprite_height *= 2; // save them rounded to the next power of two
bg->sprite_index = Render_LoadSprite (image_pathname); // load texture as sprite
}
else
{
// no it's not, so load a default texture
bg->sprite_index = Render_LoadSprite (L"data/notexture.png");
bg->sprite_width = 2;
bg->sprite_height = 2;
}
return; // finished, theme background image is loaded
}