/* Rehash the hash table (i.e. change its size and reinsert all * items). This operation is slow and should not be used frequently. */ void ght_rehash(ght_hash_table_t *p_ht, unsigned int i_size) { ght_hash_table_t *p_tmp; ght_iterator_t iterator; const void *p_key; void *p; unsigned int i; DEBUG_ASSERT(p_ht); /* Recreate the hash table with the new size */ p_tmp = ght_create(i_size); DEBUG_ASSERT(p_tmp); /* Set the flags for the new hash table */ ght_set_hash(p_tmp, p_ht->fn_hash); ght_set_alloc(p_tmp, p_ht->fn_alloc, p_ht->fn_free); ght_set_heuristics(p_tmp, GHT_HEURISTICS_NONE); ght_set_rehash(p_tmp, FALSE); /* Walk through all elements in the table and insert them into the temporary one. */ for (p = ght_first(p_ht, &iterator, &p_key); p; p = ght_next(p_ht, &iterator, &p_key)) { DEBUG_ASSERT(iterator.p_entry); /* Insert the entry into the new table */ if (ght_insert(p_tmp, iterator.p_entry->p_data, iterator.p_entry->key.i_size, iterator.p_entry->key.p_key) < 0) { LOG_ERROR("Out of memory error or entry already in hash table when rehashing (internal error)\n"); } } /* Remove the old table... */ for (i=0; i<p_ht->i_size; i++) { if (p_ht->pp_entries[i]) { /* Delete the entries in the bucket */ free_entry_chain (p_ht, p_ht->pp_entries[i]); p_ht->pp_entries[i] = NULL; } } DefaultFreeFunction (p_ht->pp_entries); DefaultFreeFunction (p_ht->p_nr); /* ... and replace it with the new */ p_ht->i_size = p_tmp->i_size; p_ht->i_size_mask = p_tmp->i_size_mask; p_ht->i_items = p_tmp->i_items; p_ht->pp_entries = p_tmp->pp_entries; p_ht->p_nr = p_tmp->p_nr; p_ht->p_oldest = p_tmp->p_oldest; p_ht->p_newest = p_tmp->p_newest; /* Clean up */ p_tmp->pp_entries = NULL; p_tmp->p_nr = NULL; DefaultFreeFunction (p_tmp); }
/******************************************************* * WriteMmdModelMaterials関数 * * PMDとPMXのテクスチャ画像データを書き出す * * 引数 * * model : テクスチャ画像データを書き出すモデル * * out_data_size : 書き出したデータのバイト数格納先 * * 返り値 * * 書き出したデータ * *******************************************************/ uint8* WriteMmdModelMaterials( MODEL_INTERFACE* model, size_t* out_data_size ) { // 画像データをまとめて書き出すバッファ MEMORY_STREAM *stream = CreateMemoryStream(1024 * 1024); // 作成結果のストリーム MEMORY_STREAM result_stream = {0}; // 作成結果データ uint8 *result; // テクスチャ画像配列へのポインタ MATERIAL_INTERFACE **materials; // 画像データの格納先 uint8 *image_data = NULL; // 画像データ格納バッファのサイズ size_t image_data_buffer_size = 0; // UTF-8での画像ファイルへのパス char utf8_path[8192]; // OSでの画像ファイルへのパス char *system_path; // 画像ファイルの読み込み、ファイルサイズ、存在確認用 FILE *fp; // 画像ファイルの数 int num_images = 0; // テクスチャ画像配列のサイズ int num_materials; // 32ビット書き出し用 uint32 data32; // 画像データの開始位置 long image_start = sizeof(data32); // 画像データの合計サイズ long total_image_size = 0; int counter; // 書き出す画像ファイルの名前・サイズ配列 MATERIAL_ARCHIVE_DATA *names; // 重複書き出し防止用 ght_hash_table_t *name_table; unsigned int name_length; uint32 diff; // for文用のカウンタ int i; // モデルに設定されているテクスチャ画像を取得 materials = (MATERIAL_INTERFACE**)model->get_materials(model, &num_materials); name_table = ght_create(num_materials+1); ght_set_hash(name_table, (ght_fn_hash_t)GetStringHash); // それぞれの画像ファイルのファイル名サイズを取得 for(i=0; i<num_materials; i++) { MATERIAL_INTERFACE *material = materials[i]; if(material->main_texture != NULL) { name_length = (unsigned int)strlen(material->main_texture); if(ght_get(name_table, name_length, material->main_texture) == NULL) { (void)ght_insert(name_table, (void*)1, name_length, material->main_texture); image_start += (long)name_length+1; image_start += sizeof(uint32) + sizeof(uint32) + sizeof(uint32); num_images++; } } if(material->sphere_texture != NULL) { name_length = (unsigned int)strlen(material->sphere_texture); if(ght_get(name_table, name_length, material->sphere_texture) == NULL) { (void)ght_insert(name_table, (void*)1, name_length, material->sphere_texture); image_start += (long)name_length+1; image_start += sizeof(uint32) + sizeof(uint32) + sizeof(uint32); num_images++; } } if(material->toon_texture != NULL) { // トゥーンテクスチャの場合はモデルのディレクトリに画像があるか確認 (void)sprintf(utf8_path, "%s/%s", model->model_path, material->toon_texture); system_path = LocaleFromUTF8(utf8_path); if((fp = fopen(system_path, "rb")) != NULL) { // 画像有 name_length = (unsigned int)strlen(material->toon_texture); if(ght_get(name_table, name_length, material->toon_texture) == NULL) { (void)ght_insert(name_table, (void*)1, name_length, material->toon_texture); image_start += (long)name_length+1; image_start += sizeof(uint32) + sizeof(uint32) + sizeof(uint32); num_images++; (void)fclose(fp); } } MEM_FREE_FUNC(system_path); } } ght_finalize(name_table); // 画像ファイルを一つのデータにまとめる name_table = ght_create(num_materials+1); ght_set_hash(name_table, (ght_fn_hash_t)GetStringHash); names = (MATERIAL_ARCHIVE_DATA*)MEM_ALLOC_FUNC(sizeof(*names)*num_images); counter = 0; for(i=0; i<num_materials; i++) { MATERIAL_INTERFACE *material = materials[i]; if(material->main_texture != NULL) { name_length = (unsigned int)strlen(material->main_texture); if(ght_get(name_table, name_length, material->main_texture) == NULL) { (void)ght_insert(name_table, (void*)1, name_length, material->main_texture); names[counter].data_start = image_start + total_image_size; (void)sprintf(utf8_path, "%s/%s", model->model_path, material->main_texture); system_path = LocaleFromUTF8(utf8_path); if((fp = fopen(system_path, "rb")) != NULL) { (void)fseek(fp, 0, SEEK_END); names[counter].name = material->main_texture; names[counter].data_size = ftell(fp); names[counter].data_start = total_image_size + image_start; total_image_size += names[counter].data_size; rewind(fp); if(image_data_buffer_size < names[counter].data_size) { image_data = (uint8*)MEM_REALLOC_FUNC(image_data, names[counter].data_size); image_data_buffer_size = names[counter].data_size; } (void)fread(image_data, 1, names[counter].data_size, fp); (void)MemWrite(image_data, 1, names[counter].data_size, stream); counter++; (void)fclose(fp); } else { char sp_path[8192] = {0}; char *extention = sp_path; char *p = extention; (void)strcpy(sp_path, system_path); while(*p != '\0') { if(*p == '.') { extention = p; } p++; } extention[1] = 's'; extention[2] = 'p'; extention[3] = 'a'; extention[4] = '\0'; if((fp = fopen(sp_path, "rb")) != NULL) { (void)fseek(fp, 0, SEEK_END); names[counter].name = material->main_texture; names[counter].data_size = ftell(fp); names[counter].data_start = total_image_size + image_start; total_image_size += names[counter].data_size; rewind(fp); if(image_data_buffer_size < names[counter].data_size) { image_data = (uint8*)MEM_REALLOC_FUNC(image_data, names[counter].data_size); image_data_buffer_size = names[counter].data_size; } (void)fread(image_data, 1, names[counter].data_size, fp); (void)MemWrite(image_data, 1, names[counter].data_size, stream); counter++; (void)fclose(fp); } else { extention[3] = 'h'; if((fp = fopen(sp_path, "rb")) != NULL) { (void)fseek(fp, 0, SEEK_END); names[counter].name = material->main_texture; names[counter].data_size = ftell(fp); names[counter].data_start = total_image_size + image_start; total_image_size += names[counter].data_size; rewind(fp); if(image_data_buffer_size < names[counter].data_size) { image_data = (uint8*)MEM_REALLOC_FUNC(image_data, names[counter].data_size); image_data_buffer_size = names[counter].data_size; } (void)fread(image_data, 1, names[counter].data_size, fp); (void)MemWrite(image_data, 1, names[counter].data_size, stream); counter++; (void)fclose(fp); } } } MEM_FREE_FUNC(system_path); } } if(material->sphere_texture != NULL) { name_length = (unsigned int)strlen(material->sphere_texture); if(ght_get(name_table, name_length, material->sphere_texture) == NULL) { (void)ght_insert(name_table, (void*)1, name_length, material->sphere_texture); names[counter].data_start = image_start + total_image_size; (void)sprintf(utf8_path, "%s/%s", model->model_path, material->sphere_texture); system_path = LocaleFromUTF8(utf8_path); if((fp = fopen(system_path, "rb")) != NULL) { (void)fseek(fp, 0, SEEK_END); names[counter].name = material->sphere_texture; names[counter].data_size = ftell(fp); names[counter].data_start = total_image_size + image_start; total_image_size += names[counter].data_size; rewind(fp); if(image_data_buffer_size < names[counter].data_size) { image_data = (uint8*)MEM_REALLOC_FUNC(image_data, names[counter].data_size); image_data_buffer_size = names[counter].data_size; } (void)fread(image_data, 1, names[counter].data_size, fp); (void)MemWrite(image_data, 1, names[counter].data_size, stream); counter++; (void)fclose(fp); } MEM_FREE_FUNC(system_path); } } if(material->toon_texture != NULL) { // トゥーンテクスチャの場合はモデルのディレクトリに画像があるか確認 (void)sprintf(utf8_path, "%s/%s", model->model_path, material->toon_texture); system_path = LocaleFromUTF8(utf8_path); name_length = (unsigned int)strlen(material->toon_texture); if(ght_get(name_table, name_length, material->toon_texture) == NULL) { if((fp = fopen(system_path, "rb")) != NULL) { // 画像有 (void)ght_insert(name_table, (void*)1, name_length, material->toon_texture); (void)fseek(fp, 0, SEEK_END); names[counter].name = material->toon_texture; names[counter].data_size = ftell(fp); names[counter].data_start = total_image_size + image_start; total_image_size += names[counter].data_size; rewind(fp); if(image_data_buffer_size < names[counter].data_size) { image_data = (uint8*)MEM_REALLOC_FUNC(image_data, names[counter].data_size); image_data_buffer_size = names[counter].data_size; } (void)fread(image_data, 1, names[counter].data_size, fp); (void)MemWrite(image_data, 1, names[counter].data_size, stream); counter++; (void)fclose(fp); } } MEM_FREE_FUNC(system_path); } } num_images = counter; ght_finalize(name_table); result = (uint8*)MEM_ALLOC_FUNC(image_start + total_image_size + sizeof(uint32)); result_stream.buff_ptr = result; result_stream.data_size = image_start + total_image_size; result_stream.block_size = 1; data32 = num_images; (void)MemWrite(&data32, sizeof(data32), 1, &result_stream); for(i=0; i<num_images; i++) { data32 = (uint32)strlen(names[i].name)+1; (void)MemWrite(&data32, sizeof(data32), 1, &result_stream); (void)MemWrite(names[i].name, 1, data32, &result_stream); data32 = names[i].data_start; (void)MemWrite(&data32, sizeof(data32), 1, &result_stream); data32 = names[i].data_size; (void)MemWrite(&data32, sizeof(data32), 1, &result_stream); } if((diff = (uint32)(image_start - result_stream.data_point)) > 0) { (void)MemSeek(&result_stream, sizeof(data32), SEEK_SET); for(i=0; i<num_images; i++) { data32 = (uint32)strlen(names[i].name)+1; (void)MemWrite(&data32, sizeof(data32), 1, &result_stream); (void)MemWrite(names[i].name, 1, data32, &result_stream); data32 = names[i].data_start - diff; (void)MemWrite(&data32, sizeof(data32), 1, &result_stream); data32 = names[i].data_start - diff; (void)MemWrite(&data32, sizeof(data32), 1, &result_stream); } image_start -= diff; } (void)MemWrite(stream->buff_ptr, 1, stream->data_point, &result_stream); if(out_data_size != NULL) { *out_data_size = image_start + total_image_size; } MEM_FREE_FUNC(image_data); MEM_FREE_FUNC(names); MEM_FREE_FUNC(materials); (void)DeleteMemoryStream(stream); return result; }