예제 #1
0
void ETextureThumbnail::Save(int age, LPCSTR path)
{
	if (!Valid()) 	return;

    CMemoryWriter F;
	F.open_chunk	(THM_CHUNK_VERSION);
	F.w_u16			(THM_TEXTURE_VERSION);
	F.close_chunk	();

/*
	F.w_chunk		(THM_CHUNK_DATA | CFS_CompressMark,m_Pixels.begin(),m_Pixels.size()*sizeof(u32));
*/        

    F.open_chunk	(THM_CHUNK_TYPE);
    F.w_u32			(m_Type);
	F.close_chunk	();

	m_TexParams.Save(F);

    string_path		fn;
    if (path)
        FS.update_path(fn, path, m_Name.c_str());
    else
    	FS.update_path(fn, _game_textures_, m_Name.c_str());

    if (F.save_to(fn))
    {
	    FS.set_file_age	(fn,age?age:m_Age);
    }else{
        Log			("!Can't save thumbnail:",fn);
    }
}
예제 #2
0
bool CPSLibrary::Save(const char* nm)
{
    CMemoryWriter F;

    F.open_chunk	(PS_CHUNK_VERSION);
    F.w_u16		(PS_VERSION);
    F.close_chunk	();

    F.open_chunk	(PS_CHUNK_SECONDGEN);
    u32 chunk_id = 0;
    for (PS::PEDIt it=m_PEDs.begin(); it!=m_PEDs.end(); ++it,++chunk_id)
    {
        F.open_chunk	(chunk_id);
        (*it)->Save	(F);
        F.close_chunk	();
    }
    F.close_chunk	();

    
    F.open_chunk	(PS_CHUNK_THIRDGEN);
    chunk_id = 0;
    for (PS::PGDIt g_it=m_PGDs.begin(); g_it!=m_PGDs.end(); ++g_it,++chunk_id)
    {
        F.open_chunk	(chunk_id);
        (*g_it)->Save	(F);
        F.close_chunk	();
    }
    F.close_chunk	();

    return F.save_to(nm);
}
예제 #3
0
void CGameGraphBuilder::save_cross_table	(const float &start, const float &amount)
{
	Progress							(start);

	Msg									("Saving cross table");

//	CTimer								timer;
//	timer.Start							();

	CMemoryWriter						tMemoryStream;
	CGameLevelCrossTable::CHeader		tCrossTableHeader;
	
	tCrossTableHeader.dwVersion			= XRAI_CURRENT_VERSION;
	tCrossTableHeader.dwNodeCount		= level_graph().header().vertex_count();
	tCrossTableHeader.dwGraphPointCount = graph().header().vertex_count();
	tCrossTableHeader.m_level_guid		= level_graph().header().guid();
	tCrossTableHeader.m_game_guid		= m_graph_guid;
	
	tMemoryStream.open_chunk			(CROSS_TABLE_CHUNK_VERSION);
	tMemoryStream.w						(&tCrossTableHeader,sizeof(tCrossTableHeader));
	tMemoryStream.close_chunk			();
	
	tMemoryStream.open_chunk			(CROSS_TABLE_CHUNK_DATA);

	for (int i=0, n=level_graph().header().vertex_count(); i<n; i++) {
		CGameLevelCrossTable::CCell	tCrossTableCell;
		tCrossTableCell.tGraphIndex = (GameGraph::_GRAPH_ID)m_results[i];
		VERIFY						(graph().header().vertex_count() > tCrossTableCell.tGraphIndex);
		tCrossTableCell.fDistance	= float(m_distances[tCrossTableCell.tGraphIndex][i])*level_graph().header().cell_size();
		tMemoryStream.w				(&tCrossTableCell,sizeof(tCrossTableCell));
	}

	tMemoryStream.close_chunk();
	
//	Msg						("CT:SAVE : %f",timer.GetElapsed_sec());
//	Msg						("Flushing cross table");

#ifdef PRIQUEL
	tMemoryStream.save_to	(m_cross_table_name);
#else // PRIQUEL
	string_path				file_name;
	strconcat				(sizeof(file_name), file_name,*m_level_name,CROSS_TABLE_NAME_RAW);
	tMemoryStream.save_to	(file_name);
#endif // PRIQUEL
//	Msg						("CT:SAVE : %f",timer.GetElapsed_sec());

//	Msg						("Freiing cross table resources");

	m_marks.clear			();
	m_mark_stack.clear		();
	m_distances.clear		();
	m_current_fringe.clear	();
	m_next_fringe.clear		();

//	Msg						("CT:SAVE : %f",timer.GetElapsed_sec());
	Progress				(start + amount);
}
예제 #4
0
bool SceneBuilder::BuildSOMModel()
{
	BOOL bResult 	= TRUE;
	CMemoryWriter 	F;

    F.open_chunk	(0);
    F.w_u32			(0);
    F.close_chunk	();

    F.open_chunk	(1);
    ObjectList& lst = Scene->ListObj(OBJCLASS_SCENEOBJECT);
    for (ObjectIt it=lst.begin(); it!=lst.end(); it++){
    	CSceneObject* S 	= (CSceneObject*)(*it);
    	CEditableObject* E	= S->GetReference(); R_ASSERT(E);
    	if (E->m_Flags.is(CEditableObject::eoSoundOccluder)){ 
            Fvector 		v;
            const Fmatrix&	parent = S->_Transform();
            for (EditMeshIt m_it=E->FirstMesh(); m_it!=E->LastMesh(); m_it++){
                for (SurfFacesPairIt sf_it=(*m_it)->m_SurfFaces.begin(); sf_it!=(*m_it)->m_SurfFaces.end(); sf_it++){
                	CSurface* surf 		= sf_it->first;
                    int gm_id			= surf->_GameMtl(); 
                    if (gm_id==GAMEMTL_NONE_ID){ 
                        ELog.DlgMsg		(mtError,"Object '%s', surface '%s' contain invalid game material.",(*m_it)->Parent()->m_LibName.c_str(),surf->_Name());
                        bResult 		= FALSE; 
                        break; 
                    }
                    SGameMtl* mtl 		= GMLib.GetMaterialByID(gm_id);
                    if (0==mtl){
                        ELog.DlgMsg		(mtError,"Object '%s', surface '%s' contain undefined game material.",(*m_it)->Parent()->m_LibName.c_str(),surf->_Name());
                        bResult 		= FALSE; 
                        break; 
                    }
                    BOOL b2Sided 		= surf->m_Flags.is(CSurface::sf2Sided);
                    IntVec& i_lst		= sf_it->second;
                    for (IntIt i_it=i_lst.begin(); i_it!=i_lst.end(); i_it++){
                        st_Face& face 	= (*m_it)->m_Faces[*i_it];
                        for (int k=0; k<3; k++){
                            parent.transform_tiny(v,(*m_it)->m_Verts[face.pv[k].pindex]);
                            F.w_fvector3(v);
                        }
                        F.w_u32			(b2Sided);
                        F.w_float		(mtl->fSndOcclusionFactor);
                    }
                }
            }
        }
    }
    BOOL bValid = !!F.chunk_size()&&bResult;
    F.close_chunk();
    if (bValid){
	    xr_string som_name 	= MakeLevelPath("level.som");
	    bValid				= F.save_to(som_name.c_str());
    }
	return bValid;
}
예제 #5
0
void COMotion::SaveMotion(const char* buf){
	CMemoryWriter	F;
	F.open_chunk	(EOBJ_OMOTION);
	Save			(F);
	F.close_chunk	();
	if (!F.save_to(buf)) 
        Log			("!Can't save object motion:",buf);
}
예제 #6
0
void ELightAnimLibrary::Save()
{
	CMemoryWriter F;
    F.open_chunk	(CHUNK_VERSION);
    F.w_u16			(LANIM_VERSION);
	F.close_chunk	();
    F.open_chunk	(CHUNK_ITEM_LIST);
    int count = 0;
	for (LAItemIt it=Items.begin(); it!=Items.end(); it++){
        F.open_chunk(count++);
		(*it)->Save		(F);
        F.close_chunk();
    }
	F.close_chunk	();

	string_path		fn;
    FS.update_path	(fn,_game_data_,"lanims.xr");

    if (!F.save_to(fn))
        Log			("!Can't save color animations:",fn);
}
예제 #7
0
//----------------------------------------------------
// some types
bool SceneBuilder::BuildHOMModel()
{
	CMemoryWriter F;

    F.open_chunk(0);
    F.w_u32(0);
    F.close_chunk();

    F.open_chunk(1);
    ObjectList& lst = Scene->ListObj(OBJCLASS_SCENEOBJECT);
    for (ObjectIt it=lst.begin(); it!=lst.end(); it++){
    	CSceneObject* S 	= (CSceneObject*)(*it);
    	CEditableObject* E	= S->GetReference(); R_ASSERT(E);
    	if (E->m_Flags.is(CEditableObject::eoHOM)){ 
            Fvector 		v;
            const Fmatrix&	parent = S->_Transform();
            for (EditMeshIt m_it=E->FirstMesh(); m_it!=E->LastMesh(); m_it++){
                for (SurfFacesPairIt sf_it=(*m_it)->m_SurfFaces.begin(); sf_it!=(*m_it)->m_SurfFaces.end(); sf_it++){
                    BOOL b2Sided = sf_it->first->m_Flags.is(CSurface::sf2Sided);
                    IntVec& i_lst= sf_it->second;
                    for (IntIt i_it=i_lst.begin(); i_it!=i_lst.end(); i_it++){
                        st_Face& face = (*m_it)->m_Faces[*i_it];
                        for (int k=0; k<3; k++){
                            parent.transform_tiny(v,(*m_it)->m_Verts[face.pv[k].pindex]);
                            F.w_fvector3	(v);
                        }
                        F.w_u32(b2Sided);
                    }
                }
            }
        }
    }
    BOOL bValid = !!F.chunk_size();
    F.close_chunk();
    if (bValid){
	    xr_string hom_name 	= MakeLevelPath("level.hom");
	    bValid 				= F.save_to(hom_name.c_str());
    }
	return bValid;
}
예제 #8
0
파일: xrSaveOGF.cpp 프로젝트: 2asoft/xray
void CBuild::SaveTREE	(IWriter &fs)
{
	CMemoryWriter		MFS;

	Status				("Geometry buffers...");
	xr_vector<u32>		remap;
	remap.reserve		(g_tree.size());
	for (u32 rid=0; rid<g_tree.size(); rid++)	{
		OGF*	o		= dynamic_cast<OGF*>	(g_tree[rid]);
		if		(o)		remap.push_back(rid);
	}
	std::stable_sort	(remap.begin(),remap.end(),remap_order);
	clMsg				("remap-size: %d / %d",remap.size(),g_tree.size());
	for (u32 sid=0; sid<remap.size(); sid++)	{
		u32				id	= remap[sid];
		//clMsg			("%3d: subdiv: %d",sid,id);
		g_tree[id]->PreSave	(id);
	}

	Status				("Visuals...");
	fs.open_chunk		(fsL_VISUALS);
	for (xr_vector<OGF_Base*>::iterator it = g_tree.begin(); it!=g_tree.end(); it++)	{
		u32			idx = u32(it-g_tree.begin());
		MFS.open_chunk	(idx);
		(*it)->Save		(MFS);
		MFS.close_chunk	();
		Progress		(float(idx)/float(g_tree.size()));
	}
	fs.w				(MFS.pointer(),MFS.size());
	fs.close_chunk		();
	clMsg				("Average: %d verts/%d faces, 50(%2.1f), 100(%2.1f), 500(%2.1f), 1000(%2.1f), 5000(%2.1f)",
		g_batch_verts/g_batch_count,
		g_batch_faces/g_batch_count,
		100.f * float(g_batch_50)/float(g_batch_count),
		100.f * float(g_batch_100)/float(g_batch_count),
		100.f * float(g_batch_500)/float(g_batch_count),
		100.f * float(g_batch_1000)/float(g_batch_count),
		100.f * float(g_batch_5000)/float(g_batch_count)
		);
	mem_Compact			();

	SaveGEOMs			("level.geom",	g_VB,g_IB,g_SWI);	// Normal
	SaveGEOMs			("level.geomx",	x_VB,x_IB,x_SWI);	// Fast-Path

	Status				("Shader table...");
	fs.open_chunk		(fsL_SHADERS);
	fs.w_u32			(g_Shaders.size());
	for (xr_vector<LPCSTR>::iterator T=g_Shaders.begin(); T!=g_Shaders.end(); T++)
		fs.w_stringZ	(*T);
	fs.close_chunk		();
	//mem_Compact			();
}
예제 #9
0
void	CLevel::net_Save				(LPCSTR name)		// Game Save
{
	if (0==Server)		{
		Msg("KERNEL::Can't save game on pure client");
		return;
	}

	// 1. Create stream
	CMemoryWriter			fs;

	// 2. Description
	fs.open_chunk		(fsSLS_Description);
	fs.w_stringZ		(net_SessionName());
	fs.close_chunk		();

	// 3. Server state
	fs.open_chunk		(fsSLS_ServerState);
	Server->SLS_Save	(fs);
	fs.close_chunk		();

	// Save it to file
	fs.save_to			(name);
}
void CGameSpawnConstructor::save_spawn				(LPCSTR name, LPCSTR output)
{
	CMemoryWriter					stream;

	m_spawn_header.m_version		= XRAI_CURRENT_VERSION;
	m_spawn_header.m_guid			= generate_guid();
	m_spawn_header.m_graph_guid		= game_graph().header().guid();
	m_spawn_header.m_spawn_count	= spawn_graph().vertex_count();
	m_spawn_header.m_level_count	= (u32)m_level_spawns.size();
	
	stream.open_chunk				(0);
	stream.w_u32					(m_spawn_header.m_version);
	save_data						(m_spawn_header.m_guid,stream);
	save_data						(m_spawn_header.m_graph_guid,stream);
	stream.w_u32					(m_spawn_header.m_spawn_count);
	stream.w_u32					(m_spawn_header.m_level_count);
	stream.close_chunk				();
	
	stream.open_chunk				(1);
	save_data						(spawn_graph(),stream);
	stream.close_chunk				();

	stream.open_chunk				(2);
	save_data						(m_level_points,stream);
	stream.close_chunk				();

	stream.open_chunk				(3);
	save_data						(m_patrol_path_storage,stream);
	stream.close_chunk				();

	stream.open_chunk				(4);
	m_game_graph->save				(stream);
	stream.close_chunk				();

	stream.save_to					(*spawn_name(output));
}
예제 #11
0
void CBuild::SaveSectors(IWriter& fs)
{
	CMemoryWriter MFS;
	Status("Processing...");

	// validate & save
	for (u32 I=0; I<g_sectors.size(); I++)
	{
		MFS.open_chunk(I);
		g_sectors[I]->Validate();
		g_sectors[I]->Save(MFS);
		MFS.close_chunk();
		Progress(float(I)/float(g_sectors.size()));
	}

	fs.w_chunk(fsL_SECTORS,MFS.pointer(),MFS.size());
}
예제 #12
0
bool CGameMtlLibrary::Save()
{
	R_ASSERT			(FALSE==UpdateMtlPairs());
	// save
	CMemoryWriter fs;
    fs.open_chunk		(GAMEMTLS_CHUNK_VERSION);
    fs.w_u16			(GAMEMTL_CURRENT_VERSION);
	fs.close_chunk		();

    fs.open_chunk		(GAMEMTLS_CHUNK_AUTOINC);
    fs.w_u32			(material_index);
    fs.w_u32			(material_pair_index);
	fs.close_chunk		();
    
    fs.open_chunk		(GAMEMTLS_CHUNK_MTLS);
    int count = 0;
    for(GameMtlIt m_it=materials.begin(); m_it!=materials.end(); m_it++){
        fs.open_chunk	(count++);
        (*m_it)->Save	(fs);
        fs.close_chunk	();
    }
	fs.close_chunk		();
                                                    
    fs.open_chunk		(GAMEMTLS_CHUNK_MTLS_PAIR);
    count = 0;
    for(GameMtlPairIt p_it=material_pairs.begin(); p_it!=material_pairs.end(); p_it++){
        fs.open_chunk	(count++);
        (*p_it)->Save	(fs);
        fs.close_chunk	();
    }
	fs.close_chunk		();

	string_path fn;
    FS.update_path		(fn,_game_data_,GAMEMTL_FILENAME);
    return fs.save_to	(fn);
}
예제 #13
0
bool EDetailManager::Export(LPCSTR path) 
{
    AnsiString fn		= AnsiString(path)+"build.details";
    bool bRes=true;

    SPBItem* pb = UI->ProgressStart(5,"Making details...");
	CMemoryWriter F;

    pb->Inc				("merge textures");
    Fvector2Vec			offsets;
    Fvector2Vec			scales;
    boolVec				rotated;
    RStringSet 			textures_set;
    RStringVec 			textures;
    U32Vec				remap;
    U8Vec remap_object	(objects.size(),u8(-1));

    int slot_cnt		= dtH.size_x*dtH.size_z;
	for (int slot_idx=0; slot_idx<slot_cnt; slot_idx++){
    	DetailSlot* it 	= &dtSlots[slot_idx];
        for (int part=0; part<4; part++){
        	u8 id		= it->r_id(part);
        	if (id!=DetailSlot::ID_Empty) {
            	textures_set.insert(((EDetail*)(objects[id]))->GetTextureName());
                remap_object[id] = 1;
            }
        }
    }
    textures.assign		(textures_set.begin(),textures_set.end());

    U8It remap_object_it= remap_object.begin();

    u32 new_idx			= 0;
    for (DetailIt d_it=objects.begin(); d_it!=objects.end(); d_it++,remap_object_it++)
    	if ((*remap_object_it==1)&&(textures_set.find(((EDetail*)(*d_it))->GetTextureName())!=textures_set.end()))
	    	*remap_object_it	= (u8)new_idx++;

    AnsiString 			do_tex_name = ChangeFileExt(fn,"_details");
    int res				= ImageLib.CreateMergedTexture(textures,do_tex_name.c_str(),STextureParams::tfADXT1,256,1024,256,1024,offsets,scales,rotated,remap);
    if (1!=res)			bRes=FALSE;

    pb->Inc				("export geometry");
    // objects
    int object_idx		= 0;
    if (bRes){
	    do_tex_name 	= ExtractFileName(do_tex_name);
        F.open_chunk	(DETMGR_CHUNK_OBJECTS);
        for (DetailIt it=objects.begin(); it!=objects.end(); it++){
        	if (remap_object[it-objects.begin()]!=u8(-1)){
                F.open_chunk	(object_idx++);
                if (!((EDetail*)(*it))->m_pRefs){
                    ELog.DlgMsg(mtError, "Bad object or object not found '%s'.", ((EDetail*)(*it))->m_sRefs.c_str());
                    bRes=false;
                }else{
                    LPCSTR tex_name = ((EDetail*)(*it))->GetTextureName();
                    for (u32 t_idx=0; t_idx<textures.size(); t_idx++) 
                        if (textures[t_idx]==tex_name) break;
                    VERIFY(t_idx<textures.size());
                    t_idx = remap[t_idx];
                    ((EDetail*)(*it))->Export	(F,do_tex_name.c_str(),offsets[t_idx],scales[t_idx],rotated[t_idx]);
                }
                F.close_chunk	();
                if (!bRes) break;
            }
        }
        F.close_chunk		();
    }
    
    pb->Inc	("export slots");
    // slots
    if (bRes){
    	xr_vector<DetailSlot> dt_slots(slot_cnt); dt_slots.assign(dtSlots,dtSlots+slot_cnt);
        for (slot_idx=0; slot_idx<slot_cnt; slot_idx++){
            DetailSlot& it 	= dt_slots[slot_idx];
            // zero colors need lighting
	        it.c_dir		= 0;
	        it.c_hemi		= 0;
	        it.c_r			= 0;
	        it.c_g			= 0;
	        it.c_b			= 0;
            for (int part=0; part<4; part++){
                u8 id		= it.r_id(part);
                if (id!=DetailSlot::ID_Empty) it.w_id(part,remap_object[id]);
            }
        }
		F.open_chunk	(DETMGR_CHUNK_SLOTS);
		F.w				(dt_slots.begin(),dtH.size_x*dtH.size_z*sizeof(DetailSlot));
	    F.close_chunk	();
        pb->Inc();

        // write header
        dtH.version		= DETAIL_VERSION;
        dtH.object_count= object_idx;

        F.w_chunk		(DETMGR_CHUNK_HEADER,&dtH,sizeof(DetailHeader));

    	bRes 			= F.save_to(fn.c_str());
    }

    pb->Inc();
    UI->ProgressEnd(pb);
    return bRes;
}
예제 #14
0
CCrossTableBuilder::CCrossTableBuilder(LPCSTR caProjectName)
{
	FILE_NAME			caFileName;
	strconcat			(sizeof(caFileName),caFileName,caProjectName,GAME_LEVEL_GRAPH);
	
	Phase				("Loading level graph");
	CGameGraph			tGraph(caFileName);
	
	Phase				("Loading AI map");
	CLevelGraph			tMap(caProjectName);
	
	Phase				("Building dynamic objects");
	FLOAT_VECTOR_VECTOR	tDistances;
	int					iVertexCount	= tGraph.header().vertex_count();
	R_ASSERT2			(iVertexCount > 0,"There are no graph points in the graph!");
	int					iNodeCount		= tMap.header().vertex_count();
	xr_vector<bool>		tMarks;
	tMarks.assign		(tMap.header().vertex_count(),false);
	{
		for (int i=0; i<iVertexCount; i++)
			vfRecurseMark(tMap,tMarks,tGraph.vertex(i)->level_vertex_id());
		tMarks.flip		();
	}

	tDistances.resize	(iVertexCount);
	{
		FLOAT_VECTOR_IT		I = tDistances.begin();
		FLOAT_VECTOR_IT		E = tDistances.end();
		for ( ; I != E; I++) {
			(*I).resize		(iNodeCount);
			FLOAT_IT		i = (*I).begin();
			FLOAT_IT		e = (*I).end();
			for ( ; i != e; i++)
				*i			= u32(-1);
		}
	}
	
	Phase				("Building cross table");
	Progress(0.f);
	for (int i=0; i<iVertexCount; ++i) {
		if (i)
			for (int k=0; k<(int)tMap.header().vertex_count(); k++)
				tDistances[i][k] = tDistances[i - 1][k];
		g_tDistances	= &tDistances[i];
		g_tMap			= &tMap;
		g_tMarks		= &tMarks;
		vfRecurseUpdate(tGraph.vertex(i)->level_vertex_id(),i,iVertexCount);
		Progress(float(i + 1)/float(iVertexCount));
	}
	Progress			(1.f);
	
	Phase				("Saving cross table");
	CMemoryWriter					tMemoryStream;
	CGameLevelCrossTable::CHeader	tCrossTableHeader;
	
	tCrossTableHeader.dwVersion			= XRAI_CURRENT_VERSION;
	tCrossTableHeader.dwNodeCount		= iNodeCount;
	tCrossTableHeader.dwGraphPointCount = iVertexCount;
	tCrossTableHeader.m_level_guid		= tMap.header().guid();
	tCrossTableHeader.m_game_guid		= tGraph.header().guid();
	
	tMemoryStream.open_chunk			(CROSS_TABLE_CHUNK_VERSION);
	tMemoryStream.w						(&tCrossTableHeader,sizeof(tCrossTableHeader));
	tMemoryStream.close_chunk			();
	
	tMemoryStream.open_chunk			(CROSS_TABLE_CHUNK_DATA);
	{
		for (int i=0; i<iNodeCount; i++) {
			FLOAT_VECTOR_IT		I = tDistances.begin(), B = I;
			FLOAT_VECTOR_IT		E = tDistances.end();
			CGameLevelCrossTable::CCell tCrossTableCell;
			tCrossTableCell.fDistance = flt_max;
			tCrossTableCell.tGraphIndex = u16(-1);
			for ( ; I != E; I++)
				if (float((*I)[i])*tMap.header().cell_size() < tCrossTableCell.fDistance) {
					tCrossTableCell.fDistance	= float((*I)[i])*tMap.header().cell_size();
					tCrossTableCell.tGraphIndex = GameGraph::_GRAPH_ID(I - B);
				}
			
			for (int j=0; j<iVertexCount; j++)
				if ((tGraph.vertex(j)->level_vertex_id() == (u32)i) && (tCrossTableCell.tGraphIndex != j)) {
					Msg("! Warning : graph points are too close, therefore cross table is automatically validated");
					Msg("%d : [%f][%f][%f] %d[%f] -> %d[%f]",i,VPUSH(tGraph.vertex(j)->level_point()),tCrossTableCell.tGraphIndex,tCrossTableCell.fDistance,j,tDistances[j][i]);
					tCrossTableCell.fDistance	= float(tDistances[j][i])*tMap.header().cell_size();
					tCrossTableCell.tGraphIndex = (GameGraph::_GRAPH_ID)j;
				}
			tMemoryStream.w(&tCrossTableCell,sizeof(tCrossTableCell));
		}
	}
	tMemoryStream.close_chunk();
	
	strconcat			(sizeof(caFileName),caFileName,caProjectName,CROSS_TABLE_NAME_RAW);
	tMemoryStream.save_to(caFileName);
}