Beispiel #1
0
void nsCollect::ProcessData::SetFiles(int runIndex)
{
  ConcatInt(runIndex, "_S", processID, 2, 40);

  if (rangeOutputDesc.writeFile)
    ReplaceExtension(rngFile, rangeOutputFile.fileName, processID, ".nRng");

  if (optOutputDesc.writeFile)
    ReplaceExtension(optFile, optOutputFile.fileName, processID, ".nOpt");

  if (xyForwardOutputDesc.writeFile)
    ReplaceExtension(xyFile, xyForwardOutputFile.fileName, processID, ".nXYSim");
}
Beispiel #2
0
void AAI::InitAI(IGlobalAICallback* callback, int team)
{
	aicb = callback;
	cb = callback->GetAICallback();

	// open log file
	char filename[1000];
	char buffer[60];
	char team_number[3];
	
	#ifdef WIN32
		itoa(team, team_number, 10);
	#else
		snprintf(team_number,10,"%d",team);
	#endif
	
	strcpy(buffer, AILOG_PATH);
	strcat(buffer, "AAI_log_team_");
	strcat(buffer, team_number);
	strcat(buffer, ".txt");
	ReplaceExtension (buffer, filename, sizeof(filename), ".txt");
	cb->GetValue(AIVAL_LOCATE_FILE_W, filename);
	file = fopen(filename,"w");

	fprintf(file, "AAI %s running mod %s\n \n", AAI_VERSION, cb->GetModName());

	// load config file first
	cfg->LoadConfig(this);

	if(!cfg->initialized)
	{
		cb->SendTextMsg("Error: Could not load mod and/or general config file, see .../log/AILog.txt for further information",0);
		return;
	}

	// create buildtable
	bt = new AAIBuildTable(cb, this);
	bt->Init();
	
	// init unit table
	ut = new AAIUnitTable(this, bt);

	// init map
	map = new AAIMap(this);
	map->Init();

	// init brain
	brain = new AAIBrain(this);

	// init executer
	execute = new AAIExecute(this, brain);

	// create unit groups
	group_list = new list<AAIGroup*>[SEA_BUILDER+1];

	// init airforce manager
	af = new AAIAirForceManager(this, cb, bt);

	cb->SendTextMsg("AAI loaded",0);
}
Beispiel #3
0
bool Texture2D::BeginLoad(Deserializer& source)
{
    // In headless mode, do not actually load the texture, just return success
    if (!graphics_)
        return true;

    // If device is lost, retry later
    if (graphics_->IsDeviceLost())
    {
        URHO3D_LOGWARNING("Texture load while device is lost");
        dataPending_ = true;
        return true;
    }

    // Load the image data for EndLoad()
    loadImage_ = new Image(context_);
    if (!loadImage_->Load(source))
    {
        loadImage_.Reset();
        return false;
    }

    // Precalculate mip levels if async loading
    if (GetAsyncLoadState() == ASYNC_LOADING)
        loadImage_->PrecalculateLevels();

    // Load the optional parameters file
    ResourceCache* cache = GetSubsystem<ResourceCache>();
    String xmlName = ReplaceExtension(GetName(), ".xml");
    loadParameters_ = cache->GetTempResource<XMLFile>(xmlName, false);

    return true;
}
Beispiel #4
0
void CExportDlg::OnSelchangeFormatoptions()
{
	UpdateData();

	// check exporter has a file extension
	if (m_mgrImportExport.ExporterHasFileExtension(s_nFormatOption))
	{
		// enable path edit
		m_eExportPath.EnableWindow(TRUE);

		// check file extension is correct
		m_eExportPath.SetFilter(m_mgrImportExport.GetExporterFileFilter(s_nFormatOption));

		if (m_nExportOption == ACTIVETASKLIST || m_bExportOneFile)
		{
			if (m_sExportPath.IsEmpty())
			{
				m_sExportPath = m_sOrgFilePath;
			}

			ReplaceExtension(m_sExportPath, s_nFormatOption);
			UpdateData(FALSE);
		}
		else if (m_sExportPath.IsEmpty())
		{
			m_sExportPath = m_sOrgFolderPath;
		}
	}
	else // disable path edit and remove file path
	{
		m_eExportPath.SetWindowText(_T(""));
		m_eExportPath.EnableWindow(FALSE);
	}
}
Beispiel #5
0
void CExportDlg::OnSelchangeTasklistoptions()
{
	UpdateData();

	// can't do all tasklists and selected item
	if (m_taskSel.GetWantSelectedTasks() && m_nExportOption == ALLTASKLISTS)
	{
		m_taskSel.SetWantWhatTasks(TSDT_ALL);
	}

	// only process this notification if something's _really_ changed
	if (!(m_nExportOption == ALLTASKLISTS && m_bExportOneFile))
	{
		BOOL bFolder = (m_nExportOption == ALLTASKLISTS && !m_bExportOneFile);

		m_eExportPath.EnableStyle(FES_FOLDERS, bFolder);
		m_sPathLabel.LoadString(bFolder ? IDS_ED_FOLDER : IDS_ED_FILEPATH);

		// check file extension is correct
		if (m_nExportOption == ALLTASKLISTS && !m_bExportOneFile)
		{
			m_sExportPath = m_sFolderPath;
		}
		else
		{
			m_sExportPath = m_sFilePath;
			ReplaceExtension(m_sExportPath, s_nFormatOption);
		}
	}

	GetDlgItem(IDC_EXPORTONEFILE)->EnableWindow(!m_bSingleTaskList && m_nExportOption == ALLTASKLISTS);

	UpdateData(FALSE);
}
Beispiel #6
0
void Font::LoadParameters()
{
    ResourceCache* cache = GetSubsystem<ResourceCache>();
    String xmlName = ReplaceExtension(GetName(), ".xml");
    SharedPtr<XMLFile> xml = cache->GetTempResource<XMLFile>(xmlName, false);
    if (!xml)
        return;
    
    XMLElement rootElem = xml->GetRoot();
    
    XMLElement absoluteElem = rootElem.GetChild("absoluteoffset");
    if (!absoluteElem)
        absoluteElem = rootElem.GetChild("absolute");
    
    if (absoluteElem)
    {
        absoluteOffset_.x_ = absoluteElem.GetInt("x");
        absoluteOffset_.y_ = absoluteElem.GetInt("y");
    }
    
    XMLElement scaledElem = rootElem.GetChild("scaledoffset");
    if (!scaledElem)
        scaledElem = rootElem.GetChild("scaled");
    
    if (scaledElem)
    {
        scaledOffset_.x_ = scaledElem.GetFloat("x");
        scaledOffset_.y_ = scaledElem.GetFloat("y");
    }
}
bool Animation::Save(Serializer& dest) const
{
    // Write ID, name and length
    dest.WriteFileID("UANI");
    dest.WriteString(animationName_);
    dest.WriteFloat(length_);

    // Write tracks
    dest.WriteUInt(tracks_.Size());
    for (HashMap<StringHash, AnimationTrack>::ConstIterator i = tracks_.Begin(); i != tracks_.End(); ++i)
    {
        const AnimationTrack& track = i->second_;
        dest.WriteString(track.name_);
        dest.WriteUByte(track.channelMask_);
        dest.WriteUInt(track.keyFrames_.Size());

        // Write keyframes of the track
        for (unsigned j = 0; j < track.keyFrames_.Size(); ++j)
        {
            const AnimationKeyFrame& keyFrame = track.keyFrames_[j];
            dest.WriteFloat(keyFrame.time_);
            if (track.channelMask_ & CHANNEL_POSITION)
                dest.WriteVector3(keyFrame.position_);
            if (track.channelMask_ & CHANNEL_ROTATION)
                dest.WriteQuaternion(keyFrame.rotation_);
            if (track.channelMask_ & CHANNEL_SCALE)
                dest.WriteVector3(keyFrame.scale_);
        }
    }

    // If triggers have been defined, write an XML file for them
    if (!triggers_.Empty() || HasMetadata())
    {
        File* destFile = dynamic_cast<File*>(&dest);
        if (destFile)
        {
            String xmlName = ReplaceExtension(destFile->GetName(), ".xml");

            SharedPtr<XMLFile> xml(new XMLFile(context_));
            XMLElement rootElem = xml->CreateRoot("animation");

            for (unsigned i = 0; i < triggers_.Size(); ++i)
            {
                XMLElement triggerElem = rootElem.CreateChild("trigger");
                triggerElem.SetFloat("time", triggers_[i].time_);
                triggerElem.SetVariant(triggers_[i].data_);
            }

            SaveMetadataToXML(rootElem);

            File xmlFile(context_, xmlName, FILE_WRITE);
            xml->Save(xmlFile);
        }
        else
            ATOMIC_LOGWARNING("Can not save animation trigger data when not saving into a file");
    }

    return true;
}
Beispiel #8
0
//
// DeleteGwaFile
//
void DeleteGwaFile(const char *base_wad_name)
{
  char *gwa_file = ReplaceExtension(base_wad_name, "gwa");

  if (remove(gwa_file) == 0)
    PrintMsg("Deleted GWA file: %s\n", gwa_file);
 
  UtilFree(gwa_file);
}
Beispiel #9
0
void Texture::LoadParameters()
{
    ResourceCache* cache = GetSubsystem<ResourceCache>();
    String xmlName = ReplaceExtension(GetName(), ".xml");
    
    XMLFile* file = cache->GetResource<XMLFile>(xmlName, false);
    if (file)
        LoadParameters(file);
}
void CResourceCompilerHelper::GetInputFilename(
	const char* filename, 
	const unsigned int index,
	char* inputFilename, 
	size_t inputFilenameSizeInBytes)
{
	if (inputFilename == 0 || inputFilenameSizeInBytes < sizeof(inputFilename[0]))
	{
		return;
	}

	const char *ext = GetExtension(filename);

	if (ext && stricmp(ext, "dds") == 0)
	{
		switch(index)
		{
		case 0:
			ReplaceExtension(filename, "tif", inputFilename, inputFilenameSizeInBytes);
			return;
		case 1:
			ReplaceExtension(filename, "srf", inputFilename, inputFilenameSizeInBytes);
			return;
		default:
			inputFilename[0] = 0;
			return;
		}		
	}

	if (index > 0)
	{
		inputFilename[0] = 0;
		return;
	}

	strncpy_s(inputFilename, inputFilenameSizeInBytes, filename, _TRUNCATE);
}
void CResourceCompilerHelper::GetOutputFilename(const char* szFilePath, char* buffer, size_t bufferSizeInBytes)
{
	const char* const ext = GetExtension(szFilePath);

	if (ext)
	{
		if (stricmp(ext, "tif") == 0 ||
		    stricmp(ext, "hdr") == 0)
		{
			ReplaceExtension(szFilePath, "dds", buffer, bufferSizeInBytes);
			return;
		}
	}

	cry_strcpy(buffer, bufferSizeInBytes, szFilePath);
}
Beispiel #12
0
bool FileMisc::LogText(LPCTSTR szLine, bool bWantDateTime)
{
	CString sLogFile = GetAppFileName();
	ReplaceExtension(sLogFile, _T(".log"));

	CString sLogLine(szLine);

	if (bWantDateTime)
	{
		sLogLine += _T(" (");
		sLogLine += COleDateTime::GetCurrentTime().Format();
		sLogLine += _T(")");
	}

	return AppendLineToFile(sLogFile, sLogLine);
}
Beispiel #13
0
void Sound::LoadParameters()
{
    ResourceCache* cache = GetSubsystem<ResourceCache>();
    String xmlName = ReplaceExtension(GetName(), ".xml");
    
    if (!cache->Exists(xmlName))
        return;
    
    XMLFile* file = cache->GetResource<XMLFile>(xmlName);
    if (!file)
        return;
    
    XMLElement rootElem = file->GetRoot();
    XMLElement paramElem = rootElem.GetChild();
    
    while (paramElem)
    {
        String name = paramElem.GetName();
        
        if (name == "format" && !compressed_)
        {
            if (paramElem.HasAttribute("frequency"))
                frequency_ = paramElem.GetInt("frequency");
            if (paramElem.HasAttribute("sixteenbit"))
                sixteenBit_ = paramElem.GetBool("sixteenbit");
            if (paramElem.HasAttribute("16bit"))
                sixteenBit_ = paramElem.GetBool("16bit");
            if (paramElem.HasAttribute("stereo"))
                stereo_ = paramElem.GetBool("stereo");
        }
        
        if (name == "loop")
        {
            if (paramElem.HasAttribute("enable"))
                SetLooped(paramElem.GetBool("enable"));
            if (paramElem.HasAttribute("start") && paramElem.HasAttribute("end"))
                SetLoop(paramElem.GetInt("start"), paramElem.GetInt("end"));
        }
        
        paramElem = paramElem.GetNext();
    }
}
void StaticModel::ApplyMaterialList(const String& fileName)
{
    String useFileName = fileName;
    if (useFileName.Trimmed().Empty() && model_)
        useFileName = ReplaceExtension(model_->GetName(), ".txt");

    ResourceCache* cache = GetSubsystem<ResourceCache>();
    SharedPtr<File> file = cache->GetFile(useFileName, false);
    if (!file)
        return;

    unsigned index = 0;
    while (!file->IsEof() && index < batches_.Size())
    {
        Material* material = cache->GetResource<Material>(file->ReadLine());
        if (material)
            SetMaterial(index, material);

        ++index;
    }
}
bool ModConfig::Load (IGlobalAICallback *cb)
{
	char file[64];

	const char *mod = cb->GetAICallback()->GetModName ();
	ReplaceExtension (mod, file, 64, "cfg");
	
	// register the build options type:
	CfgValue::AddValueClass (&cfg_BuildOptionsType);

	// load config
	root = CfgValue::LoadFile (file);
	if (!root)
	{
		ChatMsgPrintf (cb->GetAICallback(), "Error loading mod config: %s", file);
		return false;
	}

	unitTypesInfo.Load (root, &buildTable);
	return true;
}
Beispiel #16
0
libDHStandard<T, B, S>::libDHStandard(struct libDHBase<T>::SPParameters* params) {
	DHParams = params;

	NumFeatures = 0;
	isMyGraph = true;
	isMyObs = true;
	phi = new struct Sample<GRAPH_TYPE>;
	phi->x = new std::vector<GRAPH_TYPE>;
	y = new std::vector<std::vector<size_t> >(DHParams->FeatureFiles.size(), std::vector<size_t>());

	T (*conversion)(T) = NULL;//&convFunc;

	for(std::vector<std::string>::iterator f=DHParams->FeatureFiles.begin(),f_e=DHParams->FeatureFiles.end();f!=f_e;++f) {
		GRAPH_TYPE tmp;
		if(DHParams->ReadBinary==1) {
			ReadRegionFileBinary(f->c_str(), tmp, true, conversion);
		} else {
			ReadRegionFile(f->c_str(), tmp, true, conversion);
		}
		phi->x->push_back(tmp);

		ReadObservationFile(ReplaceExtension(*f, std::string(".observation")).c_str(), y->at(f-DHParams->FeatureFiles.begin()));
	}

	for(size_t x=0,x_e=phi->x->size();x!=x_e;++x) {
		GRAPH_TYPE* ptr = &phi->x->at(x);
		for(typename GRAPH_TYPE::iterator rit=ptr->begin(),rit_e=ptr->end();rit!=rit_e;++rit) {
			typename S::MPNode* r = *rit;
			size_t maxEl = *std::max_element(r->featureIDs.begin(), r->featureIDs.end());
			NumFeatures = (maxEl>NumFeatures) ? maxEl : NumFeatures;
		}
	}
	++NumFeatures;

	for(size_t x=0,x_e=phi->x->size();x!=x_e;++x) {
		GRAPH_TYPE* ptr = &phi->x->at(x);
		rBP.push_back(new S(ptr, DHParams->epsilon));
		rBP.back()->Initialize();
	}
}
Beispiel #17
0
void CExportDlg::OnExportonefile()
{
	UpdateData();

	m_eExportPath.EnableStyle(FES_FOLDERS, (m_nExportOption == ALLTASKLISTS && !m_bExportOneFile));

	if (m_nExportOption == ALLTASKLISTS && !m_bExportOneFile)
	{
		m_sExportPath = m_sFolderPath;
	}
	else
	{
		m_sExportPath = m_sFilePath;
	}

	if (m_nExportOption == ACTIVETASKLIST || m_bExportOneFile)
	{
		ReplaceExtension(m_sExportPath, s_nFormatOption);
	}

	UpdateData(FALSE);
}
tstring CResourceCompilerHelper::GetInputFilename( const TCHAR *szFilePath, const unsigned int dwIndex ) const
{
	const TCHAR *ext = GetExtension(szFilePath);

	if(ext)
	{
		if(_tcsicmp(ext,_T("dds"))==0)
		{
			switch(dwIndex)
			{
				case 0: return ReplaceExtension(szFilePath,_T("tif"));	// index 0
//					case 1: return ReplaceExtension(szFilePath,".srf");	// index 1
				default: return _T("");	// last one
			}
		}
	}

	if(dwIndex)
		return _T("");				// last one

	return szFilePath;	// index 0
}
Beispiel #19
0
void StaticModel::ApplyMaterialList(const ea::string& fileName)
{
    ea::string useFileName = fileName;
    useFileName.trim();
    if (useFileName.empty() && model_)
        useFileName = ReplaceExtension(model_->GetName(), ".txt");

    auto* cache = GetSubsystem<ResourceCache>();
    ea::shared_ptr<File> file = cache->GetFile(useFileName, false);
    if (!file)
        return;

    unsigned index = 0;
    while (!file->IsEof() && index < batches_.size())
    {
        auto* material = cache->GetResource<Material>(file->ReadLine());
        if (material)
            SetMaterial(index, material);

        ++index;
    }
}
Beispiel #20
0
void Sound::LoadParameters()
{
    auto* cache = GetSubsystem<ResourceCache>();
    String xmlName = ReplaceExtension(GetName(), ".xml");

    SharedPtr<XMLFile> file(cache->GetTempResource<XMLFile>(xmlName, false));
    if (!file)
        return;

    XMLElement rootElem = file->GetRoot();
    LoadMetadataFromXML(rootElem);

    for (XMLElement paramElem = rootElem.GetChild(); paramElem; paramElem = paramElem.GetNext())
    {
        String name = paramElem.GetName();

        if (name == "format" && !compressed_)
        {
            if (paramElem.HasAttribute("frequency"))
                frequency_ = (unsigned)paramElem.GetInt("frequency");
            if (paramElem.HasAttribute("sixteenbit"))
                sixteenBit_ = paramElem.GetBool("sixteenbit");
            if (paramElem.HasAttribute("16bit"))
                sixteenBit_ = paramElem.GetBool("16bit");
            if (paramElem.HasAttribute("stereo"))
                stereo_ = paramElem.GetBool("stereo");
        }

        if (name == "loop")
        {
            if (paramElem.HasAttribute("enable"))
                SetLooped(paramElem.GetBool("enable"));
            if (paramElem.HasAttribute("start") && paramElem.HasAttribute("end"))
                SetLoop((unsigned)paramElem.GetInt("start"), (unsigned)paramElem.GetInt("end"));
        }
    }
}
Beispiel #21
0
void MeshCompiler::CompileMaterial( TiXmlElement* Material )
{
	SMaterial NewMaterial = { 0 };

	TiXmlAttribute* MatAttr = Material->FirstAttribute();
	const char* pTypeName = MatAttr->Value();
	if( strcmp( pTypeName, "Diffuse" ) == 0 )
	{
		NewMaterial.m_Type = EMT_DIFFUSE;
	}
	else if( strcmp( pTypeName, "Normal" ) == 0 )
	{
		NewMaterial.m_Type = EMT_NORMAL;
	}

	MatAttr = MatAttr->Next();
	const char* pFilename = MatAttr->Value();
	CleanStrncpy( NewMaterial.m_Filename, FileUtil::StripLeadingUpFolders( pFilename ), MAT_FILENAME_LENGTH );

	SimpleString FilenameAsString( NewMaterial.m_Filename );
	FilenameAsString.Replace( '\\', '/' );

	CleanStrncpy( NewMaterial.m_Filename, FilenameAsString.CStr(), MAT_FILENAME_LENGTH );

	if( FilenameAsString.Contains( "NODXT" ) )
	{
		// Leave the extension alone
	}
	else
	{
		ReplaceExtension( NewMaterial.m_Filename, ".tga", ".dds" );
	}

	m_Materials.PushBack( NewMaterial );
	++m_Header.m_NumMaterials;
}
FIMULTIBITMAP * DLL_CALLCONV
FreeImage_OpenMultiBitmap(FREE_IMAGE_FORMAT fif, const char *filename, BOOL create_new, BOOL read_only, BOOL keep_cache_in_memory, int flags) {
	// sanity check on the parameters

	if (create_new)
		read_only = FALSE;

	// retrieve the plugin list to find the node belonging to this plugin

	PluginList *list = FreeImage_GetPluginList();

	if (list) {
		PluginNode *node = list->FindNodeFromFIF(fif);

		if (node) {
			FreeImageIO *io = new FreeImageIO;

			if (io) {
				SetDefaultIO(io);

				BOOL cont = TRUE;

				FILE *handle = NULL;

				if (!create_new) {
					handle = fopen(filename, "rb");

					if (handle == NULL) {
						cont = FALSE;
					}
				}

				if (cont) {
					FIMULTIBITMAP *bitmap = new FIMULTIBITMAP;

					if (bitmap) {
						MULTIBITMAPHEADER *header = new MULTIBITMAPHEADER;

						header->m_filename = new char[strlen(filename) + 1];
						strcpy(header->m_filename, filename);
						header->node = node;
						header->fif = fif;
						header->io = io;
						header->handle = handle;						
						header->changed = FALSE;						
						header->read_only = read_only;
						header->m_cachefile = NULL;
						header->cache_fif = fif;
						header->load_flags = flags;

						if (header) {
							// store the MULTIBITMAPHEADER in the surrounding FIMULTIBITMAP structure

							bitmap->data = header;

							// cache the page count

							header->page_count = FreeImage_InternalGetPageCount(bitmap);

							// allocate a continueus block to describe the bitmap

							if (!create_new)
								header->m_blocks.push_back((BlockTypeS *)new BlockContinueus(0, header->page_count - 1));

							// set up the cache

							if (!read_only) {
								char cache_name[256];
								ReplaceExtension(cache_name, filename, "ficache");

								CacheFile *cache_file = new CacheFile(cache_name, keep_cache_in_memory);

								if (cache_file->open()) {
									header->m_cachefile = cache_file;

									// return the multibitmap

									return bitmap;
								}

								delete cache_file;
								delete header;
							}

							return bitmap;
						}
						
						return NULL;
					}
				}
			}

			delete io;
		}
	}

	return NULL;
}
Beispiel #23
0
bool Animation::BeginLoad(Deserializer& source)
{
    unsigned memoryUse = sizeof(Animation);

    // Check ID
    if (source.ReadFileID() != "UANI")
    {
        URHO3D_LOGERROR(source.GetName() + " is not a valid animation file");
        return false;
    }

    // Read name and length
    animationName_ = source.ReadString();
    animationNameHash_ = animationName_;
    length_ = source.ReadFloat();
    tracks_.Clear();

    unsigned tracks = source.ReadUInt();
    memoryUse += tracks * sizeof(AnimationTrack);

    // Read tracks
    for (unsigned i = 0; i < tracks; ++i)
    {
        AnimationTrack* newTrack = CreateTrack(source.ReadString());
        newTrack->channelMask_ = source.ReadUByte();

        unsigned keyFrames = source.ReadUInt();
        newTrack->keyFrames_.Resize(keyFrames);
        memoryUse += keyFrames * sizeof(AnimationKeyFrame);

        // Read keyframes of the track
        for (unsigned j = 0; j < keyFrames; ++j)
        {
            AnimationKeyFrame& newKeyFrame = newTrack->keyFrames_[j];
            newKeyFrame.time_ = source.ReadFloat();
            if (newTrack->channelMask_ & CHANNEL_POSITION)
                newKeyFrame.position_ = source.ReadVector3();
            if (newTrack->channelMask_ & CHANNEL_ROTATION)
                newKeyFrame.rotation_ = source.ReadQuaternion();
            if (newTrack->channelMask_ & CHANNEL_SCALE)
                newKeyFrame.scale_ = source.ReadVector3();
        }
    }

    // Optionally read triggers from an XML file
    ResourceCache* cache = GetSubsystem<ResourceCache>();
    String xmlName = ReplaceExtension(GetName(), ".xml");

    SharedPtr<XMLFile> file(cache->GetTempResource<XMLFile>(xmlName, false));
    if (file)
    {
        XMLElement rootElem = file->GetRoot();
        XMLElement triggerElem = rootElem.GetChild("trigger");
        while (triggerElem)
        {
            if (triggerElem.HasAttribute("normalizedtime"))
                AddTrigger(triggerElem.GetFloat("normalizedtime"), true, triggerElem.GetVariant());
            else if (triggerElem.HasAttribute("time"))
                AddTrigger(triggerElem.GetFloat("time"), false, triggerElem.GetVariant());

            triggerElem = triggerElem.GetNext("trigger");
        }

        memoryUse += triggers_.Size() * sizeof(AnimationTriggerPoint);
        SetMemoryUse(memoryUse);
        return true;
    }

    // Optionally read triggers from a JSON file
    String jsonName = ReplaceExtension(GetName(), ".json");

    SharedPtr<JSONFile> jsonFile(cache->GetTempResource<JSONFile>(jsonName, false));
    if (jsonFile)
    {
        const JSONValue& rootVal = jsonFile->GetRoot();
        JSONArray triggerArray = rootVal.Get("triggers").GetArray();

        for (unsigned i = 0; i < triggerArray.Size(); i++)
        {
            const JSONValue& triggerValue = triggerArray.At(i);
            JSONValue normalizedTimeValue = triggerValue.Get("normalizedTime");
            if (!normalizedTimeValue.IsNull())
                AddTrigger(normalizedTimeValue.GetFloat(), true, triggerValue.GetVariant());
            else
            {
                JSONValue timeVal = triggerValue.Get("time");
                if (!timeVal.IsNull())
                    AddTrigger(timeVal.GetFloat(), false, triggerValue.GetVariant());
            }
        }

        memoryUse += triggers_.Size() * sizeof(AnimationTriggerPoint);
        SetMemoryUse(memoryUse);
        return true;
    }

    SetMemoryUse(memoryUse);
    return true;
}
Beispiel #24
0
BOOL DLL_CALLCONV
FreeImage_CloseMultiBitmap(FIMULTIBITMAP *bitmap, int flags) {
	if (bitmap) {
		BOOL success = TRUE;
		
		if (bitmap->data) {
			MULTIBITMAPHEADER *header = FreeImage_GetMultiBitmapHeader(bitmap);			
			
			// saves changes only of images loaded directly from a file
			if (header->changed && header->m_filename) {
				try {
					// open a temp file

					std::string spool_name;

					ReplaceExtension(spool_name, header->m_filename, "fispool");

					// open the spool file and the source file
        
					FILE *f = fopen(spool_name.c_str(), "w+b");
				
					// saves changes
					if (f == NULL) {
						FreeImage_OutputMessageProc(header->fif, "Failed to open %s, %s", spool_name.c_str(), strerror(errno));
						success = FALSE;
					} else {
						success = FreeImage_SaveMultiBitmapToHandle(header->fif, bitmap, header->io, (fi_handle)f, flags);

						// close the files

						if (fclose(f) != 0) {
							success = FALSE;
							FreeImage_OutputMessageProc(header->fif, "Failed to close %s, %s", spool_name.c_str(), strerror(errno));
						}
					}
					if (header->handle) {
						fclose((FILE *)header->handle);
					}
				
					// applies changes to the destination file

					if (success) {
						remove(header->m_filename);
						success = (rename(spool_name.c_str(), header->m_filename) == 0) ? TRUE:FALSE;
						if(!success) {
							FreeImage_OutputMessageProc(header->fif, "Failed to rename %s to %s", spool_name.c_str(), header->m_filename);
						}
					} else {
						remove(spool_name.c_str());
					}
				} catch (std::bad_alloc &) {
					success = FALSE;
				}

			} else {
				if (header->handle && header->m_filename) {
					fclose((FILE *)header->handle);
				}
			}

			// clear the blocks list

			for (BlockListIterator i = header->m_blocks.begin(); i != header->m_blocks.end(); ++i) {
				delete *i;
			}

			// flush and dispose the cache

			if (header->m_cachefile) {
				header->m_cachefile->close();
				delete header->m_cachefile;
			}

			// delete the last open bitmaps

			while (!header->locked_pages.empty()) {
				FreeImage_Unload(header->locked_pages.begin()->first);

				header->locked_pages.erase(header->locked_pages.begin()->first);
			}

			// get rid of the IO structure

			delete header->io;

			// delete the filename

			if(header->m_filename) {
				delete[] header->m_filename;
			}

			// delete the FIMULTIBITMAPHEADER

			delete header;
		}

		delete bitmap;

		return success;
	}

	return FALSE;
}
Beispiel #25
0
FIMULTIBITMAP * DLL_CALLCONV
FreeImage_OpenMultiBitmap(FREE_IMAGE_FORMAT fif, const char *filename, BOOL create_new, BOOL read_only, BOOL keep_cache_in_memory, int flags) {

	FILE *handle = NULL;
	try {
		// sanity check on the parameters

		if (create_new) {
			read_only = FALSE;
		}

		// retrieve the plugin list to find the node belonging to this plugin

		PluginList *list = FreeImage_GetPluginList();

		if (list) {
			PluginNode *node = list->FindNodeFromFIF(fif);

			if (node) {
				std::auto_ptr<FreeImageIO> io (new FreeImageIO);

				SetDefaultIO(io.get());

				if (!create_new) {
					handle = fopen(filename, "rb");
					if (handle == NULL) {
						return NULL;
					}
				}

				std::auto_ptr<FIMULTIBITMAP> bitmap (new FIMULTIBITMAP);
				std::auto_ptr<MULTIBITMAPHEADER> header (new MULTIBITMAPHEADER);
				header->m_filename = new char[strlen(filename) + 1];
				strcpy(header->m_filename, filename);
				header->node = node;
				header->fif = fif;
				header->io = io.get ();
				header->handle = handle;
				header->changed = FALSE;
				header->read_only = read_only;
				header->m_cachefile = NULL;
				header->cache_fif = fif;
				header->load_flags = flags;

				// store the MULTIBITMAPHEADER in the surrounding FIMULTIBITMAP structure

				bitmap->data = header.get();

				// cache the page count

				header->page_count = FreeImage_InternalGetPageCount(bitmap.get());

				// allocate a continueus block to describe the bitmap

				if (!create_new) {
					header->m_blocks.push_back((BlockTypeS *)new BlockContinueus(0, header->page_count - 1));
				}

				// set up the cache

				if (!read_only) {
					std::string cache_name;
					ReplaceExtension(cache_name, filename, "ficache");

					std::auto_ptr<CacheFile> cache_file (new CacheFile(cache_name, keep_cache_in_memory));

					if (cache_file->open()) {
						// we can use release() as std::bad_alloc won't be thrown from here on
						header->m_cachefile = cache_file.release();
					} else {
						// an error occured ...
						fclose(handle);
						return NULL;
					}
				}
				// return the multibitmap
				// std::bad_alloc won't be thrown from here on
				header.release(); // now owned by bitmap
				io.release();	  // now owned by bitmap
				return bitmap.release(); // now owned by caller
			}
		}
	} catch (std::bad_alloc &) {
		/** @todo report error */
	}
	if (handle)
		fclose(handle);
	return NULL;
}
Beispiel #26
0
void WriteOutput(const String& outputFileName, bool exportAnimations, bool rotationsOnly, bool saveMaterialList)
{
    // Begin serialization
    {
        File dest(context_);
        if (!dest.Open(outputFileName, FILE_WRITE))
            ErrorExit("Could not open output file " + outputFileName);

        // ID
        dest.WriteFileID("UMDL");

        // Vertexbuffers
        dest.WriteUInt(vertexBuffers_.Size());
        for (unsigned i = 0; i < vertexBuffers_.Size(); ++i)
            vertexBuffers_[i].WriteData(dest);

        // Indexbuffers
        dest.WriteUInt(indexBuffers_.Size());
        for (unsigned i = 0; i < indexBuffers_.Size(); ++i)
            indexBuffers_[i].WriteData(dest);

        // Subgeometries
        dest.WriteUInt(subGeometries_.Size());
        for (unsigned i = 0; i < subGeometries_.Size(); ++i)
        {
            // Write bone mapping info from the first LOD level. It does not change for further LODs
            dest.WriteUInt(subGeometries_[i][0].boneMapping_.Size());
            for (unsigned k = 0; k < subGeometries_[i][0].boneMapping_.Size(); ++k)
                dest.WriteUInt(subGeometries_[i][0].boneMapping_[k]);

            // Lod levels for this subgeometry
            dest.WriteUInt(subGeometries_[i].Size());
            for (unsigned j = 0; j < subGeometries_[i].Size(); ++j)
            {
                dest.WriteFloat(subGeometries_[i][j].distance_);
                dest.WriteUInt((unsigned)subGeometries_[i][j].primitiveType_);
                dest.WriteUInt(subGeometries_[i][j].vertexBuffer_);
                dest.WriteUInt(subGeometries_[i][j].indexBuffer_);
                dest.WriteUInt(subGeometries_[i][j].indexStart_);
                dest.WriteUInt(subGeometries_[i][j].indexCount_);
            }
        }

        // Morphs
        dest.WriteUInt(morphs_.Size());
        for (unsigned i = 0; i < morphs_.Size(); ++i)
            morphs_[i].WriteData(dest);

        // Skeleton
        dest.WriteUInt(bones_.Size());
        for (unsigned i = 0; i < bones_.Size(); ++i)
        {
            dest.WriteString(bones_[i].name_);
            dest.WriteUInt(bones_[i].parentIndex_);
            dest.WriteVector3(bones_[i].bindPosition_);
            dest.WriteQuaternion(bones_[i].bindRotation_);
            dest.WriteVector3(bones_[i].bindScale_);

            Matrix3x4 offsetMatrix(bones_[i].derivedPosition_, bones_[i].derivedRotation_, bones_[i].derivedScale_);
            offsetMatrix = offsetMatrix.Inverse();
            dest.Write(offsetMatrix.Data(), sizeof(Matrix3x4));

            dest.WriteUByte(bones_[i].collisionMask_);
            if (bones_[i].collisionMask_ & 1)
                dest.WriteFloat(bones_[i].radius_);
            if (bones_[i].collisionMask_ & 2)
                dest.WriteBoundingBox(bones_[i].boundingBox_);
        }

        // Bounding box
        dest.WriteBoundingBox(boundingBox_);

        // Geometry centers
        for (unsigned i = 0; i < subGeometryCenters_.Size(); ++i)
            dest.WriteVector3(subGeometryCenters_[i]);
    }

    if (saveMaterialList)
    {
        String materialListName = ReplaceExtension(outputFileName, ".txt");
        File listFile(context_);
        if (listFile.Open(materialListName, FILE_WRITE))
        {
            for (unsigned i = 0; i < materialNames_.Size(); ++i)
            {
                // Assume the materials will be located inside the standard Materials subdirectory
                listFile.WriteLine("Materials/" + ReplaceExtension(SanitateAssetName(materialNames_[i]), ".xml"));
            }
        }
        else
            PrintLine("Warning: could not write material list file " + materialListName);
    }

    XMLElement skeletonRoot = skelFile_->GetRoot("skeleton");
    if (skeletonRoot && exportAnimations)
    {
        // Go through animations
        XMLElement animationsRoot = skeletonRoot.GetChild("animations");
        if (animationsRoot)
        {
            XMLElement animation = animationsRoot.GetChild("animation");
            while (animation)
            {
                ModelAnimation newAnimation;
                newAnimation.name_ = animation.GetAttribute("name");
                newAnimation.length_ = animation.GetFloat("length");

                XMLElement tracksRoot = animation.GetChild("tracks");
                XMLElement track = tracksRoot.GetChild("track");
                while (track)
                {
                    String trackName = track.GetAttribute("bone");
                    ModelBone* bone = 0;
                    for (unsigned i = 0; i < bones_.Size(); ++i)
                    {
                        if (bones_[i].name_ == trackName)
                        {
                            bone = &bones_[i];
                            break;
                        }
                    }
                    if (!bone)
                        ErrorExit("Found animation track for unknown bone " + trackName);

                    AnimationTrack newAnimationTrack;
                    newAnimationTrack.name_ = trackName;
                    if (!rotationsOnly)
                        newAnimationTrack.channelMask_ = CHANNEL_POSITION | CHANNEL_ROTATION;
                    else
                        newAnimationTrack.channelMask_ = CHANNEL_ROTATION;

                    XMLElement keyFramesRoot = track.GetChild("keyframes");
                    XMLElement keyFrame = keyFramesRoot.GetChild("keyframe");
                    while (keyFrame)
                    {
                        AnimationKeyFrame newKeyFrame;

                        // Convert from right- to left-handed
                        XMLElement position = keyFrame.GetChild("translate");
                        float x = position.GetFloat("x");
                        float y = position.GetFloat("y");
                        float z = position.GetFloat("z");
                        Vector3 pos(x, y, -z);

                        XMLElement rotation = keyFrame.GetChild("rotate");
                        XMLElement axis = rotation.GetChild("axis");
                        float angle = -rotation.GetFloat("angle") * M_RADTODEG;
                        x = axis.GetFloat("x");
                        y = axis.GetFloat("y");
                        z = axis.GetFloat("z");
                        Vector3 axisVec(x, y, -z);
                        Quaternion rot(angle, axisVec);

                        // Transform from bind-pose relative into absolute
                        pos = bone->bindPosition_ + bone->bindRotation_ * pos;
                        rot = bone->bindRotation_ * rot;

                        newKeyFrame.time_ = keyFrame.GetFloat("time");
                        newKeyFrame.position_ = pos;
                        newKeyFrame.rotation_ = rot;

                        newAnimationTrack.keyFrames_.Push(newKeyFrame);
                        keyFrame = keyFrame.GetNext("keyframe");
                    }

                    // Make sure keyframes are sorted from beginning to end
                    Sort(newAnimationTrack.keyFrames_.Begin(), newAnimationTrack.keyFrames_.End(), CompareKeyFrames);

                    // Do not add tracks with no keyframes
                    if (newAnimationTrack.keyFrames_.Size())
                        newAnimation.tracks_.Push(newAnimationTrack);

                    track = track.GetNext("track");
                }

                // Write each animation into a separate file
                String animationFileName = outputFileName.Replaced(".mdl", "");
                animationFileName += "_" + newAnimation.name_ + ".ani";

                File dest(context_);
                if (!dest.Open(animationFileName, FILE_WRITE))
                    ErrorExit("Could not open output file " + animationFileName);

                dest.WriteFileID("UANI");
                dest.WriteString(newAnimation.name_);
                dest.WriteFloat(newAnimation.length_);
                dest.WriteUInt(newAnimation.tracks_.Size());
                for (unsigned i = 0; i < newAnimation.tracks_.Size(); ++i)
                {
                    AnimationTrack& track = newAnimation.tracks_[i];
                    dest.WriteString(track.name_);
                    dest.WriteUByte(track.channelMask_);
                    dest.WriteUInt(track.keyFrames_.Size());
                    for (unsigned j = 0; j < track.keyFrames_.Size(); ++j)
                    {
                        AnimationKeyFrame& keyFrame = track.keyFrames_[j];
                        dest.WriteFloat(keyFrame.time_);
                        if (track.channelMask_ & CHANNEL_POSITION)
                            dest.WriteVector3(keyFrame.position_);
                        if (track.channelMask_ & CHANNEL_ROTATION)
                            dest.WriteQuaternion(keyFrame.rotation_);
                        if (track.channelMask_ & CHANNEL_SCALE)
                            dest.WriteVector3(keyFrame.scale_);
                    }
                }

                animation = animation.GetNext("animation");
                PrintLine("Processed animation " + newAnimation.name_);
            }
        }
    }
}
Beispiel #27
0
bool Animation::Load(Deserializer& source)
{
    PROFILE(LoadAnimation);
    
    unsigned memoryUse = sizeof(Animation);
    
    // Check ID
    if (source.ReadFileID() != "UANI")
    {
        LOGERROR(source.GetName() + " is not a valid animation file");
        return false;
    }
    
    // Read name and length
    animationName_ = source.ReadString();
    animationNameHash_ = animationName_;
    length_ = source.ReadFloat();
    tracks_.Clear();
    
    unsigned tracks = source.ReadUInt();
    tracks_.Resize(tracks);
    memoryUse += tracks * sizeof(AnimationTrack);
    
    // Read tracks
    for (unsigned i = 0; i < tracks; ++i)
    {
        AnimationTrack& newTrack = tracks_[i];
        newTrack.name_ = source.ReadString();
        newTrack.nameHash_ = newTrack.name_;
        newTrack.channelMask_ = source.ReadUByte();
        
        unsigned keyFrames = source.ReadUInt();
        newTrack.keyFrames_.Resize(keyFrames);
        memoryUse += keyFrames * sizeof(AnimationKeyFrame);
        
        // Read keyframes of the track
        for (unsigned j = 0; j < keyFrames; ++j)
        {
            AnimationKeyFrame& newKeyFrame = newTrack.keyFrames_[j];
            newKeyFrame.time_ = source.ReadFloat();
            if (newTrack.channelMask_ & CHANNEL_POSITION)
                newKeyFrame.position_ = source.ReadVector3();
            if (newTrack.channelMask_ & CHANNEL_ROTATION)
                newKeyFrame.rotation_ = source.ReadQuaternion();
            if (newTrack.channelMask_ & CHANNEL_SCALE)
                newKeyFrame.scale_ = source.ReadVector3();
        }
    }
    
    // Optionally read triggers from an XML file
    ResourceCache* cache = GetSubsystem<ResourceCache>();
    String xmlName = ReplaceExtension(GetName(), ".xml");
    
    if (cache->Exists(xmlName))
    {
        XMLFile* file = cache->GetResource<XMLFile>(xmlName);
        if (file)
        {
            XMLElement rootElem = file->GetRoot();
            XMLElement triggerElem = rootElem.GetChild("trigger");
            while (triggerElem)
            {
                if (triggerElem.HasAttribute("normalizedtime"))
                    AddTrigger(triggerElem.GetFloat("normalizedtime"), true, triggerElem.GetVariant());
                else if (triggerElem.HasAttribute("time"))
                    AddTrigger(triggerElem.GetFloat("time"), false, triggerElem.GetVariant());
                
                triggerElem = triggerElem.GetNext("trigger");
            }
            
            memoryUse += triggers_.Size() * sizeof(AnimationTriggerPoint);
        }
    }
    
    SetMemoryUse(memoryUse);
    return true;
}
BOOL DLL_CALLCONV
FreeImage_CloseMultiBitmap(FIMULTIBITMAP *bitmap, int flags) {
	if (bitmap) {
		BOOL success = TRUE;

		if (bitmap->data) {
			MULTIBITMAPHEADER *header = FreeImage_GetMultiBitmapHeader(bitmap);			

			if (header->changed) {
				// open a temp file

				char spool_name[256];

				ReplaceExtension(spool_name, header->m_filename, "fispool");

				// open the spool file and the source file

				FILE *f = fopen(spool_name, "w+b");

				void *data = FreeImage_Open(header->node, header->io, (fi_handle)f, FALSE);
				void *data_read = NULL;

				if (header->handle) {
					header->io->seek_proc(header->handle, 0, SEEK_SET);

			   		data_read = FreeImage_Open(header->node, header->io, header->handle, TRUE);
				}

				// write all the pages to the temp file

				int count = 0;				

				for (BlockListIterator i = header->m_blocks.begin(); i != header->m_blocks.end(); i++) {
					if (success) {
						switch((*i)->m_type) {
							case BLOCK_CONTINUEUS :
							{
								BlockContinueus *block = (BlockContinueus *)(*i);

								for (int j = block->m_start; j <= block->m_end; j++) {
									FIBITMAP *dib = header->node->m_plugin->load_proc(header->io, header->handle, j, header->load_flags, data_read);

									success = header->node->m_plugin->save_proc(header->io, dib, (fi_handle)f, count, flags, data);
									count++;

									FreeImage_Unload(dib);
								}

								break;
							}

							case BLOCK_REFERENCE :
							{
								BlockReference *ref = (BlockReference *)(*i);

								// read the compressed data

								BYTE *compressed_data = (BYTE*)malloc(ref->m_size * sizeof(BYTE));

								header->m_cachefile->readFile((BYTE *)compressed_data, ref->m_reference, ref->m_size);

								// uncompress the data

								FIMEMORY *hmem = FreeImage_OpenMemory(compressed_data, ref->m_size);
								FIBITMAP *dib = FreeImage_LoadFromMemory(header->cache_fif, hmem, 0);
								FreeImage_CloseMemory(hmem);

								// get rid of the buffer
								free(compressed_data);

								// save the data

								success = header->node->m_plugin->save_proc(header->io, dib, (fi_handle)f, count, flags, data);
								count++;

								// unload the dib

								FreeImage_Unload(dib);

								break;
							}
						}
					} else {
						break;
					}
				}

				// close the files

				FreeImage_Close(header->node, header->io, (fi_handle)f, data); 

				fclose(f);

				if (header->handle) {
					FreeImage_Close(header->node, header->io, header->handle, data_read);

					fclose((FILE *)header->handle);
				}	

				if (success) {
					remove(header->m_filename);

					rename(spool_name, header->m_filename);
				} else {
					remove(spool_name);
				}
			} else {
				if (header->handle && header->m_filename) {
					fclose((FILE *)header->handle);
				}
			}

			// clear the blocks list

			for (BlockListIterator i = header->m_blocks.begin(); i != header->m_blocks.end(); ++i)
				delete *i;

			// flush and dispose the cache

			if (header->m_cachefile) {
				header->m_cachefile->close();

				delete header->m_cachefile;
			}

			// delete the last open bitmaps

			while (!header->locked_pages.empty()) {
				FreeImage_Unload(header->locked_pages.begin()->first);

				header->locked_pages.erase(header->locked_pages.begin()->first);
			}

			// get rid of the IO structure

			delete header->io;

			// delete the filename

			if(header->m_filename)
				delete[] header->m_filename;

			// delete the FIMULTIBITMAPHEADER

			delete header;
		}

		delete bitmap;

		return success;
	}

	return FALSE;
}
Beispiel #29
0
bool Model::Save(Serializer& dest) const
{
    // Write ID
    if (!dest.WriteFileID("UMD2"))
        return false;

    // Write vertex buffers
    dest.WriteUInt(vertexBuffers_.Size());
    for (unsigned i = 0; i < vertexBuffers_.Size(); ++i)
    {
        VertexBuffer* buffer = vertexBuffers_[i];
        dest.WriteUInt(buffer->GetVertexCount());
        const PODVector<VertexElement>& elements = buffer->GetElements();
        dest.WriteUInt(elements.Size());
        for (unsigned j = 0; j < elements.Size(); ++j)
        {
            unsigned elementDesc = ((unsigned)elements[j].type_) |
                (((unsigned)elements[j].semantic_) << 8) |
                (((unsigned)elements[j].index_) << 16);
            dest.WriteUInt(elementDesc);
        }
        dest.WriteUInt(morphRangeStarts_[i]);
        dest.WriteUInt(morphRangeCounts_[i]);
        dest.Write(buffer->GetShadowData(), buffer->GetVertexCount() * buffer->GetVertexSize());
    }
    // Write index buffers
    dest.WriteUInt(indexBuffers_.Size());
    for (unsigned i = 0; i < indexBuffers_.Size(); ++i)
    {
        IndexBuffer* buffer = indexBuffers_[i];
        dest.WriteUInt(buffer->GetIndexCount());
        dest.WriteUInt(buffer->GetIndexSize());
        dest.Write(buffer->GetShadowData(), buffer->GetIndexCount() * buffer->GetIndexSize());
    }
    // Write geometries
    dest.WriteUInt(geometries_.Size());
    for (unsigned i = 0; i < geometries_.Size(); ++i)
    {
        // Write bone mappings
        dest.WriteUInt(geometryBoneMappings_[i].Size());
        for (unsigned j = 0; j < geometryBoneMappings_[i].Size(); ++j)
            dest.WriteUInt(geometryBoneMappings_[i][j]);

        // Write the LOD levels
        dest.WriteUInt(geometries_[i].Size());
        for (unsigned j = 0; j < geometries_[i].Size(); ++j)
        {
            Geometry* geometry = geometries_[i][j];
            dest.WriteFloat(geometry->GetLodDistance());
            dest.WriteUInt(geometry->GetPrimitiveType());
            dest.WriteUInt(LookupVertexBuffer(geometry->GetVertexBuffer(0), vertexBuffers_));
            dest.WriteUInt(LookupIndexBuffer(geometry->GetIndexBuffer(), indexBuffers_));
            dest.WriteUInt(geometry->GetIndexStart());
            dest.WriteUInt(geometry->GetIndexCount());
        }
    }

    // Write morphs
    dest.WriteUInt(morphs_.Size());
    for (unsigned i = 0; i < morphs_.Size(); ++i)
    {
        dest.WriteString(morphs_[i].name_);
        dest.WriteUInt(morphs_[i].buffers_.Size());

        // Write morph vertex buffers
        for (HashMap<unsigned, VertexBufferMorph>::ConstIterator j = morphs_[i].buffers_.Begin();
             j != morphs_[i].buffers_.End(); ++j)
        {
            dest.WriteUInt(j->first_);
            dest.WriteUInt(j->second_.elementMask_);
            dest.WriteUInt(j->second_.vertexCount_);

            // Base size: size of each vertex index
            unsigned vertexSize = sizeof(unsigned);
            // Add size of individual elements
            if (j->second_.elementMask_ & MASK_POSITION)
                vertexSize += sizeof(Vector3);
            if (j->second_.elementMask_ & MASK_NORMAL)
                vertexSize += sizeof(Vector3);
            if (j->second_.elementMask_ & MASK_TANGENT)
                vertexSize += sizeof(Vector3);

            dest.Write(j->second_.morphData_.Get(), vertexSize * j->second_.vertexCount_);
        }
    }

    // Write skeleton
    skeleton_.Save(dest);

    // Write bounding box
    dest.WriteBoundingBox(boundingBox_);

    // Write geometry centers
    for (unsigned i = 0; i < geometryCenters_.Size(); ++i)
        dest.WriteVector3(geometryCenters_[i]);

    // Write metadata
    if (HasMetadata())
    {
        File* destFile = dynamic_cast<File*>(&dest);
        if (destFile)
        {
            String xmlName = ReplaceExtension(destFile->GetName(), ".xml");

            SharedPtr<XMLFile> xml(new XMLFile(context_));
            XMLElement rootElem = xml->CreateRoot("model");
            SaveMetadataToXML(rootElem);

            File xmlFile(context_, xmlName, FILE_WRITE);
            xml->Save(xmlFile);
        }
        else
            URHO3D_LOGWARNING("Can not save model metadata when not saving into a file");
    }

    return true;
}
void BuildTable::Init (IAICallback *callback, bool cache)
{
	cb = callback;

	char cachefn[80];
	ReplaceExtension (cb->GetModName (), cachefn, sizeof(cachefn), "modcache");
	if (cache) {
		if (LoadCache (cachefn))
			return;
	}

	// this is what makes loading times long, because spring will load unit defs only when they're needed.
	// meaning, GetUnitDefs() will make spring load all the unit defs at once.
	numDefs = cb->GetNumUnitDefs();
	deflist = new UDef[numDefs];

	const UnitDef** templist=new const UnitDef*[numDefs];
	cb->GetUnitDefList (templist);
	for (int a=0;a<numDefs;a++)
	{
		UDef& d = deflist[a];
		d.def = templist[a];
		d.cost.energy = d.def->energyCost;
		d.cost.metal = d.def->metalCost;
		d.make.energy = d.def->energyMake;
		d.make.metal = d.def->metalMake;
		if (d.def->activateWhenBuilt)
		{ // Solars have negative energy upkeep so they can be disabled
			d.make.energy -= d.def->energyUpkeep;
			d.make.metal += d.def->makesMetal;
			d.make.metal -= d.def->metalUpkeep;
		}
		d.storage.energy = d.def->energyStorage;
		d.storage.metal = d.def->metalStorage;
		d.metalExtractDepth = d.def->extractsMetal;
		d.buildTime = d.def->buildTime;
		d.energyUse = d.def->energyUpkeep;
		d.buildSpeed = d.def->buildSpeed;
		d.numBuildOptions = d.def->buildOptions.size();

		d.flags = 0;
		if (!d.def->buildOptions.empty ()) d.flags |= CUD_Builder;
		if (d.def->type == "Building" || d.def->type == "Factory" || d.def->type == "MetalExtractor")
			d.flags |= CUD_Building;
		if (d.def->windGenerator) d.flags |= CUD_WindGen;
		if (d.def->movedata)  {
			d.moveType = d.def->movedata->moveType;
			d.flags |= CUD_MoveType;
		}
		
		deflist[a].def = templist[a];
		deflist[a].name = templist[a]->name;

		d.weaponDamage = 0.0f;
		d.weaponRange = 0.0f;

		for (int b=0;b<d.def->weapons.size();b++)
		{
			const WeaponDef* w = d.def->weapons[b].def;

			if (d.weaponRange < w->range)
				d.weaponRange = w->range;

			d.weaponDamage += CalcAverageDamage (&w->damages);
		}
	}
	delete[] templist;

    table.alloc(numDefs);

	logPrintf ("Calculating build table for %d build types...\n", numDefs);

	// convert all string'ed identifiers to id's, which can be used for indexing directly
	buildby = new std::vector<int>[numDefs]; 

	for (int a=0;a<numDefs;a++)
	{
		const UnitDef *def=deflist[a].def;
		
		for (map<int,string>::const_iterator i=def->buildOptions.begin();i!=def->buildOptions.end();++i)
		{
			const UnitDef *bdef = cb->GetUnitDef (i->second.c_str());
			if (bdef)
				buildby[bdef->id-1].push_back(a);
		}

		deflist[a].buildby = &buildby [a];
	}

	for (int a=0;a<numDefs;a++)
		CalcBuildTable (a, a, 0, ResInfo());

	SaveCache (cachefn);

/*	for (int a=0;a<numDefs;a++)
	{
		logPrintf ("%s builds:", deflist[a].name.c_str());

		for (int b=0;b<numDefs;b++)
		{
			BuildTable::Table::ent& e=table.get(a,b);
			if (e.id>=0)
				logPrintf ("%s by building %s (%d), ", deflist[b].name.c_str(), deflist[e.id].name.c_str(), e.depth);
		}

		logPrintf ("\n");
	}*/
}