- // 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 
-   
-    #define THEME_LOAD_MESH(varname,mesh_name) \ 
-    { \ 
-       theme->varname = Render_LoadMesh (L"themes/%s/models/" mesh_name L".*", theme->name); \ 
-       if (theme->varname == -1) \ 
-          MessageBox (NULL, LOCALIZE (L"Error_UnableToAddMeshD3DXLoadMeshFromXFailed"), LOCALIZE (L"FatalError"), MB_ICONERROR | MB_OK); \ 
-    } 
-    #define THEME_LOAD_PART(part_id,part_name) \ 
-    { \ 
-       theme->part_meshes[part_id] = -1; \ 
-       if (options.want_hiquality) \ 
-          theme->part_meshes[part_id] = Render_LoadMesh (L"themes/%s/models/" part_name L"-hidef.*", theme->name); \ 
-       if (theme->part_meshes[part_id] == -1) \ 
-          theme->part_meshes[part_id] = Render_LoadMesh (L"themes/%s/models/" part_name L".*", theme->name); \ 
-       if (theme->part_meshes[part_id] == -1) \ 
-          MessageBox (NULL, LOCALIZE (L"Error_UnableToAddMeshD3DXLoadMeshFromXFailed"), LOCALIZE (L"FatalError"), MB_ICONERROR | MB_OK); \ 
-    } 
-   
-    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_LOAD_MESH (board_meshindex, L"board"); 
-    if ((theme->load_index == 2) || (want_all && (theme->load_index < 3))) 
-       THEME_LOAD_MESH (table_meshindex, L"table"); 
-    if ((theme->load_index == 3) || (want_all && (theme->load_index < 4))) 
-       THEME_LOAD_MESH (trim_meshindex, L"trim"); 
-    if ((theme->load_index == 4) || (want_all && (theme->load_index < 5))) 
-       THEME_LOAD_MESH (tile_meshindex, L"tile"); 
-   
-    // load part meshes 
-    if ((theme->load_index == 5) || (want_all && (theme->load_index < 6))) 
-       THEME_LOAD_PART (PART_KING, L"king"); 
-    if ((theme->load_index == 6) || (want_all && (theme->load_index < 7))) 
-       THEME_LOAD_PART (PART_QUEEN, L"queen"); 
-    if ((theme->load_index == 7) || (want_all && (theme->load_index < 8))) 
-       THEME_LOAD_PART (PART_BISHOP, L"bishop"); 
-    if ((theme->load_index == 8) || (want_all && (theme->load_index < 9))) 
-       THEME_LOAD_PART (PART_KNIGHT, L"knight"); 
-    if ((theme->load_index == 9) || (want_all && (theme->load_index < 10))) 
-       THEME_LOAD_PART (PART_ROOK, L"rook"); 
-    if ((theme->load_index == 10) || (want_all && (theme->load_index < 11))) 
-       THEME_LOAD_PART (PART_PAWN, L"pawn"); 
-   
-    // 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 
-   
-    #undef THEME_LOAD_PART 
-    #undef THEME_LOAD_MESH 
- } 
-   
-   
- 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 
- } 
-