Esempio n. 1
0
void GenAudioID::Trigger(const std::string& src_dir, const std::string& dst_file)
{
	Json::Value val;

	// audio
	{
		wxArrayString files;
		ee::FileHelper::FetchAllFiles(src_dir + "\\audio", files);

		int idx = val.size();

		for (auto& file : files)
		{
			if (file.find("manga_") == std::string::npos) {
				continue;
			}
			Json::Value item;
			item["id"] = idx;
			item["name"] = "audio/" + GetFormatName(file.ToStdString());
			val[idx++] = item;
		}
		for (auto& file : files)
		{
			if (file.find("manga_") != std::string::npos) {
				continue;
			}
			Json::Value item;
			item["id"] = idx;
			item["name"] = "audio/" + GetFormatName(file.ToStdString());
			val[idx++] = item;
		}
	}

	// sound
	{
		wxArrayString files;
		ee::FileHelper::FetchAllFiles(src_dir + "\\sound", files);

		int idx = val.size();
		for (auto& file : files)
		{
			Json::Value item;
			item["id"] = idx;
			item["name"] = "sound/" + GetFormatName(file.ToStdString());
			val[idx++] = item;
		}
	}

	// music
	{
		wxArrayString files;
		ee::FileHelper::FetchAllFiles(src_dir + "\\music", files);

		int idx = val.size();
		for (auto& file : files)
		{
			Json::Value item;
			item["id"] = idx;
			item["name"] = "music/" + GetFormatName(file.ToStdString());
			val[idx++] = item;
		}
	}

	Json::StyledStreamWriter writer;
	std::locale::global(std::locale(""));
	std::ofstream fout(dst_file.c_str());
	std::locale::global(std::locale("C"));
	writer.write(fout, val);
	fout.close();
}
Esempio n. 2
0
std::ostream& operator<<( std::ostream &sout, const Value &root )
{
   Json::StyledStreamWriter writer;
   writer.write(sout, root);
   return sout;
}
Esempio n. 3
0
//----------------------------------------------------------------------------------------
//名称: ImportFavoriteData
//描述: 将当前的记录导入到浏览器中
//参数: 
//		@param	ppData			需要导入的的收藏夹数据数组
//		@param	nDataNum		需要导入的收藏夹条目的条数
//----------------------------------------------------------------------------------------
int C360ChromePlugIn::ImportFavoriteData(PFAVORITELINEDATA* ppData, int32& nDataNum)
{
	if (ppData == NULL || nDataNum == 0)
	{
		return ERROR_INVALID_PARAM;
	}

	m_mapPidInfo.clear();
	m_mapDepthInfo.clear();
	m_mapPidNodeInfo.clear();
	m_mapIdIndexInfo.clear();

	PFAVORITELINEDATA* ppInnerData = new PFAVORITELINEDATA[nDataNum];
	memcpy(ppInnerData, ppData, sizeof(PFAVORITELINEDATA)*nDataNum);

	wchar_t* pszPath = GetFavoriteDataPath();

	//获取导入文件路径
	std::wstring strTmpPath = StringHelper::ANSIToUnicode(StringHelper::UnicodeToUtf8(pszPath));
	if( FileHelper::IsFileExist(strTmpPath.c_str()) == TRUE)
	{
		BOOL bResult = ::DeleteFileW(pszPath);
		if( bResult == FALSE)
		{
			//导入前先删除之前的收藏夹文件
			bResult = FileHelper::DeleteFile(pszPath);
			free(pszPath);
			if (!bResult)
			{
				delete ppInnerData;
				return ERROR_CLEAR_FAVORITE_DATA;
			}
		}
	}

	Json::Value root;
	Json::Value bookmark_bar;
	Json::Value other;
	Json::Value synced;
	uint32 nIndex = 0;
	int32 nDepth = 0;

	InitializeChecksum();

	MakeSpecialFolderNode(L"Bookmarks bar", m_nIndex, bookmark_bar);
	SortByDepth(&ppInnerData[0], nDataNum);
	for (int32 i = 0; i < nDataNum; ++i)
	{
		if (ppInnerData[i] == NULL || ppInnerData[i]->bDelete == true)
		{
			continue;
		}

		MAP_PID_INFO::iterator it;
		it = m_mapPidInfo.find(ppInnerData[i]->nPid);
		if (it != m_mapPidInfo.end())
		{
			nDepth = (*it).second + 1;
		}
		else
		{
			nDepth = 0;
		}

		if (nDepth > m_nMaxDepth)
		{
			m_nMaxDepth = nDepth;
		}

		if (ppInnerData[i]->bFolder)
		{
			m_mapPidInfo.insert(MAP_PID_INFO::value_type(ppInnerData[i]->nId, nDepth));
		}
		
		m_mapDepthInfo.insert(MAP_DEPTH_INFO::value_type(nDepth, i));
	}

	TraverseNode(ppInnerData, m_nMaxDepth);
	if (m_mapPidNodeInfo.size() == 1)
	{
		bookmark_bar["children"] = m_mapPidNodeInfo.begin()->second;
	}
	else
	{
		delete ppInnerData;
		return ERROR_INTERNAL_ERROR;
	}

	MAP_ID_INDEX_INFO::iterator itIdIndex;

	int nRealNum  = 0;
	for (int k = 0; k < nDataNum; k++)
	{
		if( ppInnerData[k] == NULL || ppInnerData[k]->bDelete == true)
			continue;

		nRealNum ++;

		itIdIndex = m_mapIdIndexInfo.find(ppInnerData[k]->nId);
		if (itIdIndex != m_mapIdIndexInfo.end())
		{
			int32 nIndex = (*itIdIndex).second; 
			if (ppInnerData[k]->bFolder)
			{
				m_mapPidInfo.insert(MAP_PID_INFO::value_type(ppInnerData[k]->nId, nDepth));
				char szId[256] = {0};
				sprintf_s(szId, 255, "%u", nIndex);
				UpdateChecksumWithFolderNode(&szId[0], ppInnerData[k]->szTitle);
			}
			else
			{
				char szId[256] = {0};
				sprintf_s(szId, 255, "%u", nIndex);
				UpdateChecksumWithUrlNode(&szId[0], ppInnerData[k]->szTitle, StringHelper::UnicodeToUtf8(ppInnerData[k]->szUrl));
			}
		}
	}

	MakeSpecialFolderNode(L"Other bookmarks", m_nIndex, other);
	MakeSpecialFolderNode(L"Synced bookmarks", m_nIndex, synced);
	
	FinalizeChecksum();

	root["checksum"] = m_strCheckSum;
	root["roots"]["bookmark_bar"] = bookmark_bar;
	root["roots"]["other"] = other;
	root["roots"]["synced"] = synced;
	root["version"] = 1;

	std::ofstream outfile(strTmpPath.c_str());
	Json::StyledStreamWriter writer;
	writer.write(outfile, root);	
	outfile.close();

	delete[] ppInnerData;

	nDataNum = nRealNum;

	return ERROR_OK;
}
Esempio n. 4
0
int main(int argc, char** argv)
{
	float scale = 0.1f;
	float scaleTexV = -1.f;

	std::vector<Object> objects;
	std::ifstream inputFile(argv[1]);
	if (!inputFile.is_open())
	{
		printf("Failed to open %s", argv[1]);
		return -1;
	}

	if (argc != 3)
	{
		printf("Missing scene name");
		return -1;
	}
	std::string sceneName = argv[2];

	char line[1024];
	std::vector<Vec3> positions;
	std::vector<Vec3> normals;
	std::vector<Vec2> texcoords;

	Object* pActiveObj = nullptr;
	SubObject* pActiveSubObject = nullptr;

	int lineNum = 0;
	while (inputFile.getline(line, 1024))
	{
		++lineNum;

		char* context = nullptr;
		char* tok = strtok_s(line, " ", &context);
		if (!tok)
			continue;

		if (strcmp(tok, "v") == 0)
		{
			// Position
			Vec3 pos;
			pos.x = scale * (float)atof(strtok_s(nullptr, " ", &context));
			pos.y = scale * (float)atof(strtok_s(nullptr, " ", &context));
			pos.z = scale * (float)atof(strtok_s(nullptr, " ", &context));
			positions.push_back(pos);
		}
		else if (strcmp(tok, "vn") == 0)
		{
			// Normal
			Vec3 norm;
			norm.x = (float)atof(strtok_s(nullptr, " ", &context));
			norm.y = (float)atof(strtok_s(nullptr, " ", &context));
			norm.z = (float)atof(strtok_s(nullptr, " ", &context));
			normals.push_back(norm);
		}
		else if (strcmp(tok, "vt") == 0)
		{
			// Tex coord
			Vec2 uv;
			uv.x = (float)atof(strtok_s(nullptr, " ", &context));
			uv.y = (float)atof(strtok_s(nullptr, " ", &context)) * scaleTexV;
			texcoords.push_back(uv);
		}
		else if (strcmp(tok, "f") == 0)
		{
			// Face
			Vertex faceVerts[4];
			int numVerts = 0;

			while (context[0] != 0)
			{
				Vertex& rVert = faceVerts[numVerts];
				rVert.pos = atoi(strtok_s(nullptr, "/ ", &context)) - 1;
				rVert.uv = atoi(strtok_s(nullptr, "/ ", &context)) - 1;
				rVert.norm = atoi(strtok_s(nullptr, "/ ", &context)) - 1;

				++numVerts;
			}

			if (numVerts == 3)
			{
				pActiveSubObject->verts.push_back(faceVerts[0]);
				pActiveSubObject->verts.push_back(faceVerts[1]);
				pActiveSubObject->verts.push_back(faceVerts[2]);
			}
			else if (numVerts == 4)
			{
				pActiveSubObject->verts.push_back(faceVerts[0]);
				pActiveSubObject->verts.push_back(faceVerts[1]);
				pActiveSubObject->verts.push_back(faceVerts[2]);
				pActiveSubObject->verts.push_back(faceVerts[0]);
				pActiveSubObject->verts.push_back(faceVerts[2]);
				pActiveSubObject->verts.push_back(faceVerts[3]);
			}
			else
			{
				assert(false);
			}
		}
		else if (strcmp(tok, "g") == 0)
		{
			objects.emplace_back();
			pActiveObj = &objects.back();

			pActiveObj->name = strtok_s(nullptr, " ", &context);
		}
		else if (strcmp(tok, "usemtl") == 0)
		{
			pActiveObj->subobjects.emplace_back();
			pActiveSubObject = &pActiveObj->subobjects.back();

			pActiveSubObject->material = strtok_s(nullptr, " ", &context);
		}
	}

	Json::StyledStreamWriter jsonWriter;

	Json::Value jSceneRoot(Json::objectValue);

	// Camera
	{
		Json::Value jCamera(Json::objectValue);

		Json::Value jPos(Json::arrayValue);
		jPos[0] = 0.f;
		jPos[1] = 5.f;
		jPos[2] = 0.f;
		jCamera["position"] = jPos;

		Json::Value jRot(Json::arrayValue);
		jRot[0] = 0.f;
		jRot[1] = 0.f;
		jRot[2] = 0.f;
		jCamera["rotation"] = jRot;

		jSceneRoot["camera"] = jCamera;
	}

	jSceneRoot["sky"] = "cloudy";
	jSceneRoot["lights"] = Json::Value(Json::arrayValue);
	Json::Value& jSceneObjects = jSceneRoot["objects"] = Json::Value(Json::arrayValue);

	int numObjects = (int)objects.size();
	for (int i = 0; i < numObjects; ++i)
	{
		const Object& obj = objects[i];

		Vec3 minExtents = { FLT_MAX, FLT_MAX, FLT_MAX };
		Vec3 maxExtents = { -FLT_MAX, -FLT_MAX, -FLT_MAX };
		char str[256];

		for (unsigned int n = 0; n < obj.subobjects.size(); ++n)
		{
			const SubObject& subobj = obj.subobjects[n];
			for (unsigned int k = 0; k < subobj.verts.size(); ++k)
			{
				const Vertex& vert = subobj.verts[k];
				const Vec3& pos = positions[vert.pos];
				minExtents.x = min(minExtents.x, pos.x);
				minExtents.y = min(minExtents.y, pos.y);
				minExtents.z = min(minExtents.z, pos.z);
				maxExtents.x = max(maxExtents.x, pos.x);
				maxExtents.y = max(maxExtents.y, pos.y);
				maxExtents.z = max(maxExtents.z, pos.z);
			}
		}

		Vec3 center = { (maxExtents.x + minExtents.x) * 0.5f, minExtents.y, (maxExtents.z + minExtents.z) * 0.5f };

		std::string objFilename = "output/" + obj.name + ".obj";
		createDirectoryTreeForFile(objFilename);

		std::ofstream objFile(objFilename);
		assert(objFile.is_open());

		int posCount = 0;
		int uvCount = 0;
		int normCount = 0;

		for (unsigned int n = 0; n < obj.subobjects.size(); ++n)
		{
			const SubObject& subobj = obj.subobjects[n];

			// Build the obj file
			int posStart = INT_MAX;
			int posEnd = 0;
			int uvStart = INT_MAX;
			int uvEnd = 0;
			int normStart = INT_MAX;
			int normEnd = 0;

			for (unsigned int k = 0; k < subobj.verts.size(); ++k)
			{
				const Vertex& vert = subobj.verts[k];

				posStart = min(posStart, vert.pos);
				posEnd = max(posEnd, vert.pos);
				uvStart = min(uvStart, vert.uv);
				uvEnd = max(uvEnd, vert.uv);
				normStart = min(normStart, vert.norm);
				normEnd = max(normEnd, vert.norm);
			}

			// write positions
			for (int k = posStart; k <= posEnd; ++k)
			{
				const Vec3& pos = positions[k];
				sprintf_s(str, "v %f %f %f\n", (pos.x - center.x), (pos.y - center.y), (pos.z - center.z));
				objFile.write(str, strlen(str));
			}

			// write uvs
			for (int k = uvStart; k <= uvEnd; ++k)
			{
				const Vec2& uv = texcoords[k];
				sprintf_s(str, "vt %f %f\n", uv.x, uv.y);
				objFile.write(str, strlen(str));
			}

			// write normals
			for (int k = normStart; k <= normEnd; ++k)
			{
				const Vec3& normal = normals[k];
				sprintf_s(str, "vn %f %f %f\n", normal.x, normal.y, normal.z);
				objFile.write(str, strlen(str));
			}

			// write material to use for this subobject
			std::string materialName = sceneName + "/" + subobj.material;
			sprintf_s(str, "usemtl %s\n", materialName.c_str());
			objFile.write(str, strlen(str));

			// write faces
			for (unsigned int k = 0; k < subobj.verts.size(); k += 3)
			{
				const Vertex& vert1 = subobj.verts[k + 0];
				const Vertex& vert2 = subobj.verts[k + 1];
				const Vertex& vert3 = subobj.verts[k + 2];
				sprintf_s(str, "f %d/%d/%d %d/%d/%d %d/%d/%d\n",
					posCount + (vert1.pos - posStart + 1), uvCount + (vert1.uv - uvStart + 1), normCount + (vert1.norm - normStart + 1),
					posCount + (vert2.pos - posStart + 1), uvCount + (vert2.uv - uvStart + 1), normCount + (vert2.norm - normStart + 1),
					posCount + (vert3.pos - posStart + 1), uvCount + (vert3.uv - uvStart + 1), normCount + (vert3.norm - normStart + 1));
				objFile.write(str, strlen(str));
			}

			posCount += (posEnd - posStart) + 1;
			uvCount += (uvEnd - uvStart) + 1;
			normCount += (normEnd - normStart) + 1;
		}

		objFile.close();

		// Add instance to scene
		Json::Value& jObj = jSceneObjects.append(Json::objectValue);
		jObj["model"] = sceneName + "/" + obj.name;

		Json::Value& jPos = jObj["position"] = Json::arrayValue;
		jPos[0] = center.x; jPos[1] = center.y; jPos[2] = center.z;

		Json::Value& jRot = jObj["rotation"] = Json::arrayValue;
		jRot[0] = 0.f; jRot[1] = 0.f; jRot[2] = 0.f;

		Json::Value& jScale = jObj["scale"] = Json::arrayValue;
		jScale[0] = 1.f; jScale[1] = 1.f; jScale[2] = 1.f;
	}

	std::ofstream sceneFile("output/" + sceneName + ".scene");
	jsonWriter.write(sceneFile, jSceneRoot);
}
Esempio n. 5
0
int main(int argc, char *argv[])
{
	if (argc < 2) {
		std::cerr << "Need Resource Dir !" << std::endl;
		return 1;
	}

// 	if (argc < 3) {
// 		std::cerr << "Need Resource Dir & Extrude size !" << std::endl;
// 		return 1;
// 	}

	std::string dirpath = argv[1];
	wxArrayString files;
	DirTraverser traverser(files);

	wxDir dir(dirpath);
	dir.Traverse(traverser);

	std::map<std::string, ee::Rect> map_name2rect;

	double size = 1;
//	wxString(argv[2]).ToDouble(&size);
	try {
		for (size_t i = 0, n = files.size(); i < n; ++i)
		{
			wxFileName filename(files[i]);
			filename.Normalize();
			wxString filepath = filename.GetFullPath();
			
			if (ee::FileNameParser::isType(filepath, ee::FileNameParser::e_image))
			{
				coceditor::ExtrudeImg extrude(filepath.ToStdString());
				extrude.Trigger((int)size);
				map_name2rect.insert(std::make_pair(extrude.GetFileName(), extrude.GetRectTrimed()));
			}
		}

		for (size_t i = 0, n= files.size(); i < n; ++i)
		{
			wxFileName filename(files[i]);
			filename.Normalize();
			wxString filepath = filename.GetFullPath();

			if (ee::FileNameParser::isType(filepath, ee::FileNameParser::e_complex))
			{
				Json::Value value;
				Json::Reader reader;
				std::locale::global(std::locale(""));
				std::ifstream fin(filepath.fn_str());
				std::locale::global(std::locale("C"));
				reader.parse(fin, value);
				fin.close();

				bool dirty = false;

				int i = 0;
				Json::Value spriteValue = value["sprite"][i++];
				while (!spriteValue.isNull()) {

					std::string path = spriteValue["filepath"].asString();
					path = ee::FilenameTools::getFilenameWithExtension(path);
					std::map<std::string, ee::Rect>::iterator itr = map_name2rect.find(path);
					if (itr != map_name2rect.end()) {
						dirty = true;

						const float x = spriteValue["position"]["x"].asDouble(),
							y = spriteValue["position"]["y"].asDouble();
						value["sprite"][i-1]["position"]["x"] = x + itr->second.xCenter() * spriteValue["x scale"].asDouble();
						value["sprite"][i-1]["position"]["y"] = y + itr->second.yCenter() * spriteValue["y scale"].asDouble();
					}
					spriteValue = value["sprite"][i++];
				}

				if (dirty)
				{
					Json::StyledStreamWriter writer;
					std::locale::global(std::locale(""));
					std::ofstream fout(filepath.fn_str());
					std::locale::global(std::locale("C"));					
					writer.write(fout, value);
					fout.close();
				}
			}
		}
	} catch (ee::Exception& e) {
		std::cerr << e.what() << std::endl;
	}

	return 0;
}
Esempio n. 6
0
void GenNoCompressCfg::Trigger(const std::string& src_dir, const std::string& src_cfg, 
							   const std::string& dst_dir)
{
	wxArrayString files;
	ee::FileHelper::FetchAllFiles(src_dir, files);
	
	std::set<std::string> paths;

	// read from old cfg
	Json::Value src_value;
	Json::Reader reader;
	std::locale::global(std::locale(""));
	std::ifstream fin(src_cfg.c_str());
	std::locale::global(std::locale("C"));
	reader.parse(fin, src_value);
	fin.close();
	if (src_value.isMember("no_compress")) {
		for (int i = 0, n = src_value["no_compress"].size(); i < n; ++i) {
			std::string path = src_value["no_compress"][i].asString();
			auto full_path = gum::FilepathHelper::Absolute(src_dir.c_str(), path.c_str());
			paths.insert(gum::FilepathHelper::Format(full_path.c_str()).c_str());
		}
	}

	// add scale9
	for (int i = 0, n = files.size(); i < n; ++i)
	{
		wxFileName filename(files[i]);
		filename.Normalize();
		std::string filepath = filename.GetFullPath();
		int type = ee::SymbolFile::Instance()->Type(filepath);
		if (type != s2::SYM_SCALE9) {
			continue;
		}

		Json::Value value;
		Json::Reader reader;
		std::locale::global(std::locale(""));
		std::ifstream fin(filepath.c_str());
		std::locale::global(std::locale("C"));
		reader.parse(fin, value);
		fin.close();

		int zero = 0;

		std::string dir = ee::FileHelper::GetFileDir(filepath);
		int s9_type = value["type"].asInt();
		switch (s9_type)
		{
		case s2::S9_NULL:
			break;
		case s2::S9_9GRID:
			AddPath(paths, dst_dir, value["sprite"][1], dir);
			AddPath(paths, dst_dir, value["sprite"][3], dir);
			AddPath(paths, dst_dir, value["sprite"][4], dir);
			AddPath(paths, dst_dir, value["sprite"][5], dir);
			AddPath(paths, dst_dir, value["sprite"][7], dir);
			break;
		case s2::S9_3GRID_HORI:
			AddPath(paths, dst_dir, value["sprite"][1], dir);
			break;
		case s2::S9_3GRID_VERT:
			AddPath(paths, dst_dir, value["sprite"][1], dir);
			break;
		case s2::S9_6GRID_UPPER:
			AddPath(paths, dst_dir, value["sprite"][zero], dir);
			AddPath(paths, dst_dir, value["sprite"][1], dir);
			AddPath(paths, dst_dir, value["sprite"][2], dir);
			AddPath(paths, dst_dir, value["sprite"][4], dir);
			break;
		case s2::S9_9GRID_HOLLOW:
			AddPath(paths, dst_dir, value["sprite"][1], dir);
			AddPath(paths, dst_dir, value["sprite"][3], dir);
			AddPath(paths, dst_dir, value["sprite"][4], dir);
			AddPath(paths, dst_dir, value["sprite"][6], dir);
			break;
		}

		Json::StyledStreamWriter writer;
		std::locale::global(std::locale(""));
		std::ofstream fout(filepath.c_str());
		std::locale::global(std::locale("C"));	
		writer.write(fout, value);
		fout.close();
	}

	// output
	std::ofstream f_compress((dst_dir + "\\compress.tmp").c_str());
	std::ofstream f_no_compress((dst_dir + "\\no_compress.tmp").c_str());
	for (int i = 0, n = files.size(); i < n; ++i)
	{
		wxFileName filename(files[i]);
		filename.Normalize();
		std::string filepath = filename.GetFullPath();
		int type = ee::SymbolFile::Instance()->Type(filepath);
		if (type != s2::SYM_IMAGE) {
			continue;
		}

		filepath = gum::FilepathHelper::Format(filepath.c_str()).c_str();
		if (paths.find(filepath) != paths.end()) {
			f_no_compress << filepath << "\n";
		} else {
			f_compress << filepath << "\n";
		}
	}
	f_compress.close();
	f_no_compress.close();
}
Esempio n. 7
0
void ExportBodymovin::FixFontLayer(const std::string& filepath, const std::string& dir)
{
	Json::Value val;
	Json::Reader reader;
	std::locale::global(std::locale(""));
	std::ifstream fin(filepath.c_str());
	std::locale::global(std::locale("C"));
	reader.parse(fin, val);
	fin.close();

	Json::Value dst_val;
	dst_val["fps"] = val["fps"];
	dst_val["name"] = val["name"];

	int IDX0 = 0;

	auto layer_name = gum::FilepathHelper::Filename(filepath.c_str());
	layer_name = layer_name.substr(0, layer_name.size() - 10);

	bool dirty = false;
	for (int i = 0, n = val["layer"].size(); i < n; ++i)
	{
		const Json::Value& layer_val = val["layer"][i];
		assert(layer_val.size() > 0 && layer_val["frame"].size() > 0);
		const Json::Value& frame_val = layer_val["frame"][IDX0];
		assert(frame_val.size() > 0 && frame_val["actor"].size() > 0);
		const Json::Value& actor_val = frame_val["actor"][IDX0];
		std::string filename = actor_val["filepath"].asString();
		filename = gum::FilepathHelper::Filename(filename.c_str()).c_str();

		int sz = dst_val["layer"].size();
		dst_val["layer"][sz] = val["layer"][i];
		if (filename.size() != 6 ||
			filename[0] != '0' ||
			filename.substr(2) != ".png") 
		{
			continue;
		}

		auto t_sym = ee::SymbolFactory::Create(s2::SYM_TEXTBOX);
		s2::Textbox tb;
		tb.width = 200;
		tb.height = 200;
		tb.font_type = 0;
		tb.font_size = 40;
		tb.font_color = pt2::Color(0, 0, 0);
		tb.has_edge = false;
		tb.align_hori = s2::Textbox::HA_LEFT;
		tb.align_vert = s2::Textbox::VA_CENTER;
		std::dynamic_pointer_cast<etext::Symbol>(t_sym)->SetTextbox(tb);
		auto t_spr = ee::SpriteFactory::Instance()->Create(t_sym);
		t_spr->UpdateBounding();

		auto text_spr = std::dynamic_pointer_cast<etext::Sprite>(t_spr);
		text_spr->SetExport(true);

		auto c_sym = ee::SymbolFactory::Create(s2::SYM_COMPLEX);
		std::dynamic_pointer_cast<ecomplex::Symbol>(c_sym)->Add(t_spr);
		CU_STR text_path = layer_name + "_" + gum::StringHelper::ToString(i) + "_text_complex.json";
		c_sym->SetFilepath(dir + "\\" + std::string(text_path.c_str()));
		auto c_spr = ee::SpriteFactory::Instance()->Create(c_sym);
		c_spr->UpdateBounding();

		ecomplex::FileStorer::Store(c_sym->GetFilepath(), *std::dynamic_pointer_cast<ecomplex::Symbol>(c_sym), dir, false);

		Json::Value new_layer = layer_val;
		for (int j = 0, m = new_layer["frame"].size(); j < m; ++j)
		{
			Json::Value& frame_val = new_layer["frame"][j];
			assert(frame_val["actor"].size() == 1);
			const Json::Value& src_val = frame_val["actor"][IDX0];

			ee::SpriteIO spr_io;
			spr_io.Load(src_val, dir.c_str());

			sm::vec2 anchor = spr_io.m_position + spr_io.m_offset;

			spr_io.m_position = spr_io.m_position + sm::rotate_vector(-spr_io.m_offset, spr_io.m_angle) + spr_io.m_offset;
			spr_io.m_angle = 0;
			float scale = std::min(fabs(spr_io.m_scale.x), fabs(spr_io.m_scale.y));
			spr_io.m_scale.x = scale;
			spr_io.m_scale.y = scale;
			spr_io.m_offset = anchor - spr_io.m_position;

			Json::Value dst_val;
			dst_val["filepath"] = text_path.c_str();
			spr_io.Store(dst_val, dir.c_str());

			frame_val["actor"][IDX0] = dst_val;
		}

		dst_val["layer"][sz + 1] = new_layer;

		dirty = true;
	}

	if (dirty) 
	{
		Json::StyledStreamWriter writer;
		std::locale::global(std::locale(""));
		std::ofstream fout(filepath.c_str());
		std::locale::global(std::locale("C"));
		writer.write(fout, dst_val);
		fout.close();
	}
}