diff --git a/.gitignore b/.gitignore index 716270ff..ef70de07 100644 --- a/.gitignore +++ b/.gitignore @@ -101,3 +101,6 @@ Build/Converter/cppfs/ Build/Ss6ConverterGUI/build-Ss6ConverterGUI-Desktop_Qt_5_15_2_clang_64bit-Debug/ Build/Ss6ConverterGUI/build-Ss6ConverterGUI-Desktop_Qt_5_15_2_clang_64bit-Debug/ Build/Ss6ConverterGUI/build-Ss6ConverterGUI-Desktop_Qt_5_15_2_clang_64bit-Release/ +Build/Converter/flatbuffers/_build/ +Build/Converter/flatbuffers/tests/FlatBuffers.Test/ +Build/vcpkg/ diff --git a/Build/Converter/BackGroudRender.cpp b/Build/Converter/BackGroudRender.cpp index 72c5ce12..23e1eedf 100644 --- a/Build/Converter/BackGroudRender.cpp +++ b/Build/Converter/BackGroudRender.cpp @@ -19,7 +19,7 @@ -static spritestudio6::SSTextureFactory* texfactory = nullptr; +static SpriteStudio::SSTextureFactory* texfactory = nullptr; GLuint FramebufferName = 0; @@ -87,8 +87,8 @@ bool ConverterOpenGLInit() isGPUInit = true; - spritestudio6::SsCurrentRenderer::SetCurrentRender(new spritestudio6::SsRenderGL()); - texfactory = new spritestudio6::SSTextureFactory(new spritestudio6::SSTextureGL()); + SpriteStudio::SsCurrentRenderer::SetCurrentRender(new SpriteStudio::SsRenderGL()); + texfactory = new SpriteStudio::SSTextureFactory(new SpriteStudio::SSTextureGL()); glGenFramebuffers(1, &FramebufferName); glBindFramebuffer(GL_FRAMEBUFFER, FramebufferName); diff --git a/Build/Converter/CMakeLists.txt b/Build/Converter/CMakeLists.txt index 58dd1ef6..ab7d2585 100644 --- a/Build/Converter/CMakeLists.txt +++ b/Build/Converter/CMakeLists.txt @@ -171,6 +171,8 @@ if(WIN32 OR APPLE) ${CMAKE_CURRENT_SOURCE_DIR}/../../Common/Drawer/ssplayer_render_gl.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../../Common/Drawer/ssplayer_shader_gl.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../../Common/Helper/OpenGL/SSTextureGL.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/../../Common/Drawer/ssopenglninesdrawer.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/../../Common/Drawer/ssopenglshapedrawer.cpp ) list(APPEND Ss6Converter_HEADERS @@ -179,6 +181,8 @@ if(WIN32 OR APPLE) ${CMAKE_CURRENT_SOURCE_DIR}/../../Common/Drawer/ssplayer_shader_gl.h ${CMAKE_CURRENT_SOURCE_DIR}/../../Common/Helper/OpenGL/SSTextureGL.h ${CMAKE_CURRENT_SOURCE_DIR}/../../Common/Helper/stb_image_write.h + ${CMAKE_CURRENT_SOURCE_DIR}/../../Common/Drawer/ssopenglninesdrawer.h + ${CMAKE_CURRENT_SOURCE_DIR}/../../Common/Drawer/ssopenglshapedrawer.h ) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../Common/Drawer) diff --git a/Build/Converter/LumpExporter.cpp b/Build/Converter/LumpExporter.cpp index 34d8ace3..ba8e2f56 100644 --- a/Build/Converter/LumpExporter.cpp +++ b/Build/Converter/LumpExporter.cpp @@ -36,7 +36,7 @@ static std::string encode(const std::string& str, StringEncoding encoding) { switch (encoding) { case UTF8: return str; - case SJIS: return spritestudio6::SsCharConverter::utf8_to_sjis(str); // TODO: + case SJIS: return SpriteStudio::SsCharConverter::utf8_to_sjis(str); // TODO: default: break; } diff --git a/Build/Converter/main.cpp b/Build/Converter/main.cpp index b018c853..9cebb8b1 100644 --- a/Build/Converter/main.cpp +++ b/Build/Converter/main.cpp @@ -180,23 +180,23 @@ struct Options }; -typedef std::map CellList; +typedef std::map CellList; //static plog::ConsoleAppender consoleAppender; -CellList* makeCellList(spritestudio6::SsProject* proj) +CellList* makeCellList(SpriteStudio::SsProject* proj) { // セルデータの出力と、全てセルデータを集約したリストを作る - CellList* cellList = new std::map(); + CellList* cellList = new std::map(); int cellListIndex = 0; for (size_t mapIndex = 0; mapIndex < proj->cellmapList.size(); mapIndex++) { - const spritestudio6::SsCellMap* cellMap = proj->getCellMap((int)mapIndex); + const SpriteStudio::SsCellMap* cellMap = proj->getCellMap((int)mapIndex); for (size_t cellIndex = 0; cellIndex < cellMap->cells.size(); cellIndex++) { - const spritestudio6::SsCell* cell = cellMap->cells[cellIndex]; + const SpriteStudio::SsCell* cell = cellMap->cells[cellIndex]; cellList->insert(CellList::value_type(cell, cellListIndex++)); } } @@ -205,20 +205,20 @@ CellList* makeCellList(spritestudio6::SsProject* proj) } -static const spritestudio6::SsKeyframe* findDefaultKeyframe(spritestudio6::SsAnimeDecoder& decoder, int partIndex, spritestudio6::SsAttributeKind::_enum tag) +static const SpriteStudio::SsKeyframe* findDefaultKeyframe(SpriteStudio::SsAnimeDecoder& decoder, int partIndex, SpriteStudio::SsAttributeKind::_enum tag) { - SPRITESTUDIO6SDK_foreach(std::vector, decoder.getPartAnime(), it) + SPRITESTUDIO6SDK_foreach(std::vector, decoder.getPartAnime(), it) { - spritestudio6::SsPartAnime* partAnime = it->second; - spritestudio6::SsPart* part = it->first; + SpriteStudio::SsPartAnime* partAnime = it->second; + SpriteStudio::SsPart* part = it->first; if (part->arrayIndex != partIndex) continue; - SPRITESTUDIO6SDK_foreach(spritestudio6::SsAttributeList, partAnime->attributes, attrIt) + SPRITESTUDIO6SDK_foreach(SpriteStudio::SsAttributeList, partAnime->attributes, attrIt) { - spritestudio6::SsAttribute* attr = *attrIt; + SpriteStudio::SsAttribute* attr = *attrIt; if (attr->tag != tag) continue; - const spritestudio6::SsKeyframe* key = attr->firstKey(); + const SpriteStudio::SsKeyframe* key = attr->firstKey(); return key; } @@ -227,20 +227,20 @@ static const spritestudio6::SsKeyframe* findDefaultKeyframe(spritestudio6::SsAni } -static spritestudio6::SsAttribute* findAttribute(spritestudio6::SsPartAnime* partAnime, spritestudio6::SsAttributeKind::_enum tag) +static SpriteStudio::SsAttribute* findAttribute(SpriteStudio::SsPartAnime* partAnime, SpriteStudio::SsAttributeKind::_enum tag) { - SPRITESTUDIO6SDK_foreach(spritestudio6::SsAttributeList, partAnime->attributes, attrIt) + SPRITESTUDIO6SDK_foreach(SpriteStudio::SsAttributeList, partAnime->attributes, attrIt) { - spritestudio6::SsAttribute* attr = *attrIt; + SpriteStudio::SsAttribute* attr = *attrIt; if (attr->tag == tag) return attr; } return NULL; } -static const spritestudio6::SsKeyframe* findFirstKey(spritestudio6::SsPartAnime* partAnime, spritestudio6::SsAttributeKind::_enum tag) +static const SpriteStudio::SsKeyframe* findFirstKey(SpriteStudio::SsPartAnime* partAnime, SpriteStudio::SsAttributeKind::_enum tag) { - spritestudio6::SsAttribute* attr = findAttribute(partAnime, tag); + SpriteStudio::SsAttribute* attr = findAttribute(partAnime, tag); if (attr) { return attr->firstKey(); @@ -249,11 +249,11 @@ static const spritestudio6::SsKeyframe* findFirstKey(spritestudio6::SsPartAnime* } -static const spritestudio6::SsPartState* findState(std::list& partList, int partIndex) +static const SpriteStudio::SsPartState* findState(std::list& partList, int partIndex) { - SPRITESTUDIO6SDK_foreach(std::list, partList, it) + SPRITESTUDIO6SDK_foreach(std::list, partList, it) { - const spritestudio6::SsPartState* state = *it; + const SpriteStudio::SsPartState* state = *it; if (state->index == partIndex) return state; } return NULL; @@ -277,7 +277,7 @@ static std::string convert_console_string(const std::string& srcUTF8, int kindAr switch(kindArgumentEncode) { case ARGUMENT_ENCODE_SJIS: - dst = spritestudio6::SsCharConverter::utf8_to_sjis(srcUTF8); + dst = SpriteStudio::SsCharConverter::utf8_to_sjis(srcUTF8); break; case ARGUMENT_ENCODE_UTF8: @@ -360,7 +360,7 @@ void COI(std::string str) } //全全角が使われてるかのチェック -bool isZenkaku( const spritestudio6::SsString* str ) +bool isZenkaku( const SpriteStudio::SsString* str ) { bool rc = false; int i = 0; @@ -388,11 +388,11 @@ bool isZenkaku( const spritestudio6::SsString* str ) static std::vector s_frameIndexVec; -static void parseParts_ssqe(Lump* topLump, spritestudio6::SsProject* proj, const std::string& imageBaseDir) +static void parseParts_ssqe(Lump* topLump, SpriteStudio::SsProject* proj, const std::string& imageBaseDir) { } -static Lump* parseParts(spritestudio6::SsProject* proj, const std::string& imageBaseDir , const std::string& outPath) +static Lump* parseParts(SpriteStudio::SsProject* proj, const std::string& imageBaseDir , const std::string& outPath) { bool isWrite = false; @@ -404,7 +404,7 @@ static Lump* parseParts(spritestudio6::SsProject* proj, const std::string& image Lump* topLump = Lump::set("ss::ProjectData", true, "ProjectData"); - if (spritestudio6::checkFileVersion(proj->version, SPRITESTUDIO6_SSPJVERSION) == false) + if (SpriteStudio::checkFileVersion(proj->version, SPRITESTUDIO6_SSPJVERSION) == false) { /* std::cerr << "エラー:SpriteStudio Ver.5.xのプロジェクトは使用できません。\n"; @@ -464,7 +464,7 @@ static Lump* parseParts(spritestudio6::SsProject* proj, const std::string& image // セルの情報 for (size_t mapIndex = 0; mapIndex < proj->cellmapList.size(); mapIndex++) { - const spritestudio6::SsCellMap* cellMap = proj->cellmapList[mapIndex].get(); + const SpriteStudio::SsCellMap* cellMap = proj->cellmapList[mapIndex].get(); Lump* cellMapData = Lump::set("ss::CellMap", true, "CellMap"); cellMapData->add(Lump::stringData(cellMap->name, "name")); @@ -510,7 +510,7 @@ static Lump* parseParts(spritestudio6::SsProject* proj, const std::string& image } for (size_t cellIndex = 0; cellIndex < cellMap->cells.size(); cellIndex++) { - const spritestudio6::SsCell* cell = cellMap->cells[cellIndex]; + const SpriteStudio::SsCell* cell = cellMap->cells[cellIndex]; Lump* cellData = Lump::set("ss::Cell", false, "Cell"); cellsData->add(cellData); @@ -540,7 +540,7 @@ static Lump* parseParts(spritestudio6::SsProject* proj, const std::string& image { COE( "エラー:セルに全角が使用されています。半角英数でリネームしてください。: " + cell->name ); - //LOGE << spritestudio6::SsCharConverter::utf8_to_sjis("エラー:セルに全角が使用されています。半角英数でリネームしてください。: ") << cell->name; + //LOGE << SpriteStudio::SsCharConverter::utf8_to_sjis("エラー:セルに全角が使用されています。半角英数でリネームしてください。: ") << cell->name; convert_error_exit = true; //エラーが発生コンバート失敗 return 0; @@ -560,8 +560,8 @@ static Lump* parseParts(spritestudio6::SsProject* proj, const std::string& image // パーツ、アニメ情報 for (int packIndex = 0; packIndex < (int)proj->animeList.size(); packIndex++) { - const spritestudio6::SsAnimePack* animePack = proj->animeList[packIndex].get(); - const spritestudio6::SsModel& model = animePack->Model; + const SpriteStudio::SsAnimePack* animePack = proj->animeList[packIndex].get(); + const SpriteStudio::SsModel& model = animePack->Model; // AnimePackData Lump* animePackData = Lump::set("ss::AnimePackData", false, "AnimePackData"); @@ -588,7 +588,7 @@ static Lump* parseParts(spritestudio6::SsProject* proj, const std::string& image // パーツ情報(モデル)の出力 for (int partIndex = 0; partIndex < (int)model.partList.size(); partIndex++) { - const spritestudio6::SsPart* part = model.partList[partIndex]; + const SpriteStudio::SsPart* part = model.partList[partIndex]; // PartData Lump* partData = Lump::set("ss::PartData", false, "PartData" ); @@ -610,26 +610,26 @@ static Lump* parseParts(spritestudio6::SsProject* proj, const std::string& image //5.5対応5.3.5に無いパーツ種別がある場合ワーニングを表示する switch (part->type) { - case spritestudio6::SsPartType::null: // null。領域を持たずSRT情報のみ。ただし円形の当たり判定は設定可能。 - case spritestudio6::SsPartType::normal: // 通常パーツ。領域を持つ。画像は無くてもいい。 - case spritestudio6::SsPartType::mask: // 6.0マスクパーツ - case spritestudio6::SsPartType::constraint: // 6.0コンストレイントパーツ - case spritestudio6::SsPartType::bonepoint: // 6.0ボーンエフェクトパーツ - case spritestudio6::SsPartType::joint: // 6.0ジョイントパーツ - case spritestudio6::SsPartType::armature: // 6.0ボーンパーツ - case spritestudio6::SsPartType::mesh: // 6.0メッシュパーツ + case SpriteStudio::SsPartType::null: // null。領域を持たずSRT情報のみ。ただし円形の当たり判定は設定可能。 + case SpriteStudio::SsPartType::normal: // 通常パーツ。領域を持つ。画像は無くてもいい。 + case SpriteStudio::SsPartType::mask: // 6.0マスクパーツ + case SpriteStudio::SsPartType::constraint: // 6.0コンストレイントパーツ + case SpriteStudio::SsPartType::bonepoint: // 6.0ボーンエフェクトパーツ + case SpriteStudio::SsPartType::joint: // 6.0ジョイントパーツ + case SpriteStudio::SsPartType::armature: // 6.0ボーンパーツ + case SpriteStudio::SsPartType::mesh: // 6.0メッシュパーツ partData->add(Lump::s16Data(part->type, "type")); break; - case spritestudio6::SsPartType::instance: // インスタンス。他アニメ、パーツへの参照。シーン編集モードの代替になるもの + case SpriteStudio::SsPartType::instance: // インスタンス。他アニメ、パーツへの参照。シーン編集モードの代替になるもの //参照アニメのポインタが無い場合はNULLパーツになる。 { - spritestudio6::SsString packname = part->refAnimePack; - spritestudio6::SsString animename = part->refAnime; - spritestudio6::SsAnimePack* refpack = proj->findAnimationPack(packname); - spritestudio6::SsAnimation* refanime = refpack->findAnimation(animename); + SpriteStudio::SsString packname = part->refAnimePack; + SpriteStudio::SsString animename = part->refAnime; + SpriteStudio::SsAnimePack* refpack = proj->findAnimationPack(packname); + SpriteStudio::SsAnimation* refanime = refpack->findAnimation(animename); if (refanime == NULL) { - partData->add(Lump::s16Data(spritestudio6::SsPartType::null, "type")); + partData->add(Lump::s16Data(SpriteStudio::SsPartType::null, "type")); // std::cerr << "警告:参照のないインスタンスパーツが存在します: " << animePack->name << ".ssae " << part->name << "\n"; COE( "警告:参照のないインスタンスパーツが存在します: " + animePack->name + ".ssae " + part->name ); } @@ -639,11 +639,11 @@ static Lump* parseParts(spritestudio6::SsProject* proj, const std::string& image } } break; - case spritestudio6::SsPartType::effect: // 5.5エフェクトパーツ + case SpriteStudio::SsPartType::effect: // 5.5エフェクトパーツ //参照エフェクト名が空の場合はNULLパーツになる。 if (part->refEffectName == "") { - partData->add(Lump::s16Data(spritestudio6::SsPartType::null, "type")); + partData->add(Lump::s16Data(SpriteStudio::SsPartType::null, "type")); //未実装 ワーニングを表示しNULLパーツにする // std::cerr << "警告:参照のないエフェクトパーツが存在します: " << animePack->name << ".ssae " << part->name << "\n"; COE( "警告:参照のないエフェクトパーツが存在します: " + animePack->name + ".ssae " + part->name ); @@ -657,7 +657,7 @@ static Lump* parseParts(spritestudio6::SsProject* proj, const std::string& image //未対応パーツ ワーニングを表示しNULLパーツにする // std::cerr << "警告:未対応のパーツ種別が使われています: " << animePack->name << ".ssae " << part->name << "\n"; COE( "警告:未対応のパーツ種別が使われています: " + animePack->name + ".ssae " + part->name ); - partData->add(Lump::s16Data(spritestudio6::SsPartType::null, "type")); + partData->add(Lump::s16Data(SpriteStudio::SsPartType::null, "type")); break; } partData->add(Lump::s16Data(part->boundsType, "boundsType")); @@ -667,29 +667,29 @@ static Lump* parseParts(spritestudio6::SsProject* proj, const std::string& image //インスタンスアニメ名 if ( part->refAnime == "" ) { - const spritestudio6::SsString str = ""; + const SpriteStudio::SsString str = ""; // partData->add(Lump::s16Data((int)str.length())); //文字列のサイズ partData->add(Lump::stringData(str, "refname")); //文字列 } else { - const spritestudio6::SsString str = part->refAnimePack + "/" + part->refAnime; + const SpriteStudio::SsString str = part->refAnimePack + "/" + part->refAnime; // partData->add(Lump::s16Data((int)str.length())); //文字列のサイズ partData->add(Lump::stringData(str, "refname")); //文字列 } //エフェクト名 if (part->refEffectName == "") { - const spritestudio6::SsString str = ""; + const SpriteStudio::SsString str = ""; partData->add(Lump::stringData(str, "effectfilename")); //文字列 } else { - const spritestudio6::SsString str = part->refEffectName; + const SpriteStudio::SsString str = part->refEffectName; partData->add(Lump::stringData(str, "effectfilename")); //文字列 } //カラーラベル - const spritestudio6::SsString str = part->colorLabel; + const SpriteStudio::SsString str = part->colorLabel; partData->add(Lump::stringData(str, "colorLabel")); //文字列 //マスク対象 @@ -698,19 +698,19 @@ static Lump* parseParts(spritestudio6::SsProject* proj, const std::string& image } // アニメ情報の出力 - spritestudio6::SsCellMapList* cellMapList = new spritestudio6::SsCellMapList(); // SsAnimeDecoderのデストラクタで破棄される - spritestudio6::SsAnimeDecoder decoder; + SpriteStudio::SsCellMapList* cellMapList = new SpriteStudio::SsCellMapList(); // SsAnimeDecoderのデストラクタで破棄される + SpriteStudio::SsAnimeDecoder decoder; // const SsKeyframe* key; for (int animeIndex = 0; animeIndex < (int)animePack->animeList.size(); animeIndex++) { - spritestudio6::SsAnimePack* animePack = proj->getAnimePack(packIndex); - spritestudio6::SsModel* model = &animePack->Model; - spritestudio6::SsAnimation* anime = animePack->animeList[animeIndex]; + SpriteStudio::SsAnimePack* animePack = proj->getAnimePack(packIndex); + SpriteStudio::SsModel* model = &animePack->Model; + SpriteStudio::SsAnimation* anime = animePack->animeList[animeIndex]; cellMapList->set(proj, animePack); decoder.setAnimation(model, anime, cellMapList, proj); - std::list& partList = decoder.getPartSortList(); + std::list& partList = decoder.getPartSortList(); // AnimationData Lump* animeData = Lump::set("ss::AnimationData", false, "AnimationData"); @@ -726,12 +726,12 @@ static Lump* parseParts(spritestudio6::SsProject* proj, const std::string& image Lump* initialDataArray = Lump::set("ss::AnimationInitialData[]", true, "AnimationInitialData"); int sortedOrder = 0; - SPRITESTUDIO6SDK_foreach(std::vector, decoder.getPartAnime(), it) + SPRITESTUDIO6SDK_foreach(std::vector, decoder.getPartAnime(), it) { - spritestudio6::SsPart* part = it->first; -// spritestudio6::SsPartAnime* partAnime = it->second; + SpriteStudio::SsPart* part = it->first; +// SpriteStudio::SsPartAnime* partAnime = it->second; - const spritestudio6::SsPartState* state = findState(partList, part->arrayIndex); + const SpriteStudio::SsPartState* state = findState(partList, part->arrayIndex); PartInitialData init; init.sortedOrder = sortedOrder++; @@ -775,7 +775,7 @@ static Lump* parseParts(spritestudio6::SsProject* proj, const std::string& image //本来であればキーがないときはセルのサイズが初期値になる init.size_X = state->size.x; init.size_Y = state->size.y; - spritestudio6::SsCell * cell = state->cellValue.cell; + SpriteStudio::SsCell * cell = state->cellValue.cell; if ( cell ) { //セルデータがある場合はセルのサイズを初期値にする @@ -867,17 +867,17 @@ static Lump* parseParts(spritestudio6::SsProject* proj, const std::string& image decoder.setPlayFrame(0); decoder.update(); - SPRITESTUDIO6SDK_foreach(std::vector, decoder.getPartAnime(), it) + SPRITESTUDIO6SDK_foreach(std::vector, decoder.getPartAnime(), it) { - spritestudio6::SsPart* part = it->first; - const spritestudio6::SsPartState* state = findState(partList, part->arrayIndex); + SpriteStudio::SsPart* part = it->first; + const SpriteStudio::SsPartState* state = findState(partList, part->arrayIndex); //サイズ分のUV出力 Lump* meshData = Lump::set("ss::ss_u16*[]", true, "meshData"); meshsDataUV->add(meshData); //メッシュのサイズを書き出す - if (part->type == spritestudio6::SsPartType::mesh) + if (part->type == SpriteStudio::SsPartType::mesh) { int meshsize = state->meshPart->ver_size; meshData->add(Lump::s32Data((int)state->meshPart->isBind, "isBind")); //バインドの有無 @@ -906,17 +906,17 @@ static Lump* parseParts(spritestudio6::SsProject* proj, const std::string& image decoder.setPlayFrame(0); decoder.update(); - SPRITESTUDIO6SDK_foreach(std::vector, decoder.getPartAnime(), it) + SPRITESTUDIO6SDK_foreach(std::vector, decoder.getPartAnime(), it) { - spritestudio6::SsPart* part = it->first; - const spritestudio6::SsPartState* state = findState(partList, part->arrayIndex); + SpriteStudio::SsPart* part = it->first; + const SpriteStudio::SsPartState* state = findState(partList, part->arrayIndex); //サイズ分のUV出力 Lump* meshData = Lump::set("ss::ss_u16*[]", true, "meshData"); meshsDataIndices->add(meshData); //メッシュのサイズを書き出す - if (part->type == spritestudio6::SsPartType::mesh) + if (part->type == SpriteStudio::SsPartType::mesh) { int tri_size = state->meshPart->tri_size; meshData->add(Lump::s32Data(tri_size, "tri_size")); //サイズ @@ -971,11 +971,11 @@ static Lump* parseParts(spritestudio6::SsProject* proj, const std::string& image // frameData->add(frameFlag); int outPartsCount = 0; - SPRITESTUDIO6SDK_foreach(std::list, partList, it) + SPRITESTUDIO6SDK_foreach(std::list, partList, it) { - const spritestudio6::SsPartState* state = *it; + const SpriteStudio::SsPartState* state = *it; //セルに設定された原点補正を取得 - spritestudio6::SsVector2 pivot; + SpriteStudio::SsVector2 pivot; pivot.x = 0; pivot.y = 0; //セルの原点情報はセル情報へ含める @@ -1080,7 +1080,7 @@ static Lump* parseParts(spritestudio6::SsProject* proj, const std::string& image { switch (state->partsColorValue.target) { - case spritestudio6::SsColorBlendTarget::whole: + case SpriteStudio::SsColorBlendTarget::whole: if ( ( state->partsColorValue.color.rgba.a == 0 ) && ( state->partsColorValue.color.rgba.r == 0 ) @@ -1098,7 +1098,7 @@ static Lump* parseParts(spritestudio6::SsProject* proj, const std::string& image } break; - case spritestudio6::SsColorBlendTarget::vertex: + case SpriteStudio::SsColorBlendTarget::vertex: cb_flags = VERTEX_FLAG_LT|VERTEX_FLAG_RT|VERTEX_FLAG_LB|VERTEX_FLAG_RB; break; default: @@ -1145,7 +1145,7 @@ static Lump* parseParts(spritestudio6::SsProject* proj, const std::string& image int p_flags2 = 0; //メッシュ情報を出力する必要があるかチェックする - if (state->partType == spritestudio6::SsPartType::mesh) + if (state->partType == SpriteStudio::SsPartType::mesh) { p_flags2 |= PART_FLAG_MESHDATA; } @@ -1395,16 +1395,16 @@ static Lump* parseParts(spritestudio6::SsProject* proj, const std::string& image Lump* userData = Lump::set("ss::ss_u16[]", true, "userData"); int partsCount = 0; - SPRITESTUDIO6SDK_foreach(std::vector, decoder.getPartAnime(), it) + SPRITESTUDIO6SDK_foreach(std::vector, decoder.getPartAnime(), it) { - spritestudio6::SsPart* part = it->first; - spritestudio6::SsPartAnime* partAnime = it->second; + SpriteStudio::SsPart* part = it->first; + SpriteStudio::SsPartAnime* partAnime = it->second; if (!partAnime) continue; - SPRITESTUDIO6SDK_foreach(spritestudio6::SsAttributeList, partAnime->attributes, attrIt) + SPRITESTUDIO6SDK_foreach(SpriteStudio::SsAttributeList, partAnime->attributes, attrIt) { - spritestudio6::SsAttribute* attr = *attrIt; - if (attr->tag != spritestudio6::SsAttributeKind::user) continue; + SpriteStudio::SsAttribute* attr = *attrIt; + if (attr->tag != SpriteStudio::SsAttributeKind::user) continue; // このフレームのデータを含む? if (attr->key_dic.find(frame) != attr->key_dic.end()) @@ -1412,8 +1412,8 @@ static Lump* parseParts(spritestudio6::SsProject* proj, const std::string& image hasUserData = true; partsCount++; - const spritestudio6::SsKeyframe* keyframe = attr->key_dic.at(frame); - spritestudio6::SsUserDataAnime udat; + const SpriteStudio::SsKeyframe* keyframe = attr->key_dic.at(frame); + SpriteStudio::SsUserDataAnime udat; GetSsUserDataAnime(keyframe, udat); int flags = 0; @@ -1431,10 +1431,10 @@ static Lump* parseParts(spritestudio6::SsProject* proj, const std::string& image } if (udat.useRect) { - userData->add(Lump::s32Data(udat.rect.x, "rect_x")); - userData->add(Lump::s32Data(udat.rect.y, "rect_y")); - userData->add(Lump::s32Data(udat.rect.w, "rect_w")); - userData->add(Lump::s32Data(udat.rect.h, "rect_h")); + userData->add(Lump::s32Data(udat.rect.x(), "rect_x")); + userData->add(Lump::s32Data(udat.rect.y(), "rect_y")); + userData->add(Lump::s32Data(udat.rect.width(), "rect_w")); + userData->add(Lump::s32Data(udat.rect.height(), "rect_h")); } if (udat.usePoint) { @@ -1443,7 +1443,7 @@ static Lump* parseParts(spritestudio6::SsProject* proj, const std::string& image } if (udat.useString) { - const spritestudio6::SsString& str = udat.string; + const SpriteStudio::SsString& str = udat.string; userData->add(Lump::s16Data((int)str.length(), "str_length")); userData->add(Lump::stringData(str, "str")); } @@ -1473,7 +1473,7 @@ static Lump* parseParts(spritestudio6::SsProject* proj, const std::string& image { Lump* labelData = Lump::set("ss::ss_u16[]", true, "labelData"); - spritestudio6::SsString str; + SpriteStudio::SsString str; str = anime->labels[label_idx]->name; //全角チェック if ( isZenkaku( &str ) == true ) @@ -1541,7 +1541,7 @@ static Lump* parseParts(spritestudio6::SsProject* proj, const std::string& image // ConverterOpenGLOutputBitMapImage 内の stbi_write_png は fopen を使っており narrow 文字のみなのでWin向けにSJIS化が必要。 // ToDo: sspkg 以外で Win の全角対応をする場合、 ConverterOpenGLOutputBitMapImage 側に以下相当の変換を追加。 - outputfile = spritestudio6::SsCharConverter::convert_path_string(outputfile); + outputfile = SpriteStudio::SsCharConverter::convert_path_string(outputfile); //filelist.push_back(outputfile); if (!isWrite) @@ -1571,10 +1571,10 @@ static Lump* parseParts(spritestudio6::SsProject* proj, const std::string& image Lump* effectFile = Lump::set("ss::EffectFile", false, "EffectFile"); effectfileArray->add(effectFile); - const spritestudio6::SsEffectFile* effectfile = proj->getEffectFile(effectIndex); + const SpriteStudio::SsEffectFile* effectfile = proj->getEffectFile(effectIndex); effectFile->add(Lump::stringData(effectfile->name, "name")); //エフェクト名 - const spritestudio6::SsEffectModel *effectmodel = &effectfile->effectData; + const SpriteStudio::SsEffectModel *effectmodel = &effectfile->effectData; effectFile->add(Lump::s16Data(effectmodel->fps, "fps")); //FPS effectFile->add(Lump::s16Data(effectmodel->isLockRandSeed, "isLockRandSeed")); //乱数を固定するかどうか @@ -1598,24 +1598,24 @@ static Lump* parseParts(spritestudio6::SsProject* proj, const std::string& image Lump* effectNode = Lump::set("ss::EffectNode", false, "EffectNode"); effectNodeArray->add(effectNode); - spritestudio6::SsEffectNode *node = effectmodel->nodeList[nodeindex]; + SpriteStudio::SsEffectNode *node = effectmodel->nodeList[nodeindex]; int arrayIndex = node->arrayIndex; //通し番号 int parentIndex = node->parentIndex; //親の番号 - spritestudio6::SsEffectNodeType::_enum type = node->type; //ノードの種類 + SpriteStudio::SsEffectNodeType::_enum type = node->type; //ノードの種類 // bool visible = = node->visible; //エディター用 //MEMO: 旧ソースではbehaviorが実体にしてnode->behaviorの内容をコピーしていたが……スマートポインタ化後は // 所有権の問題でエラーがでるので注意(スマートポインタの所有権の関係) - spritestudio6::SsEffectBehavior& behavior = node->behavior; //動作パラメータ - spritestudio6::SsRenderBlendType::_enum blendType = behavior.BlendType; //描画方法 + SpriteStudio::SsEffectBehavior& behavior = node->behavior; //動作パラメータ + SpriteStudio::SsRenderBlendType::_enum blendType = behavior.BlendType; //描画方法 //セル番号 - spritestudio6::SsCell* refCell = behavior.refCell; + SpriteStudio::SsCell* refCell = behavior.refCell; int cellIndex = -1; if (refCell) { cellIndex = (*cellList)[refCell]; } - spritestudio6::SsString CellName = behavior.CellName; - spritestudio6::SsString CellMapName = behavior.CellMapName; + SpriteStudio::SsString CellName = behavior.CellName; + SpriteStudio::SsString CellMapName = behavior.CellMapName; //ファイルへ書き出し effectNode->add(Lump::s16Data(arrayIndex, "arrayIndex")); //通し番号 effectNode->add(Lump::s16Data(parentIndex, "parentIndex")); //親の番号 @@ -1633,20 +1633,20 @@ static Lump* parseParts(spritestudio6::SsProject* proj, const std::string& image Lump* effectBehavior = Lump::set("ss::ss_u16[]", true, "effectBehavior"); effectBehaviorArray->add(effectBehavior); - spritestudio6::SsEffectElementBase *elementbase = behavior.plist[plistindex].get(); - spritestudio6::SsEffectFunctionType::enum_ myType = elementbase->myType; + SpriteStudio::SsEffectElementBase *elementbase = behavior.plist[plistindex].get(); + SpriteStudio::SsEffectFunctionType::enum_ myType = elementbase->myType; effectBehavior->add(Lump::s32Data(myType, "SsEffectFunctionType")); //コマンドタイプ switch (myType) { - case spritestudio6::SsEffectFunctionType::Basic: + case SpriteStudio::SsEffectFunctionType::Basic: { //基本情報 - spritestudio6::ParticleElementBasic *element = (spritestudio6::ParticleElementBasic*)elementbase; + SpriteStudio::ParticleElementBasic *element = (SpriteStudio::ParticleElementBasic*)elementbase; int maximumParticle = element->maximumParticle; - spritestudio6::f32VValue speed = element->speed; - spritestudio6::i32VValue lifespan = element->lifespan; + SpriteStudio::f32VValue speed = element->speed; + SpriteStudio::i32VValue lifespan = element->lifespan; float angle = element->angle; float angleVariance = element->angleVariance; int interval = element->interval; @@ -1671,118 +1671,118 @@ static Lump* parseParts(spritestudio6::SsProject* proj, const std::string& image effectBehavior->add(Lump::floatData(angleVariance, "angleVariance")); //射出方向範囲 break; } - case spritestudio6::SsEffectFunctionType::RndSeedChange: + case SpriteStudio::SsEffectFunctionType::RndSeedChange: { //シード上書き - spritestudio6::ParticleElementRndSeedChange *element = (spritestudio6::ParticleElementRndSeedChange*)elementbase; + SpriteStudio::ParticleElementRndSeedChange *element = (SpriteStudio::ParticleElementRndSeedChange*)elementbase; int Seed = element->Seed; effectBehavior->add(Lump::s32Data(Seed, "Seed")); //上書きする値 break; } - case spritestudio6::SsEffectFunctionType::Delay: + case SpriteStudio::SsEffectFunctionType::Delay: { //発生:タイミング - spritestudio6::ParticleElementDelay *element = (spritestudio6::ParticleElementDelay*)elementbase; + SpriteStudio::ParticleElementDelay *element = (SpriteStudio::ParticleElementDelay*)elementbase; int DelayTime = element->DelayTime; effectBehavior->add(Lump::s32Data(DelayTime, "DelayTime")); //遅延時間 break; } - case spritestudio6::SsEffectFunctionType::Gravity: + case SpriteStudio::SsEffectFunctionType::Gravity: { //重力を加える - spritestudio6::ParticleElementGravity *element = (spritestudio6::ParticleElementGravity*)elementbase; - spritestudio6::SsVector2 Gravity = element->Gravity; + SpriteStudio::ParticleElementGravity *element = (SpriteStudio::ParticleElementGravity*)elementbase; + SpriteStudio::SsVector2 Gravity = element->Gravity; effectBehavior->add(Lump::floatData(Gravity.x, "Gravity_x")); //X方向の重力 effectBehavior->add(Lump::floatData(Gravity.y, "Gravity_y")); //Y方向の重力 break; } - case spritestudio6::SsEffectFunctionType::Position: + case SpriteStudio::SsEffectFunctionType::Position: { //座標:生成時 - spritestudio6::ParticleElementPosition *element = (spritestudio6::ParticleElementPosition*)elementbase; - spritestudio6::f32VValue OffsetX = element->OffsetX; - spritestudio6::f32VValue OffsetY = element->OffsetY; + SpriteStudio::ParticleElementPosition *element = (SpriteStudio::ParticleElementPosition*)elementbase; + SpriteStudio::f32VValue OffsetX = element->OffsetX; + SpriteStudio::f32VValue OffsetY = element->OffsetY; effectBehavior->add(Lump::floatData(OffsetX.getMinValue(), "OffsetXMinValue")); //X座標に加算最小 effectBehavior->add(Lump::floatData(OffsetX.getMaxValue(), "OffsetXMaxValue")); //X座標に加算最大 effectBehavior->add(Lump::floatData(OffsetY.getMinValue(), "OffsetYMinValue")); //X座標に加算最小 effectBehavior->add(Lump::floatData(OffsetY.getMaxValue(), "OffsetYMaxValue")); //X座標に加算最大 break; } - case spritestudio6::SsEffectFunctionType::Rotation: + case SpriteStudio::SsEffectFunctionType::Rotation: { //Z回転を追加 - spritestudio6::ParticleElementRotation *element = (spritestudio6::ParticleElementRotation*)elementbase; - spritestudio6::f32VValue Rotation = element->Rotation; - spritestudio6::f32VValue RotationAdd = element->RotationAdd; + SpriteStudio::ParticleElementRotation *element = (SpriteStudio::ParticleElementRotation*)elementbase; + SpriteStudio::f32VValue Rotation = element->Rotation; + SpriteStudio::f32VValue RotationAdd = element->RotationAdd; effectBehavior->add(Lump::floatData(Rotation.getMinValue(), "RotationMinValue")); //角度初期値最小 effectBehavior->add(Lump::floatData(Rotation.getMaxValue(), "RotationMaxValue")); //角度初期値最大 effectBehavior->add(Lump::floatData(RotationAdd.getMinValue(), "RotationAddMinValue")); //角度初期加算値最小 effectBehavior->add(Lump::floatData(RotationAdd.getMaxValue(), "RotationAddMaxValue")); //角度初期加算値最大 break; } - case spritestudio6::SsEffectFunctionType::TransRotation: + case SpriteStudio::SsEffectFunctionType::TransRotation: { //Z回転速度変更 - spritestudio6::ParticleElementRotationTrans *element = (spritestudio6::ParticleElementRotationTrans*)elementbase; + SpriteStudio::ParticleElementRotationTrans *element = (SpriteStudio::ParticleElementRotationTrans*)elementbase; float RotationFactor = element->RotationFactor; float EndLifeTimePer = element->EndLifeTimePer; effectBehavior->add(Lump::floatData(RotationFactor, "RotationFactor")); //角度目標加算値 effectBehavior->add(Lump::floatData(EndLifeTimePer, "EndLifeTimePer")); //到達時間 break; } - case spritestudio6::SsEffectFunctionType::TransSpeed: + case SpriteStudio::SsEffectFunctionType::TransSpeed: { //速度:変化 - spritestudio6::ParticleElementTransSpeed *element = (spritestudio6::ParticleElementTransSpeed*)elementbase; - spritestudio6::f32VValue Speed = element->Speed; + SpriteStudio::ParticleElementTransSpeed *element = (SpriteStudio::ParticleElementTransSpeed*)elementbase; + SpriteStudio::f32VValue Speed = element->Speed; effectBehavior->add(Lump::floatData(Speed.getMinValue(), "SpeedMinValue")); //速度目標値最小 effectBehavior->add(Lump::floatData(Speed.getMaxValue(), "SpeedMaxValue")); //速度目標値最大 break; } - case spritestudio6::SsEffectFunctionType::TangentialAcceleration: + case SpriteStudio::SsEffectFunctionType::TangentialAcceleration: { //接線加速度 - spritestudio6::ParticleElementTangentialAcceleration *element = (spritestudio6::ParticleElementTangentialAcceleration*)elementbase; - spritestudio6::f32VValue Acceleration = element->Acceleration; + SpriteStudio::ParticleElementTangentialAcceleration *element = (SpriteStudio::ParticleElementTangentialAcceleration*)elementbase; + SpriteStudio::f32VValue Acceleration = element->Acceleration; effectBehavior->add(Lump::floatData(Acceleration.getMinValue(), "AccelerationMinValue")); //設定加速度最小 effectBehavior->add(Lump::floatData(Acceleration.getMaxValue(), "AccelerationMaxValue")); //設定加速度最大 break; } - case spritestudio6::SsEffectFunctionType::InitColor: + case SpriteStudio::SsEffectFunctionType::InitColor: { //カラーRGBA:生成時 - spritestudio6::ParticleElementInitColor *element = (spritestudio6::ParticleElementInitColor*)elementbase; - spritestudio6::SsU8cVValue Color = element->Color; + SpriteStudio::ParticleElementInitColor *element = (SpriteStudio::ParticleElementInitColor*)elementbase; + SpriteStudio::SsU8cVValue Color = element->Color; effectBehavior->add(Lump::s32Data(Color.getMinValue().toARGB(), "ColorMinValue")); //設定カラー最小 effectBehavior->add(Lump::s32Data(Color.getMaxValue().toARGB(), "ColorMaxValue")); //設定カラー最大 break; } - case spritestudio6::SsEffectFunctionType::TransColor: + case SpriteStudio::SsEffectFunctionType::TransColor: { //カラーRGB:変化 - spritestudio6::ParticleElementTransColor *element = (spritestudio6::ParticleElementTransColor*)elementbase; - spritestudio6::SsU8cVValue Color = element->Color; + SpriteStudio::ParticleElementTransColor *element = (SpriteStudio::ParticleElementTransColor*)elementbase; + SpriteStudio::SsU8cVValue Color = element->Color; effectBehavior->add(Lump::s32Data(Color.getMinValue().toARGB(), "ColorMinValue")); //設定カラー最小 effectBehavior->add(Lump::s32Data(Color.getMaxValue().toARGB(), "ColorMaxValue")); //設定カラー最大 break; } - case spritestudio6::SsEffectFunctionType::AlphaFade: + case SpriteStudio::SsEffectFunctionType::AlphaFade: { //フェード - spritestudio6::ParticleElementAlphaFade *element = (spritestudio6::ParticleElementAlphaFade*)elementbase; - spritestudio6::f32VValue disprange = element->disprange; // mnagaku 頭小文字 + SpriteStudio::ParticleElementAlphaFade *element = (SpriteStudio::ParticleElementAlphaFade*)elementbase; + SpriteStudio::f32VValue disprange = element->disprange; // mnagaku 頭小文字 effectBehavior->add(Lump::floatData(disprange.getMinValue(), "disprangeMinValue")); //表示区間開始 effectBehavior->add(Lump::floatData(disprange.getMaxValue(), "disprangeMaxValue")); //表示区間終了 break; } - case spritestudio6::SsEffectFunctionType::Size: + case SpriteStudio::SsEffectFunctionType::Size: { //スケール:生成時 - spritestudio6::ParticleElementSize *element = (spritestudio6::ParticleElementSize*)elementbase; - spritestudio6::f32VValue SizeX = element->SizeX; - spritestudio6::f32VValue SizeY = element->SizeY; - spritestudio6::f32VValue ScaleFactor = element->ScaleFactor; + SpriteStudio::ParticleElementSize *element = (SpriteStudio::ParticleElementSize*)elementbase; + SpriteStudio::f32VValue SizeX = element->SizeX; + SpriteStudio::f32VValue SizeY = element->SizeY; + SpriteStudio::f32VValue ScaleFactor = element->ScaleFactor; effectBehavior->add(Lump::floatData(SizeX.getMinValue(), "SizeXMinValue")); //幅倍率最小 effectBehavior->add(Lump::floatData(SizeX.getMaxValue(), "SizeXMaxValue")); //幅倍率最大 effectBehavior->add(Lump::floatData(SizeY.getMinValue(), "SizeYMinValue")); //高さ倍率最小 @@ -1791,13 +1791,13 @@ static Lump* parseParts(spritestudio6::SsProject* proj, const std::string& image effectBehavior->add(Lump::floatData(ScaleFactor.getMaxValue(), "ScaleFactorMaxValue")); //倍率最大 break; } - case spritestudio6::SsEffectFunctionType::TransSize: + case SpriteStudio::SsEffectFunctionType::TransSize: { //スケール:変化 - spritestudio6::ParticleElementTransSize *element = (spritestudio6::ParticleElementTransSize*)elementbase; - spritestudio6::f32VValue SizeX = element->SizeX; - spritestudio6::f32VValue SizeY = element->SizeY; - spritestudio6::f32VValue ScaleFactor = element->ScaleFactor; + SpriteStudio::ParticleElementTransSize *element = (SpriteStudio::ParticleElementTransSize*)elementbase; + SpriteStudio::f32VValue SizeX = element->SizeX; + SpriteStudio::f32VValue SizeY = element->SizeY; + SpriteStudio::f32VValue ScaleFactor = element->ScaleFactor; effectBehavior->add(Lump::floatData(SizeX.getMinValue(), "SizeXMinValue")); //幅倍率最小 effectBehavior->add(Lump::floatData(SizeX.getMaxValue(), "SizeXMaxValue")); //幅倍率最大 effectBehavior->add(Lump::floatData(SizeY.getMinValue(), "SizeYMinValue")); //高さ倍率最小 @@ -1806,34 +1806,34 @@ static Lump* parseParts(spritestudio6::SsProject* proj, const std::string& image effectBehavior->add(Lump::floatData(ScaleFactor.getMaxValue(), "ScaleFactorMaxValue")); //倍率最大 break; } - case spritestudio6::SsEffectFunctionType::PointGravity: + case SpriteStudio::SsEffectFunctionType::PointGravity: { //重力点の追加 - spritestudio6::ParticlePointGravity *element = (spritestudio6::ParticlePointGravity*)elementbase; - spritestudio6::SsVector2 Position = element->Position; + SpriteStudio::ParticlePointGravity *element = (SpriteStudio::ParticlePointGravity*)elementbase; + SpriteStudio::SsVector2 Position = element->Position; float Power = element->Power; effectBehavior->add(Lump::floatData(Position.x, "Position_x")); //重力点X effectBehavior->add(Lump::floatData(Position.y, "Position_y")); //重力点Y effectBehavior->add(Lump::floatData(Power, "Power")); //パワー break; } - case spritestudio6::SsEffectFunctionType::TurnToDirectionEnabled: + case SpriteStudio::SsEffectFunctionType::TurnToDirectionEnabled: { //進行方向に向ける - spritestudio6::ParticleTurnToDirectionEnabled *element = (spritestudio6::ParticleTurnToDirectionEnabled*)elementbase; + SpriteStudio::ParticleTurnToDirectionEnabled *element = (SpriteStudio::ParticleTurnToDirectionEnabled*)elementbase; //コマンドがあれば有効 effectBehavior->add(Lump::floatData(element->Rotation, "Rotation")); //方向オフセット break; } - case spritestudio6::SsEffectFunctionType::InfiniteEmitEnabled: + case SpriteStudio::SsEffectFunctionType::InfiniteEmitEnabled: { //無限にする - spritestudio6::ParticleInfiniteEmitEnabled *element = (spritestudio6::ParticleInfiniteEmitEnabled*)elementbase; + SpriteStudio::ParticleInfiniteEmitEnabled *element = (SpriteStudio::ParticleInfiniteEmitEnabled*)elementbase; //コマンドがあれば有効 effectBehavior->add(Lump::s32Data(1, "flag")); //ダミーデータ break; } - case spritestudio6::SsEffectFunctionType::Base: + case SpriteStudio::SsEffectFunctionType::Base: default: //未使用のコマンドが含まれている //std::cerr << "警告:未使用のエフェクトコマンドが含まれています。 \n"; @@ -1855,7 +1855,7 @@ static Lump* parseParts(spritestudio6::SsProject* proj, const std::string& image return topLump; } -void createPackFileList(spritestudio6::SsProject* proj , std::string sspjPath , std::vector& filelist) +void createPackFileList(SpriteStudio::SsProject* proj , std::string sspjPath , std::vector& filelist) { std::string pjpath = FileUtil::getFilePath(sspjPath); pjpath = FileUtil::normalizeFilePath(pjpath); @@ -1903,7 +1903,7 @@ void convertProject(const std::string& outPath, const std::string& outFName, std::string outputdirUTF8; // 事前の parseArguments 処理時にUTF8変換するようにしたためここでの変換をカットしました。 - //outputdirUTF8 = spritestudio6::SsCharConverter::sjis_to_utf8(outPath); + //outputdirUTF8 = SpriteStudio::SsCharConverter::sjis_to_utf8(outPath); outputdirUTF8 = outPath; COI("output directory: " + outputdirUTF8); @@ -1922,7 +1922,7 @@ void convertProject(const std::string& outPath, const std::string& outFName, } } - spritestudio6::SsProject* proj = spritestudio6::ssloader_sspj::Load(sspjPath); + SpriteStudio::SsProject* proj = SpriteStudio::ssloader_sspj::Load(sspjPath); fs::path logfilepath = fs::path(outputdirUTF8).replace_filename("convert.log"); // static plog::RollingFileAppender fileAppender(logfilepath.c_str()); @@ -1987,7 +1987,7 @@ void convertProject(const std::string& outPath, const std::string& outFName, // out.open((outPath + ".json").c_str(), std::ios_base::out); std::string outPathJson = outPath + outFName + ".json"; - out.open((spritestudio6::SsCharConverter::convert_path_string( outPathJson )).c_str() + out.open((SpriteStudio::SsCharConverter::convert_path_string( outPathJson )).c_str() , std::ios_base::out); if(out) { @@ -2018,7 +2018,7 @@ void convertProject(const std::string& outPath, const std::string& outFName, COI( "outPathSsfb " + outPathSsfb ); - out.open((spritestudio6::SsCharConverter::convert_path_string(outPathSsfb)).c_str() + out.open((SpriteStudio::SsCharConverter::convert_path_string(outPathSsfb)).c_str() , std::ios_base::binary | std::ios_base::out); if(out) { @@ -2036,7 +2036,7 @@ void convertProject(const std::string& outPath, const std::string& outFName, std::string outPathSsfb = sspkg_info::getInst()->get_sspkg_temppath() + outFName + ".ssfb";//出力はFB - out.open((spritestudio6::SsCharConverter::convert_path_string(outPathSsfb)).c_str() + out.open((SpriteStudio::SsCharConverter::convert_path_string(outPathSsfb)).c_str() , std::ios_base::binary | std::ios_base::out); if (out) { @@ -2059,7 +2059,7 @@ void convertProject(const std::string& outPath, const std::string& outFName, COI( "convert type : OUTPUT_FORMAT_FLAG_SSBP " ); std::string outPathSsfb = outPath + outFName + ".ssbp"; - out.open((spritestudio6::SsCharConverter::convert_path_string(outPathSsfb)).c_str() + out.open((SpriteStudio::SsCharConverter::convert_path_string(outPathSsfb)).c_str() , std::ios_base::binary | std::ios_base::out); if(out) { @@ -2293,7 +2293,7 @@ bool parseArguments(Options& options, int argc, const char* argv[], std::string& case ARGUMENT_ENCODE_SJIS: #ifdef _WIN32 - nameUTF8 = spritestudio6::SsCharConverter::sjis_to_utf8(name);; + nameUTF8 = SpriteStudio::SsCharConverter::sjis_to_utf8(name);; // LOGI << "name : (sjis)" << nameUTF8; break; #else @@ -2315,7 +2315,7 @@ bool parseArguments(Options& options, int argc, const char* argv[], std::string& if (options.argumentEncode == ARGUMENT_ENCODE_SJIS) { - options.outputDir = spritestudio6::SsCharConverter::sjis_to_utf8(options.outputDir); + options.outputDir = SpriteStudio::SsCharConverter::sjis_to_utf8(options.outputDir); } // success @@ -2369,8 +2369,8 @@ int convertMain(int argc, const char * argv[]) #ifdef _BACKBUFFER_RENDERING__ - std::unique_ptr texFactory; - //spritestudio6::SSTextureFactory* texFactory = nullptr; + std::unique_ptr texFactory; + //SpriteStudio::SSTextureFactory* texFactory = nullptr; if (options.outputFormat == OUTPUT_FORMAT_FLAG_SSPKG) { @@ -2383,8 +2383,8 @@ int convertMain(int argc, const char * argv[]) } else { texFactory.reset( - new spritestudio6::SSTextureFactory( - new spritestudio6::SSTextureBMP() + new SpriteStudio::SSTextureFactory( + new SpriteStudio::SSTextureBMP() ) ); } @@ -2407,12 +2407,12 @@ int convertMain(int argc, const char * argv[]) #ifdef _WIN32 // Win32プラットフォーム用コード。Win32APIを使ってワイルドカード展開する // MEMO: FileUtilで使用している文字コードはSJISであることに注意 - std::vector fileList = FileUtil::findPath(spritestudio6::SsCharConverter::utf8_to_sjis(str)); + std::vector fileList = FileUtil::findPath(SpriteStudio::SsCharConverter::utf8_to_sjis(str)); if (!fileList.empty()) { for(std::vector::iterator it=fileList.begin(); it != fileList.end(); it++) { - sources.push_back(spritestudio6::SsCharConverter::sjis_to_utf8(*it)); + sources.push_back(SpriteStudio::SsCharConverter::sjis_to_utf8(*it)); } } else diff --git a/Build/Converter/simpleFileLogger.h b/Build/Converter/simpleFileLogger.h index 2191ea87..579e1606 100644 --- a/Build/Converter/simpleFileLogger.h +++ b/Build/Converter/simpleFileLogger.h @@ -32,7 +32,7 @@ class Logger std::string OSLocaleString(std::string str) { #if _WIN32 - str = spritestudio6::SsCharConverter::sjis_to_utf8(str); + str = SpriteStudio::SsCharConverter::sjis_to_utf8(str); #endif return str; } diff --git a/Build/Converter/sspkg.cpp b/Build/Converter/sspkg.cpp index 425cf47e..52401a1a 100644 --- a/Build/Converter/sspkg.cpp +++ b/Build/Converter/sspkg.cpp @@ -17,7 +17,7 @@ using json = nlohmann::json; -using sscc = spritestudio6::SsCharConverter; +using sscc = SpriteStudio::SsCharConverter; int CreateZipFile(std::string zippath , std::vector paths , std::string remove_path ) { diff --git a/Build/TestData/allAttributeV7/9slice_64tile.png b/Build/TestData/allAttributeV7/9slice_64tile.png new file mode 100644 index 00000000..4829de1b Binary files /dev/null and b/Build/TestData/allAttributeV7/9slice_64tile.png differ diff --git a/Build/TestData/allAttributeV7/NewEffect.ssee b/Build/TestData/allAttributeV7/NewEffect.ssee new file mode 100644 index 00000000..4db42699 --- /dev/null +++ b/Build/TestData/allAttributeV7/NewEffect.ssee @@ -0,0 +1,62 @@ + + + NewEffect + + + 0 + 0 + 30 + FF000000 + 2 + 100 + 100 + + + Root + Root + 0 + -1 + 1 + + + Emitter_1 + Emmiter + 1 + 0 + 1 + + NewCell_9 + color_bar.ssce + Add + + + Basic + 64 + 20 + 1 + 1 + 30 + + + 0 + 45 + + + + + + Particle_1 + Particle + 2 + 1 + 1 + + + + Add + + + + + + diff --git a/Build/TestData/allAttributeV7/allAttributeV7.sspj b/Build/TestData/allAttributeV7/allAttributeV7.sspj new file mode 100644 index 00000000..f78d48d6 --- /dev/null +++ b/Build/TestData/allAttributeV7/allAttributeV7.sspj @@ -0,0 +1,252 @@ + + + allAttributeV7 + + + + + + + Export + 1 + 1 + SSAX + invalid + 0 + 1 + + any + + 0 + 0 + 0 + 1 + 1 + 0 + 1 + + none + linear + hermite + bezier + acceleration + deceleration + + + CELL + POSX + POSY + POSZ + ROTX + ROTY + ROTZ + SCLX + SCLY + LSCX + LSCY + ALPH + LALP + PRIO + IFLH + IFLV + FLPH + FLPV + HIDE + PCOL + VCOL + VERT + PVTX + PVTY + ANCX + ANCY + SIZX + SIZY + UVTX + UVTY + UVRZ + UVSX + UVSY + BNDR + MASK + USER + IPRM + EFCT + + + bone + effect + mask + mesh + nines + shape + sound + text + + + POSX + POSY + ROTZ + PRIO + HIDE + + clamp + linear + linear + rate + + + AVI + FF606060 + 0 + 0 + 1 + 100 + 100 + 1 + 1 + 0 + 0 + 0 + 0 + + lossless + 75 + 4 + 1 + 0 + + + 1536000 + + + + 50 + + + 2 + 1 + 0 + 0 + 0 + 0 + 0 + 8192 + 8192 + 73400320 + 100 + 0 + + + + + + + + + + + + + + + + + + + + + + + 60 + 60 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 59 + + + + 1 + 0 0 + 0 0 + 0 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + 0 + + + 4096 4096 + 1 + 0 + 0 + 1 + + + color_bar.ssce + + + alpha.ssae + boundr.ssae + cell.ssae + deform.ssae + deform_bone.ssae + easing.ssae + effect.ssae + hide.ssae + imgflip.ssae + instance.ssae + instance_flag.ssae + iptype.ssae + loalpha.ssae + loscl.ssae + mask.ssae + partsColor.ssae + pivot.ssae + pos.ssae + prio.ssae + rot.ssae + scl.ssae + setupdata.ssae + size.ssae + startend.ssae + textureChange.ssae + userdata.ssae + uvs.ssae + uvt.ssae + vertex.ssae + + + NewEffect.ssee + + + + + 9slice_64tile.png + 0 + 0 + + + + easing.ssae + anime_1 + イーズイン + color_bar.ssce + NewCell_9 + + NewEffect.ssee + 0 + + + diff --git a/Build/TestData/allAttributeV7/alpha.ssae b/Build/TestData/allAttributeV7/alpha.ssae new file mode 100644 index 00000000..b224cb19 --- /dev/null +++ b/Build/TestData/allAttributeV7/alpha.ssae @@ -0,0 +1,502 @@ + + + + 30 + 11 + prio + 320 320 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 10 + + + + 1 + 0 0 + 0 0 + 0 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + 0 + + alpha + + + + + root + 0 + -1 + null + none + self + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_3 + 1 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_4 + 2 + 1 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell + 3 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_1 + 4 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_2 + 5 + 4 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + + + + + color_bar.ssce + + + + Setup + 1 + + 60 + 1 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + 0 + + + 1 + + + root + + + + 0 + + + + + + + + anime_1 + 1 + + 60 + 60 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 59 + + + + 1 + 0 0 + 0 0 + 0 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + 0 + + + 0 + + + root + + + + 0 + + + + + + NewCell_3 + + + + + 0 + NewCell_2 + + + + + + -114 + + + + + -110 + + + + + 0 + + + + + 1 + + + 0 + + + + + 0 + + + + + 0 + + + + + + NewCell_4 + + + + + 0 + NewCell_2 + + + + + + 44 + + + + + -41 + + + + + 0 + + + + + 1 + + + 0 + + + + + 0 + + + + + 0 + + + + + + NewCell + + + + + 0 + NewCell + + + + + + -117 + + + + + 1.5 + + + + + 0 + + + + + 1 + + + 0 + + + + + 0 + + + + + 0 + + + + + + NewCell_1 + + + + + 0 + NewCell_1 + + + + + + 121 + + + + + 0.5 + + + + + 0 + + + + + 1 + + + 0 + + + + + 0 + + + + + 0 + + + + + + NewCell_2 + + + + + 0 + NewCell_1 + + + + + + 46 + + + + + -51 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + + + diff --git a/Build/TestData/allAttributeV7/boundr.ssae b/Build/TestData/allAttributeV7/boundr.ssae new file mode 100644 index 00000000..76be512d --- /dev/null +++ b/Build/TestData/allAttributeV7/boundr.ssae @@ -0,0 +1,415 @@ + + + + 30 + 11 + prio + 320 320 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 10 + 0 + + boundr + + + + + root + 0 + -1 + null + none + self + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + part_1 + 1 + 0 + null + circle + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_8 + 2 + 0 + normal + quad + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_9 + 3 + 0 + normal + aabb + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_10 + 4 + 0 + normal + circle_smin + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_11 + 5 + 0 + normal + circle_smax + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + + + + + + + Setup + 1 + + 60 + 1 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 0 + 0 + + + 1 + + + root + + + + 0 + + + + + + + + anime_1 + 1 + + 60 + 60 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 59 + 0 + + + 0 + + + root + + + + 0 + + + + + + part_1 + + + + 0 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + 100 + + + + + + NewCell_8 + + + + -228 + + + + + 4.33333301544189 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + 80 + + + + + 80 + + + + + + NewCell_9 + + + + -229 + + + + + 128.666656494141 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + 100 + + + + + 100 + + + + + + NewCell_10 + + + + 155.666656494141 + + + + + 145.666656494141 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + 100 + + + + + + NewCell_11 + + + + 167 + + + + + -126.33332824707 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + 100 + + + + + + + + diff --git a/Build/TestData/allAttributeV7/cell.ssae b/Build/TestData/allAttributeV7/cell.ssae new file mode 100644 index 00000000..01e790ba --- /dev/null +++ b/Build/TestData/allAttributeV7/cell.ssae @@ -0,0 +1,251 @@ + + + + 30 + 11 + prio + 320 320 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 10 + 0 + + cell + + + + + root + 0 + -1 + null + none + self + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell + 1 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_1 + 2 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + + + + + color_bar.ssce + + + + Setup + 1 + + 60 + 1 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 0 + 0 + + + 1 + + + root + + + + 0 + + + + + + + + anime_1 + 1 + + 60 + 60 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 59 + 0 + + + 0 + + + root + + + + 0 + + + + + + NewCell + + + + + 0 + NewCell + + + + + 0 + NewCell_2 + + + + + + -148.66667175293 + + + + + -7.33333349227905 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + NewCell_1 + + + + + 0 + NewCell_1 + + + + + 0 + NewCell_5 + + + + + + 159.33332824707 + + + + + -6 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + + + diff --git a/Build/TestData/allAttributeV7/color_bar.png b/Build/TestData/allAttributeV7/color_bar.png new file mode 100644 index 00000000..083018ab Binary files /dev/null and b/Build/TestData/allAttributeV7/color_bar.png differ diff --git a/Build/TestData/allAttributeV7/color_bar.ssce b/Build/TestData/allAttributeV7/color_bar.ssce new file mode 100644 index 00000000..388d7578 --- /dev/null +++ b/Build/TestData/allAttributeV7/color_bar.ssce @@ -0,0 +1,487 @@ + + + color_bar + + SpriteStudio + 0 + color_bar.png + 256 256 + 0 + clamp + linear + + + + 4096 4096 + 1 + 0 + 0 + 1 + + + + NewCell + 0 80 + 64 64 + 0 0 + 0 + + 0 + 0 + unknown + + + + + + + NewCell_1 + 64 80 + 64 64 + 0 0 + 0 + + 0 + 0 + unknown + + + + + + + NewCell_10 + 0 145 + 16 15 + 0 0 + 0 + + 0 + 0 + unknown + + + + + + + NewCell_11 + 192 80 + 48 48 + 0 0 + 0 + + 0 + 0 + unknown + + + + + + + NewCell_12 + 192 160 + 48 16 + -0.5 -0.5 + 0 + + 0 + 0 + unknown + + + + + + + NewCell_13 + 0 160 + 16 16 + 0 0 + 0 + + 0 + 0 + unknown + + + + + + + NewCell_14 + 16 160 + 16 16 + 0 0 + 0 + + 0 + 0 + unknown + + + + + + + NewCell_15 + 32 160 + 16 16 + 0 0 + 0 + + 0 + 0 + unknown + + + + + + + NewCell_16 + 48 160 + 16 16 + 0 0 + 0 + + 0 + 0 + unknown + + + + + + + NewCell_2 + 128 80 + 64 64 + 0 0 + 0 + + 0 + 0 + unknown + + + + + + + NewCell_3 + 0 0 + 64 64 + 0 0 + 0 + + 0 + 0 + unknown + + + + + + + NewCell_4 + 80 0 + 64 64 + 0 0 + 0 + + 0 + 0 + unknown + + + + + + + NewCell_5 + 160 0 + 64 64 + 0 0 + 0 + + 0 + 0 + unknown + + + + + + + NewCell_6 + 64 80 + 64 16 + -0.5 0 + 0 + + 0 + 0 + unknown + + + + + + + NewCell_7 + 128 80 + 64 16 + -0.5 0 + 0 + + 0 + 0 + unknown + + + + + + + NewCell_8 + 0 176 + 80 80 + 0 0 + 0 + + 0 + 0 + unknown + + + + + + + NewCell_9 + 96 176 + 64 64 + 0 0 + 0 + + 0 + 0 + unknown + + + + + + + NewCell_17 + 96 176 + 64 64 + 0 0 + 0 + + 0 + 1 + polyline + + 4 59 + 15 59 + 32 48 + 48 54 + 59 48 + 59 59 + 21 37 + 32 21 + 16 10 + 5 15 + 5 4 + 54 15 + 49 4 + 59 4 + 26 57 + 22 48 + 28 35 + 41 39 + 52 33 + 37 55 + 50 22 + 45 13 + 38 8 + 27 10 + 23 22 + 14 20 + 8 28 + 6 39 + 11 48 + 49 47 + 17 29 + 34 31 + 41 27 + 50 40 + 58 38 + 60 23 + + + -1 -1 + -1 15 + -1 32 + -1 48 + -1 65 + 15 65 + 32 65 + 48 65 + 65 65 + 65 49 + 65 32 + 65 16 + 65 -1 + 49 -1 + 33 -1 + 17 -1 + + + -1 65 + 4 59 + 15 65 + -1 48 + 11 48 + 15 59 + 26 57 + 32 65 + 37 55 + 48 65 + 48 54 + 49 47 + 59 48 + 59 59 + 65 65 + 65 49 + 58 38 + 65 32 + 52 33 + 50 40 + 41 39 + 32 48 + 22 48 + 21 37 + 6 39 + -1 32 + 8 28 + 17 29 + 28 35 + 34 31 + 41 27 + 32 21 + 23 22 + 27 10 + 38 8 + 45 13 + 50 22 + 60 23 + 65 16 + 54 15 + 49 4 + 49 -1 + 59 4 + 65 -1 + 33 -1 + 17 -1 + 16 10 + 14 20 + 5 15 + -1 15 + 5 4 + -1 -1 + + + 0 1 2 + 0 3 1 + 1 3 4 + 1 4 5 + 1 5 2 + 2 5 6 + 2 6 7 + 7 6 8 + 7 8 9 + 8 10 9 + 10 8 11 + 10 11 12 + 13 10 12 + 9 10 13 + 9 13 14 + 13 15 14 + 13 12 15 + 15 12 16 + 15 16 17 + 16 18 17 + 19 18 16 + 19 20 18 + 11 20 19 + 20 11 8 + 8 21 20 + 6 21 8 + 6 22 21 + 5 22 6 + 5 4 22 + 4 23 22 + 4 24 23 + 3 24 4 + 3 25 24 + 24 25 26 + 24 26 27 + 24 27 23 + 23 27 28 + 22 23 28 + 22 28 21 + 20 21 28 + 20 28 29 + 29 30 20 + 29 31 30 + 32 31 29 + 31 32 33 + 31 33 34 + 31 34 35 + 30 31 35 + 36 30 35 + 30 36 18 + 20 30 18 + 18 36 37 + 18 37 17 + 37 38 17 + 37 39 38 + 36 39 37 + 36 35 39 + 35 40 39 + 35 34 40 + 40 34 41 + 42 40 41 + 39 40 42 + 39 42 38 + 42 43 38 + 43 42 41 + 34 44 41 + 34 33 44 + 44 33 45 + 33 46 45 + 46 33 32 + 32 47 46 + 27 47 32 + 26 47 27 + 26 48 47 + 26 49 48 + 26 25 49 + 48 49 50 + 46 48 50 + 47 48 46 + 46 50 45 + 50 51 45 + 49 51 50 + 27 32 28 + 28 32 29 + 11 19 12 + 19 16 12 + + + + diff --git a/Build/TestData/allAttributeV7/deform.ssae b/Build/TestData/allAttributeV7/deform.ssae new file mode 100644 index 00000000..53fbff82 --- /dev/null +++ b/Build/TestData/allAttributeV7/deform.ssae @@ -0,0 +1,318 @@ + + + + 30 + 11 + prio + 320 320 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 10 + + + + 1 + 0 0 + 0 0 + 0 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + 0 + + deform + + + + + root + 0 + -1 + null + none + self + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + joint_1 + 1 + 0 + joint + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_17 + 2 + 1 + mesh + none + parent + 0 + 3 + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + + + + + + + color_bar.ssce + + + + Setup + 1 + + 60 + 1 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + 0 + + + 1 + + + root + + + + 0 + + + + + + joint_1 + + + + -2.33333325386047 + + + + + -1.33333337306976 + + + + + 0 + + + + + 3 + + + + + 3 + + + + + 0 + + + + + 0 + + + + + + NewCell_17 + + + + + 0 + NewCell_17 + + + + + + 0 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + + + anime_1 + 1 + + 60 + 60 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 59 + + + + 1 + 0 0 + 0 0 + 0 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + 0 + + + 0 + + + root + + + + 0 + + + + + + NewCell_17 + + + + + 52 + 0 + + + + + 52 + 7 0 -23.33 -15.00 7 0.00 -17.33 14 21.33 -24.00 17 24.00 -1.67 25 -29.33 2.00 43 15.33 16.67 51 -17.33 15.33 + + + + + 52 + 28 0 -23.33 -15.00 6 0.00 -5.67 7 0.00 -17.33 8 0.67 -10.67 10 5.00 -4.67 12 2.67 -6.67 13 8.33 -7.67 14 21.33 -24.00 16 9.00 -1.33 17 24.00 -1.67 18 15.33 -0.33 19 5.33 -3.33 20 3.00 -5.33 21 0.00 -5.67 23 -6.33 -2.00 24 -9.33 0.33 25 -29.33 2.00 30 5.33 0.00 31 3.00 5.33 32 -1.33 3.33 33 3.67 9.33 34 1.33 4.33 37 7.00 -2.00 42 7.33 4.67 43 15.33 16.67 46 -4.67 5.67 47 -5.00 -0.67 51 -17.33 15.33 + + + + + + + + + diff --git a/Build/TestData/allAttributeV7/deform_bone.ssae b/Build/TestData/allAttributeV7/deform_bone.ssae new file mode 100644 index 00000000..251a22e7 --- /dev/null +++ b/Build/TestData/allAttributeV7/deform_bone.ssae @@ -0,0 +1,428 @@ + + + + 30 + 11 + prio + 320 320 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 10 + + + + 1 + 0 0 + 0 0 + 0 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + 0 + + deform_bone + + + + + root + 0 + -1 + null + none + self + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + joint_1 + 1 + 0 + joint + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + bone_1 + 2 + 1 + armature + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + FFFF0000 + + 17 + 0 0 + 90 + 1 + + + bone_2 + 3 + 2 + armature + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + FFFF007F + + 19 + 17 0 + 0 + 1 + + + NewCell_17 + 4 + 1 + mesh + none + parent + 0 + 3 + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + + 0 + 1 + + + 2 0 73 -33.00 33.00 1 27 -50.00 33.00,2 0 76 -27.00 28.00 1 24 -44.00 28.00,2 0 78 -33.00 17.00 1 22 -50.00 17.00,2 0 75 -16.00 33.00 1 25 -33.00 33.00,2 0 82 -16.00 21.00 1 18 -33.00 21.00,2 0 81 -27.00 17.00 1 19 -44.00 17.00,2 0 84 -25.00 6.00 1 16 -42.00 6.00,2 0 81 -33.00 0.00 1 19 -50.00 0.00,2 0 86 -23.00 -5.00 1 14 -40.00 -5.00,2 0 79 -33.00 -16.00 1 21 -50.00 -16.00,2 0 83 -22.00 -16.00 1 17 -39.00 -16.00,2 0 85 -15.00 -17.00 1 15 -32.00 -17.00,2 0 78 -16.00 -27.00 1 22 -33.00 -27.00,2 0 77 -27.00 -27.00 1 23 -44.00 -27.00,2 0 73 -33.00 -33.00 1 27 -50.00 -33.00,2 0 75 -17.00 -33.00 1 25 -34.00 -33.00,2 0 79 -6.00 -26.00 1 21 -23.00 -26.00,2 0 70 0.00 -33.00 1 30 -17.00 -33.00,2 0 85 -1.00 -20.00 1 15 -18.00 -20.00,2 0 87 -8.00 -18.00 1 13 -25.00 -18.00,2 0 93 -7.00 -9.00 1 7 -24.00 -9.00,2 0 90 -16.00 0.00 1 10 -33.00 0.00,2 0 88 -16.00 10.00 1 12 -33.00 10.00,2 0 93 -5.00 11.00 1 7 -22.00 11.00,2 0 79 -7.00 26.00 1 21 -24.00 26.00,2 0 70 0.00 33.00 1 30 -17.00 33.00,2 0 77 4.00 24.00 1 23 -13.00 24.00,2 0 90 3.00 15.00 1 10 -14.00 15.00,2 0 97 -3.00 4.00 1 3 -20.00 4.00,2 0 99 1.00 -2.00 1 1 -16.00 -2.00,2 0 97 5.00 -9.00 1 3 -12.00 -9.00,1 0 100 11.00 0.00,2 0 95 10.00 9.00 1 5 -7.00 9.00,2 0 5 22.00 5.00 1 95 5.00 5.00,2 0 2 24.00 -6.00 1 98 7.00 -6.00,2 0 39 19.00 -13.00 1 61 2.00 -13.00,2 0 77 10.00 -18.00 1 23 -7.00 -18.00,2 0 66 9.00 -28.00 1 34 -8.00 -28.00,2 0 52 16.00 -33.00 1 48 -1.00 -33.00,2 0 52 17.00 -22.00 1 48 0.00 -22.00,2 0 16 28.00 -17.00 1 84 11.00 -17.00,2 0 12 33.00 -17.00 1 88 16.00 -17.00,2 0 30 28.00 -27.00 1 70 11.00 -27.00,2 0 31 33.00 -33.00 1 69 16.00 -33.00,2 0 1 33.00 -1.00 1 99 16.00 -1.00,2 0 9 33.00 15.00 1 91 16.00 15.00,2 0 28 22.00 16.00 1 72 5.00 16.00,2 0 72 12.00 18.00 1 28 -5.00 18.00,2 0 51 17.00 27.00 1 49 0.00 27.00,2 0 51 17.00 33.00 1 49 0.00 33.00,2 0 30 28.00 27.00 1 70 11.00 27.00,2 0 31 33.00 33.00 1 69 16.00 33.00, + + + + color_bar.ssce + + + + Setup + 1 + + 60 + 1 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + 0 + + + 1 + + + root + + + + 0 + + + + + + joint_1 + + + + -2.33333325386047 + + + + + -1.33333337306976 + + + + + 0 + + + + + 3 + + + + + 3 + + + + + 0 + + + + + 0 + + + + + + bone_1 + + + + 0 + + + + + 0 + + + + + + bone_2 + + + + 0 + + + + + 0 + + + + + + NewCell_17 + + + + + 0 + NewCell_17 + + + + + + 0 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + + + anime_1 + 1 + + 60 + 60 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 59 + + + + 1 + 0 0 + 0 0 + 0 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + 0 + + + 0 + + + root + + + + 0 + + + + + + bone_1 + + + + 0 + + + + + + bone_2 + + + + 0 + + + -67.7722549438477 + + + + + + NewCell_17 + + + + + 52 + 0 + + + + + 52 + 6 0 -23.33 -15.00 14 21.33 -24.00 17 24.00 -1.67 25 -29.33 2.00 43 15.33 16.67 51 -17.33 15.33 + + + + + 52 + 25 0 -23.33 -15.00 8 0.67 -10.67 10 5.00 -4.67 12 2.67 -6.67 13 8.33 -7.67 14 21.33 -24.00 16 9.00 -1.33 17 24.00 -1.67 18 15.33 -0.33 19 5.33 -3.33 20 3.00 -5.33 23 -6.33 -2.00 24 -9.33 0.33 25 -29.33 2.00 30 5.33 0.00 31 3.00 5.33 32 -1.33 3.33 33 3.67 9.33 34 1.33 4.33 37 7.00 -2.00 42 7.33 4.67 43 15.33 16.67 46 -4.67 5.67 47 -5.00 -0.67 51 -17.33 15.33 + + + + + + + + + diff --git a/Build/TestData/allAttributeV7/easing.ssae b/Build/TestData/allAttributeV7/easing.ssae new file mode 100644 index 00000000..2bd9280e --- /dev/null +++ b/Build/TestData/allAttributeV7/easing.ssae @@ -0,0 +1,1555 @@ + + + + 30 + 11 + prio + 320 320 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 10 + + + + 1 + 0 0 + 0 0 + 0 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + 0 + + easing + + + + + root + 0 + -1 + null + none + self + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + 1 + + + 説明 + 1 + 0 + text + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + "補間"方法から選択します。 + 0 + Arial + + 16 + 0 + 1 + 0 + 0 + 0 + 558 + 1 + 0 + 0 + 1 + + 1 + 1 + + + parent + 2 + 0 + null + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + 1 + + + イーズイン + 3 + 2 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + 1 + + + イーズアウト + 4 + 2 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + 1 + + + イーズインアウト + 5 + 2 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + 1 + + + 指数関数的イン + 6 + 2 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + 1 + + + 指数関数的アウト + 7 + 2 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + 1 + + + 指数関数的インアウト + 8 + 2 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + 1 + + + 正弦イン + 9 + 2 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + 1 + + + 正弦アウト + 10 + 2 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + 1 + + + 正弦インアウト + 11 + 2 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + 1 + + + 弾性イン + 12 + 2 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + 1 + + + 弾性アウト + 13 + 2 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + 1 + + + 弾性インアウト + 14 + 2 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + 1 + + + バウンスイン + 15 + 2 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + 1 + + + バウンスアウト + 16 + 2 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + 1 + + + バウンスインアウト + 17 + 2 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + 1 + + + イーズバックイン + 18 + 2 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + 1 + + + イーズバックアウト + 19 + 2 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + 1 + + + イーズバックインアウト + 20 + 2 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + 1 + + + + + + + color_bar.ssce + + + + Setup + 1 + + 30 + 1 + prio + 540 960 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + 0 + + + + 1 + + + root + + + + 0 + + + + + + + + anime_1 + 1 + + 30 + 61 + prio + 540 960 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 60 + + + + 1 + 0 0 + 0 0 + 0 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + 0 + + + + 0 + + + root + + + + 0 + + + + + + 説明 + + + + 0 + + + + + 352 + + + + + 0 + + + + + 0 + + + + + + parent + + + + 0 + + + + + 288 + + + + + 0 + + + + + 0 + + + + + + イーズイン + + + + + 0 + NewCell_9 + + + + + + -100 + + + 100 + + + + + 0 + + + + + 0 + + + + + 0.5 + + + + + 0.5 + + + + + 0 + + + 0 + + + + + + イーズアウト + + + + + 0 + NewCell_9 + + + + + + -100 + + + 100 + + + + + -32 + + + + + 0 + + + + + 0.5 + + + + + 0.5 + + + + + 0 + + + + + + イーズインアウト + + + + + 0 + NewCell_9 + + + + + + -100 + + + 100 + + + + + -64 + + + + + 0 + + + + + 0.5 + + + + + 0.5 + + + + + 0 + + + + + + 指数関数的イン + + + + + 0 + NewCell_9 + + + + + + -100 + + + 100 + + + + + -96 + + + + + 0 + + + + + 0.5 + + + + + 0.5 + + + + + 0 + + + + + + 指数関数的アウト + + + + + 0 + NewCell_9 + + + + + + -100 + + + 100 + + + + + -128 + + + + + 0 + + + + + 0.5 + + + + + 0.5 + + + + + 0 + + + 0 + + + + + + 指数関数的インアウト + + + + + 0 + NewCell_9 + + + + + + -100 + + + 100 + + + + + -160 + + + + + 0 + + + + + 0.5 + + + + + 0.5 + + + + + 0 + + + 0 + + + + + + 正弦イン + + + + + 0 + NewCell_9 + + + + + + -100 + + + 100 + + + + + -192 + + + + + 0 + + + + + 0.5 + + + + + 0.5 + + + + + 0 + + + 0 + + + + + + 正弦アウト + + + + + 0 + NewCell_9 + + + + + + -100 + + + 100 + + + + + -224 + + + + + 0 + + + + + 0.5 + + + + + 0.5 + + + + + 0 + + + 0 + + + + + + 正弦インアウト + + + + + 0 + NewCell_9 + + + + + + -100 + + + 100 + + + + + -256 + + + + + 0 + + + + + 0.5 + + + + + 0.5 + + + + + 0 + + + 0 + + + + + + 弾性イン + + + + + 0 + NewCell_9 + + + + + + -100 + + + 100 + + + + + -288 + + + + + 0 + + + + + 0.5 + + + + + 0.5 + + + + + 0 + + + + + + 弾性アウト + + + + + 0 + NewCell_9 + + + + + + -100 + + + 100 + + + + + -320 + + + + + 0 + + + + + 0.5 + + + + + 0.5 + + + + + 0 + + + + + + 弾性インアウト + + + + + 0 + NewCell_9 + + + + + + -100 + + + 100 + + + + + -352 + + + + + 0 + + + + + 0.5 + + + + + 0.5 + + + + + 0 + + + + + + バウンスイン + + + + + 0 + NewCell_9 + + + + + + -100 + + + 100 + + + + + -384 + + + + + 0 + + + + + 0.5 + + + + + 0.5 + + + + + 0 + + + + + + バウンスアウト + + + + + 0 + NewCell_9 + + + + + + -100 + + + 100 + + + + + -416 + + + + + 0 + + + + + 0.5 + + + + + 0.5 + + + + + 0 + + + + + + バウンスインアウト + + + + + 0 + NewCell_9 + + + + + + -100 + + + 100 + + + + + -448 + + + + + 0 + + + + + 0.5 + + + + + 0.5 + + + + + 0 + + + + + + イーズバックイン + + + + + 0 + NewCell_9 + + + + + + -100 + + + 100 + + + + + -480 + + + + + 0 + + + + + 0.5 + + + + + 0.5 + + + + + 0 + + + + + + イーズバックアウト + + + + + 0 + NewCell_9 + + + + + + -100 + + + 100 + + + + + -512 + + + + + 0 + + + + + 0.5 + + + + + 0.5 + + + + + 0 + + + + + + イーズバックインアウト + + + + + 0 + NewCell_9 + + + + + + -100 + + + 100 + + + + + -544 + + + + + 0 + + + + + 0.5 + + + + + 0.5 + + + + + 0 + + + + + + + + diff --git a/Build/TestData/allAttributeV7/effect.ssae b/Build/TestData/allAttributeV7/effect.ssae new file mode 100644 index 00000000..956381c5 --- /dev/null +++ b/Build/TestData/allAttributeV7/effect.ssae @@ -0,0 +1,368 @@ + + + + 30 + 11 + prio + 320 320 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 10 + 0 + + effect + + + + + root + 0 + -1 + null + none + self + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + effect_1 + 1 + 0 + effect + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + NewEffect + mix + 1 + 0 + 0 + 1 + + 1 + + + effect_2 + 2 + 0 + effect + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + NewEffect + mix + 1 + 0 + 0 + 1 + + 1 + + + effect_3 + 3 + 0 + effect + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + NewEffect + mix + 1 + 0 + 0 + 1 + + 1 + + + effect_4 + 4 + 0 + effect + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + NewEffect + mix + 1 + 0 + 0 + 1 + + 1 + + + + + + + + + Setup + 1 + + 60 + 1 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 0 + 0 + + + 1 + + + root + + + + 0 + + + + + + + + anime_1 + 1 + + 60 + 60 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 59 + 0 + + + 0 + + + root + + + + -372 + + + + + -5 + + + + + 0 + + + + + + effect_1 + + + + 0 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + effect_2 + + + + 192 + + + + + 2 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + 0 + 2 + 0 + + + + + + + effect_3 + + + + 358 + + + + + 5 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + 30 + 1 + 0 + + + + + + + effect_4 + + + + 632 + + + + + -6 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + 0 + 1 + 1 + + + + + + + + + diff --git a/Build/TestData/allAttributeV7/hide.ssae b/Build/TestData/allAttributeV7/hide.ssae new file mode 100644 index 00000000..d8558283 --- /dev/null +++ b/Build/TestData/allAttributeV7/hide.ssae @@ -0,0 +1,423 @@ + + + + 30 + 11 + prio + 320 320 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 10 + 0 + + hide + + + + + root + 0 + -1 + null + none + self + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell + 1 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_1 + 2 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_2 + 3 + 2 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_3 + 4 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_4 + 5 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + + + + + color_bar.ssce + + + + Setup + 1 + + 60 + 1 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 0 + 0 + + + 1 + + + root + + + + 0 + + + + + + + + anime_1 + 1 + + 60 + 60 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 59 + 0 + + + 0 + + + root + + + + 0 + + + + + + NewCell + + + + + 0 + NewCell + + + + + + -96 + + + + + 0.5 + + + + + 0 + + + + + 0 + + + + + 1 + + + 0 + + + + + + NewCell_1 + + + + + 0 + NewCell_1 + + + + + + 95 + + + + + -1.5 + + + + + 0 + + + + + 0 + + + + + 0 + + + 1 + + + + + + NewCell_2 + + + + + 0 + NewCell_1 + + + + + + 43 + + + + + -45 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + NewCell_3 + + + + + 0 + NewCell_2 + + + + + + -74 + + + + + 139.5 + + + + + 0 + + + + + 0 + + + + + + NewCell_4 + + + + + 0 + NewCell_2 + + + + + + 120 + + + + + 140 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + + + diff --git a/Build/TestData/allAttributeV7/imgflip.ssae b/Build/TestData/allAttributeV7/imgflip.ssae new file mode 100644 index 00000000..8a4e4804 --- /dev/null +++ b/Build/TestData/allAttributeV7/imgflip.ssae @@ -0,0 +1,391 @@ + + + + 30 + 11 + prio + 320 320 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 10 + 0 + + imgflip + + + + + root + 0 + -1 + null + none + self + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_9 + 1 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_10 + 2 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_11 + 3 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_12 + 4 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + + + + + color_bar.ssce + + + + Setup + 1 + + 60 + 1 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 0 + 0 + + + 1 + + + root + + + + 0 + + + + + + + + anime_1 + 1 + + 60 + 60 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 59 + 0 + + + 0 + + + root + + + + 0 + + + + + + NewCell_9 + + + + + 0 + NewCell_9 + + + + + + -72.6666564941406 + + + + + 77.3333358764648 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + NewCell_10 + + + + + 0 + NewCell_9 + + + + + + 72 + + + + + 74 + + + + + 0 + + + + + 0 + + + + + 1 + + + + + 0 + + + + + + NewCell_11 + + + + + 0 + NewCell_9 + + + + + + -72 + + + + + -63.3333358764648 + + + + + 0 + + + + + 0 + + + + + 1 + + + + + 0 + + + + + + NewCell_12 + + + + + 0 + NewCell_9 + + + + + + 67.3333435058594 + + + + + -64.6666641235352 + + + + + 0 + + + + + 0 + + + + + 1 + + + + + 1 + + + + + 0 + + + + + + + + diff --git a/Build/TestData/allAttributeV7/instance.ssae b/Build/TestData/allAttributeV7/instance.ssae new file mode 100644 index 00000000..dac1da50 --- /dev/null +++ b/Build/TestData/allAttributeV7/instance.ssae @@ -0,0 +1,525 @@ + + + + 30 + 11 + prio + 320 320 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 10 + 0 + + instance + + + + + root + 0 + -1 + null + none + self + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + alpha_anime_1 + 1 + 0 + instance + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + alpha + anime_1 + mix + 1 + 0 + 0 + 1 + + 1 + + + alpha_anime_2 + 2 + 0 + instance + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + alpha + anime_1 + mix + 1 + 0 + 0 + 1 + + 1 + + + alpha_anime_3 + 3 + 0 + instance + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + alpha + anime_1 + mix + 1 + 0 + 0 + 1 + + 1 + + + alpha_anime_5 + 4 + 0 + instance + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + alpha + anime_1 + mix + 1 + 0 + 0 + 1 + + 1 + + + alpha_anime_6 + 5 + 0 + instance + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + alpha + anime_1 + mix + 1 + 0 + 0 + 1 + + 1 + + + alpha_anime_4 + 6 + 0 + instance + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + alpha + anime_1 + mix + 1 + 0 + 0 + 1 + + 1 + + + + + + + + + Setup + 1 + + 60 + 1 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 0 + 0 + + + 1 + + + root + + + + 0 + + + + + + + + anime_1 + 1 + + 60 + 60 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 59 + 0 + + + 0 + + + root + + + + 0 + + + + + + alpha_anime_1 + + + + -353.333343505859 + + + + + 233.66667175293 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + alpha_anime_2 + + + + 255 + + + + + 247.66667175293 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + 1 + _start + 0 + _end + 0 + 0.5 + + + + + + + alpha_anime_3 + + + + -340 + + + + + 28.6666717529297 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + 1 + _start + 30 + _end + 0 + 1 + + + + + + + alpha_anime_5 + + + + -335.333343505859 + + + + + -189.33332824707 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + 1 + _start + 0 + _end + 0 + 2 + + + + + 1 + _start + 0 + _end + 0 + 2 + + + + + + + alpha_anime_6 + + + + 291.666656494141 + + + + + -211 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + 1 + _start + 30 + _end + 0 + 1 + + + + + 1 + _start + 30 + _end + 0 + 1 + + + + + + + alpha_anime_4 + + + + 255.333312988281 + + + + + 26 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + 1 + _start + 0 + _end + -30 + 1 + + + + + + + + + diff --git a/Build/TestData/allAttributeV7/instance_flag.ssae b/Build/TestData/allAttributeV7/instance_flag.ssae new file mode 100644 index 00000000..31e21477 --- /dev/null +++ b/Build/TestData/allAttributeV7/instance_flag.ssae @@ -0,0 +1,454 @@ + + + + 30 + 11 + prio + 320 320 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 10 + 0 + + instance_flag + + + + + root + 0 + -1 + null + none + self + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + alpha_anime_1 + 1 + 0 + instance + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + alpha + anime_1 + mix + 1 + 0 + 0 + 1 + + 1 + + + alpha_anime_2 + 2 + 0 + instance + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + alpha + anime_1 + mix + 1 + 0 + 0 + 1 + + 1 + + + alpha_anime_3 + 3 + 0 + instance + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + alpha + anime_1 + mix + 1 + 0 + 0 + 1 + + 1 + + + alpha_anime_4 + 4 + 0 + instance + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + alpha + anime_1 + mix + 1 + 0 + 0 + 1 + + 1 + + + alpha_anime_5 + 5 + 0 + instance + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + alpha + anime_1 + mix + 1 + 0 + 0 + 1 + + 1 + + + + + + + + + Setup + 1 + + 60 + 1 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 0 + 0 + + + 1 + + + root + + + + 0 + + + + + + + + anime_1 + 1 + + 60 + 300 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 299 + 0 + + + 0 + + + root + + + + 0 + + + + + + alpha_anime_1 + + + + -375.666656494141 + + + + + 260.666687011719 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + 1 + 1 + _start + 0 + _end + 0 + 1 + + + + + + + alpha_anime_2 + + + + 249.333343505859 + + + + + 225.33332824707 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + 3 + _start + 0 + _end + 0 + 1 + + + + + + + alpha_anime_3 + + + + -348.666656494141 + + + + + 0.666664123535156 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + 1 + 1 + _start + 0 + _end + 0 + 1 + + + + + + + alpha_anime_4 + + + + 280 + + + + + 6.33333206176758 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + 1 + 1 + _start + 0 + _end + 0 + 1 + + + + + + + alpha_anime_5 + + + + -272 + + + + + -206 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + 1 + 1 + _start + 0 + _end + 0 + 1 + + + + + + + + + diff --git a/Build/TestData/allAttributeV7/iptype.ssae b/Build/TestData/allAttributeV7/iptype.ssae new file mode 100644 index 00000000..94e38713 --- /dev/null +++ b/Build/TestData/allAttributeV7/iptype.ssae @@ -0,0 +1,509 @@ + + + + 30 + 11 + prio + 320 320 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 10 + 0 + + iptype + + + + + root + 0 + -1 + null + none + self + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell + 1 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_1 + 2 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_2 + 3 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_3 + 4 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_4 + 5 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_5 + 6 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + + + + + color_bar.ssce + + + + Setup + 1 + + 60 + 1 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 0 + 0 + + + 1 + + + root + + + + 0 + + + + + + + + anime_1 + 1 + + 60 + 60 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 59 + 0 + + + 0 + + + root + + + + 0 + + + + + + NewCell + + + + + 0 + NewCell + + + + + + -283.5 + + + 275.5 + + + + + 152.5 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + NewCell_1 + + + + + 0 + NewCell + + + + + 0 + NewCell + + + + + + -283.5 + + + 275.5 + + + + + 68.5 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + NewCell_2 + + + + + 0 + NewCell + + + + + + 0 0 -1 0 + -283.5 + + + 275.5 + + + + + -18.5 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + NewCell_3 + + + + + 0 + NewCell + + + + + + 26.8817195892334 16.2526321411133 -29.0645160675049 -6.09473705291748 + -283.5 + + + 275.5 + + + + + -106.5 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + NewCell_4 + + + + + 0 + NewCell + + + + + + -283.5 + + + 275.5 + + + + + -194.5 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + NewCell_5 + + + + + 0 + NewCell + + + + + + -283.5 + + + 275.5 + + + + + -286.5 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + + + diff --git a/Build/TestData/allAttributeV7/loalpha.ssae b/Build/TestData/allAttributeV7/loalpha.ssae new file mode 100644 index 00000000..3fe93fb1 --- /dev/null +++ b/Build/TestData/allAttributeV7/loalpha.ssae @@ -0,0 +1,502 @@ + + + + 30 + 11 + prio + 320 320 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 10 + + + + 1 + 0 0 + 0 0 + 0 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + 0 + + loalpha + + + + + root + 0 + -1 + null + none + self + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_3 + 1 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_4 + 2 + 1 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell + 3 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_1 + 4 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_2 + 5 + 4 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + + + + + color_bar.ssce + + + + Setup + 1 + + 60 + 1 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + 0 + + + 1 + + + root + + + + 0 + + + + + + + + anime_1 + 1 + + 60 + 60 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 59 + + + + 1 + 0 0 + 0 0 + 0 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + 0 + + + 0 + + + root + + + + 0 + + + + + + NewCell_3 + + + + + 0 + NewCell_2 + + + + + + -111.333335876465 + + + + + -114 + + + + + 0 + + + + + 1 + + + 0 + + + + + 1 + + + 0.5 + + + + + 0 + + + + + 0 + + + + + + NewCell_4 + + + + + 0 + NewCell_2 + + + + + + 42 + + + + + -42 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + NewCell + + + + + 0 + NewCell + + + + + + -116 + + + + + 2.5 + + + + + 0 + + + + + 1 + + + 0 + + + + + 0 + + + + + 0 + + + + + + NewCell_1 + + + + + 0 + NewCell_1 + + + + + + 102 + + + + + 0.5 + + + + + 0 + + + + + 1 + + + 0 + + + + + 0 + + + + + 0 + + + + + + NewCell_2 + + + + + 0 + NewCell_1 + + + + + + 45 + + + + + -49 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + + + diff --git a/Build/TestData/allAttributeV7/loscl.ssae b/Build/TestData/allAttributeV7/loscl.ssae new file mode 100644 index 00000000..972bb897 --- /dev/null +++ b/Build/TestData/allAttributeV7/loscl.ssae @@ -0,0 +1,523 @@ + + + + 30 + 11 + prio + 320 320 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 10 + + + + 1 + 0 0 + 0 0 + 0 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + 0 + + loscl + + + + + root + 0 + -1 + null + none + self + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_4 + 1 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell + 2 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_2 + 3 + 2 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_1 + 4 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_3 + 5 + 4 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + + + + + color_bar.ssce + + + + Setup + 1 + + 60 + 1 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + 0 + + + 1 + + + root + + + + 0 + + + + + + + + anime_1 + 1 + + 60 + 60 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 59 + + + + 1 + 0 0 + 0 0 + 0 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + 0 + + + 0 + + + root + + + + 0 + + + + + + NewCell_4 + + + + + 0 + NewCell_2 + + + + + + -107 + + + + + -178.5 + + + + + 0 + + + + + 2 + + + 2 + + + + + 2 + + + 2 + + + + + 1 + + + 0.5 + + + + + 1 + + + 0.5 + + + + + 0 + + + + + 0 + + + + + + NewCell + + + + + 0 + NewCell + + + + + + -119 + + + + + -0.5 + + + + + 0 + + + + + 1 + + + 3 + + + + + 1 + + + + + 0 + + + + + 0 + + + + + + NewCell_2 + + + + + 0 + NewCell + + + + + + 48 + + + + + -51 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + NewCell_1 + + + + + 0 + NewCell_1 + + + + + + 109 + + + + + -5.5 + + + + + 0 + + + + + 1 + + + 3 + + + + + 0 + + + + + 0 + + + + + + NewCell_3 + + + + + 0 + NewCell_1 + + + + + + 43 + + + + + -55 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + + + diff --git a/Build/TestData/allAttributeV7/mask.ssae b/Build/TestData/allAttributeV7/mask.ssae new file mode 100644 index 00000000..34bc8656 --- /dev/null +++ b/Build/TestData/allAttributeV7/mask.ssae @@ -0,0 +1,397 @@ + + + + 30 + 11 + prio + 320 320 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 10 + 0 + + mask + + + + + root + 0 + -1 + null + none + self + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_1 + 1 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell + 2 + 0 + mask + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_2 + 3 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 0 + + + NewCell_3 + 4 + 0 + mask + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + + + + + color_bar.ssce + + + + Setup + 1 + + 60 + 1 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 0 + 0 + + + 1 + + + root + + + + 0 + + + + + + + + anime_1 + 1 + + 60 + 60 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 59 + 0 + + + 0 + + + root + + + + 0 + + + + + + NewCell_1 + + + + + 0 + NewCell_1 + + + + + + -98 + + + + + -4 + + + + + 0 + + + + + 1.89583325386047 + + + + + 1.89583325386047 + + + + + 0 + + + + + 0 + + + + + + NewCell + + + + + 0 + NewCell + + + + + + -48 + + + + + -3 + + + + + 0 + + + + + 2.0625 + + + + + 2.0625 + + + + + 0 + + + + + 0 + + + + + 0 + + + 255 + + + + + + NewCell_2 + + + + + 0 + NewCell_1 + + + + + + -128.66667175293 + + + + + -166 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + NewCell_3 + + + + + 0 + NewCell + + + + + + -96.6666717529297 + + + + + -165.66667175293 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + 0 + + + 255 + + + + + + + + diff --git a/Build/TestData/allAttributeV7/partsColor.ssae b/Build/TestData/allAttributeV7/partsColor.ssae new file mode 100644 index 00000000..b56340f6 --- /dev/null +++ b/Build/TestData/allAttributeV7/partsColor.ssae @@ -0,0 +1,1749 @@ + + + + 30 + 11 + prio + 320 320 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 10 + + + + 1 + 0 0 + 0 0 + 0 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + 0 + + partsColor + + + + + root + 0 + -1 + null + none + self + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_9 + 1 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_10 + 2 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_11 + 3 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_12 + 4 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_13 + 5 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_14 + 6 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_15 + 7 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_23 + 8 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_16 + 9 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_24 + 10 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_17 + 11 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_18 + 12 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_19 + 13 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_20 + 14 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_21 + 15 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_22 + 16 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + + + + + color_bar.ssce + + + + Setup + 1 + + 60 + 1 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + 0 + + + 1 + + + root + + + + 0 + + + + + + + + anime_1 + 1 + + 60 + 60 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 59 + + + + 1 + 0 0 + 0 0 + 0 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + 0 + + + 0 + + + root + + + + 0 + + + + + + NewCell_9 + + + + + 0 + NewCell_9 + + + + + + -235 + + + + + 0.5 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + whole + mix + + FFFF1313 + 1 + + + + + + whole + mix + + FFFF1313 + 0 + + + + + + + + NewCell_10 + + + + + 0 + NewCell_9 + + + + + + -101 + + + + + -0.5 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + whole + mul + + FFF30000 + 1 + + + + + + whole + mul + + 00F30000 + 1 + + + + + + + + NewCell_11 + + + + + 0 + NewCell_9 + + + + + + 25 + + + + + -3.5 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + whole + add + + FFF60000 + 1 + + + + + + whole + add + + 00F60000 + 1 + + + + + + + + NewCell_12 + + + + + 0 + NewCell_9 + + + + + + 167 + + + + + -7.5 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + whole + sub + + FFFF1B1B + 1 + + + + + + whole + sub + + 00FF1B1B + 1 + + + + + + + + NewCell_13 + + + + + 0 + NewCell_9 + + + + + + -239 + + + + + -122.5 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + vertex + mix + + FFF10000 + 1 + + + FF00FB0F + 1 + + + FF1600F3 + 1 + + + FF808080 + 1 + + + + + + vertex + mix + + 00F10000 + 1 + + + 0000FB0F + 1 + + + 001600F3 + 1 + + + 00808080 + 1 + + + + + + + + NewCell_14 + + + + + 0 + NewCell_9 + + + + + + -104 + + + + + -122.5 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + vertex + mul + + FFF60000 + 1 + + + FF23FF04 + 1 + + + FF1600E9 + 1 + + + FF808080 + 1 + + + + + + vertex + mul + + 00F60000 + 1 + + + 0023FF04 + 1 + + + 001600E9 + 1 + + + 00808080 + 1 + + + + + + + + NewCell_15 + + + + + 0 + NewCell_9 + + + + + + 29 + + + + + -124.5 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + vertex + add + + FFF90000 + 1 + + + FF00FE08 + 1 + + + FF0D00CF + 1 + + + FF808080 + 1 + + + + + + vertex + add + + 00F90000 + 1 + + + 0000FE08 + 1 + + + 000D00CF + 1 + + + 00808080 + 1 + + + + + + + + NewCell_23 + + + + + 0 + NewCell_9 + + + + + + 34 + + + + + -238.5 + + + + + 0 + + + + + 1 + + + 0 + + + + + 0 + + + + + 0 + + + + + + vertex + add + + FFF90000 + 1 + + + FF00FE08 + 1 + + + FF0D00CF + 1 + + + FF808080 + 1 + + + + + + vertex + add + + 00F90000 + 1 + + + 0000FE08 + 1 + + + 000D00CF + 1 + + + 00808080 + 1 + + + + + + + + NewCell_16 + + + + + 0 + NewCell_9 + + + + + + 163 + + + + + -126.5 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + vertex + sub + + FFEE0000 + 1 + + + FF00EE07 + 1 + + + FF1D00E9 + 1 + + + FF808080 + 1 + + + + + + vertex + sub + + 00EE0000 + 1 + + + 0000EE07 + 1 + + + 001D00E9 + 1 + + + 00808080 + 1 + + + + + + + + NewCell_24 + + + + + 0 + NewCell_9 + + + + + + 167 + + + + + -237.5 + + + + + 0 + + + + + 1 + + + 0 + + + + + 0 + + + + + 0 + + + + + + vertex + sub + + FFEE0000 + 1 + + + FF00EE07 + 1 + + + FF1D00E9 + 1 + + + FF808080 + 1 + + + + + + vertex + sub + + 00EE0000 + 1 + + + 0000EE07 + 1 + + + 001D00E9 + 1 + + + 00808080 + 1 + + + + + + + + NewCell_17 + + + + + 0 + NewCell_9 + + + + + + -234 + + + + + 122.5 + + + + + 0 + + + + + 1 + + + 0 + + + + + 0 + + + + + 0 + + + + + + whole + mix + + FFFF1313 + 1 + + + + + + whole + mix + + FFFF1313 + 0 + + + + + + + + NewCell_18 + + + + + 0 + NewCell_9 + + + + + + -235 + + + + + -235.5 + + + + + 0 + + + + + 1 + + + 0 + + + + + 0 + + + + + 0 + + + + + + vertex + mix + + FFF10000 + 1 + + + FF00FB0F + 1 + + + FF1600F3 + 1 + + + FF808080 + 1 + + + + + + vertex + mix + + 00F10000 + 1 + + + 0000FB0F + 1 + + + 001600F3 + 1 + + + 00808080 + 1 + + + + + + + + NewCell_19 + + + + + 0 + NewCell_9 + + + + + + -101 + + + + + 118.5 + + + + + 0 + + + + + 1 + + + 0 + + + + + 0 + + + + + 0 + + + + + + whole + mul + + FFF30000 + 1 + + + + + + whole + mul + + 00F30000 + 1 + + + + + + + + NewCell_20 + + + + + 0 + NewCell_9 + + + + + + 30 + + + + + 117.5 + + + + + 0 + + + + + 1 + + + 0 + + + + + 0 + + + + + 0 + + + + + + whole + add + + FFF60000 + 1 + + + + + + whole + add + + 00F60000 + 1 + + + + + + + + NewCell_21 + + + + + 0 + NewCell_9 + + + + + + 163 + + + + + 109.5 + + + + + 0 + + + + + 1 + + + 0 + + + + + 0 + + + + + 0 + + + + + + whole + sub + + FFFF1B1B + 1 + + + + + + whole + sub + + 00FF1B1B + 1 + + + + + + + + NewCell_22 + + + + + 0 + NewCell_9 + + + + + + -99 + + + + + -238.5 + + + + + 0 + + + + + 1 + + + 0 + + + + + 0 + + + + + 0 + + + + + + vertex + mul + + FFF60000 + 1 + + + FF23FF04 + 1 + + + FF1600E9 + 1 + + + FF808080 + 1 + + + + + + vertex + mul + + 00F60000 + 1 + + + 0023FF04 + 1 + + + 001600E9 + 1 + + + 00808080 + 1 + + + + + + + + + + diff --git a/Build/TestData/allAttributeV7/pivot.ssae b/Build/TestData/allAttributeV7/pivot.ssae new file mode 100644 index 00000000..d9b4c4de --- /dev/null +++ b/Build/TestData/allAttributeV7/pivot.ssae @@ -0,0 +1,541 @@ + + + + 30 + 11 + prio + 320 320 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 10 + 0 + + pivot + + + + + root + 0 + -1 + null + none + self + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell + 1 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_1 + 2 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_6 + 3 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_5 + 4 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_2 + 5 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_3 + 6 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + + + + + color_bar.ssce + + + + Setup + 1 + + 60 + 1 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 0 + 0 + + + 1 + + + root + + + + 0 + + + + + + + + anime_1 + 1 + + 60 + 60 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 59 + 0 + + + 0 + + + root + + + + 0 + + + + + + NewCell + + + + + 0 + NewCell + + + + + + -181.33332824707 + + + + + 97.3333358764648 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + 0 + + + 1 + + + + + + NewCell_1 + + + + + 0 + NewCell_1 + + + + + + 198.66667175293 + + + + + 106.666664123535 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + 0 + + + 1 + + + + + + NewCell_6 + + + + + 0 + NewCell_5 + + + + + + 209.33332824707 + + + + + -74.6666641235352 + + + + + 0 + + + 360 + + + + + 0 + + + + + 0 + + + + + 1 + + + + + + NewCell_5 + + + + + 0 + NewCell_5 + + + + + + -117 + + + + + -57.5 + + + + + 0 + + + 360 + + + + + 0 + + + + + 0 + + + + + 1 + + + + + + NewCell_2 + + + + + 0 + NewCell_2 + + + + + + -332.666687011719 + + + + + -12.3333435058594 + + + + + 0 + + + + + 1 + + + 2 + + + + + 0 + + + + + 0 + + + + + 1 + + + + + + NewCell_3 + + + + + 0 + NewCell_2 + + + + + + 390.666687011719 + + + + + 48 + + + + + 0 + + + + + 1 + + + 2 + + + + + 0 + + + + + 0 + + + + + 1 + + + + + + + + diff --git a/Build/TestData/allAttributeV7/pos.ssae b/Build/TestData/allAttributeV7/pos.ssae new file mode 100644 index 00000000..18c01c1a --- /dev/null +++ b/Build/TestData/allAttributeV7/pos.ssae @@ -0,0 +1,786 @@ + + + + 30 + 11 + prio + 320 320 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 10 + + + + 1 + 0 0 + 0 0 + 0 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + 0 + + pos + + + + + root + 0 + -1 + null + none + self + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_8 + 1 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_9 + 2 + 1 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell + 3 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_1 + 4 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_2 + 5 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_3 + 6 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_4 + 7 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_6 + 8 + 7 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_5 + 9 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_7 + 10 + 9 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + + + + + color_bar.ssce + + + + Setup + 1 + + 30 + 1 + prio + 320 320 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + 0 + + + 1 + + + root + + + + 0 + + + + + + + + anime_1 + 1 + + 60 + 60 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 59 + + + + 1 + 0 0 + 0 0 + 0 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + 0 + + + 0 + + + root + + + + 0 + + + + + + NewCell_8 + + + + + 0 + NewCell_2 + + + + + + -204 + + + + + 168 + + + + + 0 + + + + + 0 + + + 360 + + + + + 0 + + + + + 0 + + + + + + NewCell_9 + + + + + 0 + NewCell_2 + + + + + + 72 + + + + + 0 + + + + + 100 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + NewCell + + + + + 0 + NewCell + + + + + + 100 + + + 200 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + NewCell_1 + + + + + 0 + NewCell_1 + + + + + + 100 + + + 200 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + NewCell_2 + + + + + 0 + NewCell_2 + + + + + + -100 + + + -200 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + NewCell_3 + + + + + 0 + NewCell_3 + + + + + + -100 + + + -200 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + NewCell_4 + + + + + 0 + NewCell + + + + + + -254 + + + -428 + + + + + -104.5 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + NewCell_6 + + + + + 0 + NewCell + + + + + + 53 + + + + + -58 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + NewCell_5 + + + + + 0 + NewCell_1 + + + + + + 280 + + + + + -116.5 + + + -246.5 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + NewCell_7 + + + + + 0 + NewCell_1 + + + + + + 47 + + + + + -49 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + + + diff --git a/Build/TestData/allAttributeV7/prio.ssae b/Build/TestData/allAttributeV7/prio.ssae new file mode 100644 index 00000000..815b4aa9 --- /dev/null +++ b/Build/TestData/allAttributeV7/prio.ssae @@ -0,0 +1,498 @@ + + + + 30 + 11 + prio + 320 320 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 10 + 0 + + prio + + + + + root + 0 + -1 + null + none + self + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_11 + 1 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell + 2 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_1 + 3 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_2 + 4 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_3 + 5 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_5 + 6 + 5 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + + + + + color_bar.ssce + + + + Setup + 1 + + 60 + 1 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 0 + 0 + + + 1 + + + root + + + + 0 + + + + + + + + anime_1 + 1 + + 60 + 60 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 59 + 0 + + + 0 + + + root + + + + 0 + + + + + + NewCell_11 + + + + + 0 + NewCell_11 + + + + + + -111 + + + + + -37.5 + + + + + 0 + + + + + 50 + + + 20 + + + + + 0 + + + + + + NewCell + + + + + 0 + NewCell + + + + + + -76 + + + + + -62.5 + + + + + 0 + + + + + 40 + + + 30 + + + + + 0 + + + + + + NewCell_1 + + + + + 0 + NewCell_1 + + + + + + -33 + + + + + -39.5 + + + + + 0 + + + + + 30 + + + 40 + + + + + 0 + + + + + + NewCell_2 + + + + + 0 + NewCell_2 + + + + + + 19 + + + + + -63.5 + + + + + 0 + + + + + 20 + + + 50 + + + + + 0 + + + + + + NewCell_3 + + + + + 0 + NewCell_3 + + + + + + -6 + + + + + 136.5 + + + + + 0 + + + + + 10 + + + + + 0 + + + + + + NewCell_5 + + + + + 0 + NewCell_5 + + + + + + 39 + + + + + -48 + + + + + 0 + + + + + 0 + + + 20 + + + + + 0 + + + + + + + + diff --git a/Build/TestData/allAttributeV7/rot.ssae b/Build/TestData/allAttributeV7/rot.ssae new file mode 100644 index 00000000..924babf6 --- /dev/null +++ b/Build/TestData/allAttributeV7/rot.ssae @@ -0,0 +1,967 @@ + + + + 30 + 11 + prio + 320 320 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 10 + + + + 1 + 0 0 + 0 0 + 0 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + 0 + + rot + + + + + root + 0 + -1 + null + none + self + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_9 + 1 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_10 + 2 + 1 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_6 + 3 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_7 + 4 + 3 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell + 5 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_1 + 6 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_11 + 7 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_2 + 8 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_4 + 9 + 8 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_3 + 10 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_5 + 11 + 10 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_12 + 12 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_13 + 13 + 12 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + + + + + color_bar.ssce + + + + Setup + 1 + + 60 + 1 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + 0 + + + 1 + + + root + + + + 0 + + + + + + + + anime_1 + 1 + + 60 + 60 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 59 + + + + 1 + 0 0 + 0 0 + 0 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + 0 + + + 0 + + + root + + + + 0 + + + + + + NewCell_9 + + + + + 0 + NewCell_9 + + + + + + -270 + + + + + 57.3333358764648 + + + + + 0.260416984558105 + + + + + 1 + + + + + 0 + + + + + 0 + + + + + + NewCell_10 + + + + + 0 + NewCell_9 + + + + + + 149.759658813477 + + + + + 1 + + + + + 0 + + + 90 + + + + + 0 + + + + + 0 + + + + + + NewCell_6 + + + + + 0 + NewCell_2 + + + + + + -3.33333325386047 + + + + + 195.33332824707 + + + + + -1 + + + + + 0 + + + + + 0 + + + + + + NewCell_7 + + + + + 0 + NewCell_5 + + + + + + 0 + + + + + 57 + + + + + 0 + + + 360 + + + + + 0 + + + + + 0 + + + + + + NewCell + + + + + 0 + NewCell + + + + + + -100 + + + + + 0 + + + 360 + + + + + 0 + + + + + 0 + + + + + + NewCell_1 + + + + + 0 + NewCell_1 + + + + + + 0 + + + 360 + + + + + 0 + + + + + 0 + + + + + + NewCell_11 + + + + + 0 + NewCell_11 + + + + + + 100 + + + + + 0 + + + 360 + + + + + 0 + + + + + 0 + + + + + + NewCell_2 + + + + + 0 + NewCell + + + + + + -203 + + + + + -125 + + + + + 0 + + + 360 + + + + + 0 + + + + + 0 + + + + + + NewCell_4 + + + + + 0 + NewCell + + + + + + 37 + + + + + -48 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + NewCell_3 + + + + + 0 + NewCell_1 + + + + + + 2 + + + + + -130 + + + + + 0 + + + 360 + + + + + 0 + + + + + 0 + + + + + + NewCell_5 + + + + + 0 + NewCell_1 + + + + + + 46 + + + + + -54 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + NewCell_12 + + + + + 0 + NewCell_11 + + + + + + 210 + + + + + -135 + + + + + 0 + + + 360 + + + + + 0 + + + + + 0 + + + + + + NewCell_13 + + + + + 0 + NewCell_11 + + + + + + 41 + + + + + -51 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + + + diff --git a/Build/TestData/allAttributeV7/scl.ssae b/Build/TestData/allAttributeV7/scl.ssae new file mode 100644 index 00000000..c73822c6 --- /dev/null +++ b/Build/TestData/allAttributeV7/scl.ssae @@ -0,0 +1,712 @@ + + + + 30 + 11 + prio + 320 320 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 10 + + + + 1 + 0 0 + 0 0 + 0 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + 0 + + scl + + + + + root + 0 + -1 + null + none + self + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell + 1 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_1 + 2 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_2 + 3 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_4 + 4 + 3 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_3 + 5 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_5 + 6 + 5 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_6 + 7 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_7 + 8 + 7 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + + + + + color_bar.ssce + + + + Setup + 1 + + 60 + 1 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + 0 + + + 1 + + + root + + + + 0 + + + + + + + + anime_1 + 1 + + 60 + 60 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 59 + + + + 1 + 0 0 + 0 0 + 0 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + 0 + + + 0 + + + root + + + + 0 + + + + + + NewCell + + + + + 0 + NewCell + + + + + + -100 + + + + + 0 + + + + + 1 + + + 2 + + + + + 0 + + + + + 0 + + + + + + NewCell_1 + + + + + 0 + NewCell_1 + + + + + + 109 + + + + + 73 + + + + + 0 + + + + + 1 + + + 3 + + + + + 0 + + + + + 0 + + + + + + NewCell_2 + + + + + 0 + NewCell + + + + + + -90 + + + + + -154 + + + + + 0 + + + + + 1 + + + 2 + + + + + 0 + + + + + 0 + + + + + + NewCell_4 + + + + + 0 + NewCell + + + + + + 42 + + + + + -45 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + NewCell_3 + + + + + 0 + NewCell_1 + + + + + + 262 + + + + + 71 + + + + + 0 + + + + + 1 + + + 3 + + + + + 0 + + + + + 0 + + + + + + NewCell_5 + + + + + 0 + NewCell_1 + + + + + + 39 + + + + + -50 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + NewCell_6 + + + + + 0 + NewCell_2 + + + + + + -360 + + + + + 110.5 + + + + + 0 + + + + + 1 + + + 1.5 + + + + + 1 + + + 1.5 + + + + + 0 + + + + + 0 + + + + + + NewCell_7 + + + + + 0 + NewCell_2 + + + + + + 41 + + + + + -39 + + + + + 0 + + + + + 1 + + + 1.5 + + + + + 1 + + + 1.5 + + + + + 0 + + + + + 0 + + + + + + + + diff --git a/Build/TestData/allAttributeV7/setupdata.ssae b/Build/TestData/allAttributeV7/setupdata.ssae new file mode 100644 index 00000000..24cb5fc0 --- /dev/null +++ b/Build/TestData/allAttributeV7/setupdata.ssae @@ -0,0 +1,304 @@ + + + + 30 + 11 + prio + 320 320 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 10 + 0 + + setupdata + + + + + root + 0 + -1 + null + none + self + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell + 1 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_1 + 2 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + + + + + color_bar.ssce + + + + Setup + 1 + + 60 + 1 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 0 + 0 + + + 1 + + + root + + + + 0 + + + + + + NewCell + + + + + 0 + NewCell + + + + + + 127.5 + + + + + 71.5 + + + + + 45 + + + + + 2 + + + + + 2 + + + + + 0.5 + + + + + 0 + + + + + 0 + + + + + + NewCell_1 + + + + + 0 + NewCell + + + + + + -201.5 + + + + + 73.5 + + + + + 45 + + + + + 2 + + + + + 2 + + + + + 0.5 + + + + + 0 + + + + + 0 + + + + + + + + anime_1 + 1 + + 60 + 60 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 59 + 0 + + + 0 + + + root + + + + 0 + + + + + + NewCell_1 + + + + -197.5 + + + + + -160.5 + + + + + 90 + + + + + 3 + + + + + 3 + + + + + 1 + + + + + + + + diff --git a/Build/TestData/allAttributeV7/size.ssae b/Build/TestData/allAttributeV7/size.ssae new file mode 100644 index 00000000..77417899 --- /dev/null +++ b/Build/TestData/allAttributeV7/size.ssae @@ -0,0 +1,403 @@ + + + + 30 + 11 + prio + 320 320 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 10 + 0 + + size + + + + + root + 0 + -1 + null + none + self + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell + 1 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_2 + 2 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_1 + 3 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_3 + 4 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + + + + + color_bar.ssce + + + + Setup + 1 + + 60 + 1 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 0 + 0 + + + 1 + + + root + + + + 0 + + + + + + + + anime_1 + 1 + + 60 + 60 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 59 + 0 + + + 0 + + + root + + + + 0 + + + + + + NewCell + + + + + 0 + NewCell + + + + + + -200 + + + + + 13.3333339691162 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + 64 + + + 200 + + + + + + NewCell_2 + + + + + 0 + NewCell + + + + + + -200 + + + + + -78 + + + + + 0 + + + + + 1 + + + 2 + + + + + 0 + + + + + 0 + + + + + 100 + + + + + + NewCell_1 + + + + + 0 + NewCell_1 + + + + + + 181.333343505859 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + 64 + + + 200 + + + + + + NewCell_3 + + + + + 0 + NewCell_1 + + + + + + 300 + + + + + 0 + + + + + 0 + + + + + 1 + + + 2 + + + + + 0 + + + + + 0 + + + + + 100 + + + + + + + + diff --git a/Build/TestData/allAttributeV7/startend.ssae b/Build/TestData/allAttributeV7/startend.ssae new file mode 100644 index 00000000..8cbaae3f --- /dev/null +++ b/Build/TestData/allAttributeV7/startend.ssae @@ -0,0 +1,181 @@ + + + + 30 + 11 + prio + 320 320 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 10 + 0 + + startend + + + + + root + 0 + -1 + null + none + self + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_5 + 1 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + + + + + color_bar.ssce + + + + Setup + 1 + + 60 + 1 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 0 + 0 + + + 1 + + + root + + + + 0 + + + + + + + + anime_1 + 1 + + 60 + 60 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 20 + 40 + 0 + + + 0 + + + root + + + + 0 + + + + + + NewCell_5 + + + + + 0 + NewCell_5 + + + + + + 0 + + + + + 0 + + + + + 0 + + + 360 + + + + + 0 + + + + + 0 + + + + + + + + diff --git a/Build/TestData/allAttributeV7/textureChange.ssae b/Build/TestData/allAttributeV7/textureChange.ssae new file mode 100644 index 00000000..4a191d3b --- /dev/null +++ b/Build/TestData/allAttributeV7/textureChange.ssae @@ -0,0 +1,242 @@ + + + + 30 + 11 + prio + 320 320 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 10 + + + + 1 + 0 0 + 0 0 + 0 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + 0 + + textureChange + + + + + root + 0 + -1 + null + none + self + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + 1 + + + NewCell + 1 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + 1 + + + + + + + color_bar.ssce + + + + Setup + 1 + + 60 + 1 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + 0 + + + + 1 + + + root + + + + 0 + + + + + + + + anime_1 + 1 + + 60 + 60 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 59 + + + + 1 + 0 0 + 0 0 + 0 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + 0 + + + + 0 + + + root + + + + 0 + + + + + + NewCell + + + + + 0 + NewCell_11 + + + + + + 0 + + + + + -2 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + color_bar.png + + + + + 9slice_64tile.png + + + + + + + + + diff --git a/Build/TestData/allAttributeV7/userdata.ssae b/Build/TestData/allAttributeV7/userdata.ssae new file mode 100644 index 00000000..9c340dd7 --- /dev/null +++ b/Build/TestData/allAttributeV7/userdata.ssae @@ -0,0 +1,389 @@ + + + + 30 + 11 + prio + 320 320 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 10 + 0 + + userdata + + + + + root + 0 + -1 + null + none + self + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell + 1 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_1 + 2 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_2 + 3 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_3 + 4 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + + + + + color_bar.ssce + + + + Setup + 1 + + 60 + 1 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 0 + 0 + + + 1 + + + root + + + + 0 + + + + + + + + anime_1 + 1 + + 60 + 60 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 59 + 0 + + + 0 + + + root + + + + 0 + + + + + + NewCell + + + + + 0 + NewCell + + + + + + -282.666687011719 + + + + + -9.33333396911621 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + 10 + + + + + + + NewCell_1 + + + + + 0 + NewCell + + + + + + -94.6666641235352 + + + + + -9.66666793823242 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + 10 20 30 40 + + + + + + + NewCell_2 + + + + + 0 + NewCell + + + + + + 138.666656494141 + + + + + -12.6666679382324 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + 10 20 + + + + + + + NewCell_3 + + + + + 0 + NewCell + + + + + + 319.333312988281 + + + + + -13.3333339691162 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + test + + + + + + + + + diff --git a/Build/TestData/allAttributeV7/uvs.ssae b/Build/TestData/allAttributeV7/uvs.ssae new file mode 100644 index 00000000..6c12c270 --- /dev/null +++ b/Build/TestData/allAttributeV7/uvs.ssae @@ -0,0 +1,409 @@ + + + + 30 + 11 + prio + 320 320 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 10 + 0 + + uvs + + + + + root + 0 + -1 + null + none + self + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell + 1 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_1 + 2 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_2 + 3 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_9 + 4 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + + + + + color_bar.ssce + + + + Setup + 1 + + 60 + 1 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 0 + 0 + + + 1 + + + root + + + + 0 + + + + + + + + anime_1 + 1 + + 60 + 60 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 59 + 0 + + + 0 + + + root + + + + 0 + + + + + + NewCell + + + + + 0 + NewCell_2 + + + + + + -110 + + + + + 1.66666603088379 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + 1 + + + 2 + + + + + + NewCell_1 + + + + + 0 + NewCell_1 + + + + + + 89.3333358764648 + + + + + 5 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + 1 + + + 2 + + + + + + NewCell_2 + + + + + 0 + NewCell_1 + + + + + + -101.333335876465 + + + + + -111 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + 1 + + + 2 + + + + + 1 + + + 2 + + + + + + NewCell_9 + + + + + 0 + NewCell_9 + + + + + + 96.3333358764648 + + + + + -113.66667175293 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + 1 + + + 0.5 + + + + + 1 + + + 0.5 + + + + + + + + diff --git a/Build/TestData/allAttributeV7/uvt.ssae b/Build/TestData/allAttributeV7/uvt.ssae new file mode 100644 index 00000000..93ff2abd --- /dev/null +++ b/Build/TestData/allAttributeV7/uvt.ssae @@ -0,0 +1,324 @@ + + + + 30 + 11 + prio + 320 320 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 10 + 0 + + uvt + + + + + root + 0 + -1 + null + none + self + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell + 1 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_1 + 2 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_11 + 3 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + + + + + color_bar.ssce + + + + Setup + 1 + + 60 + 1 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 0 + 0 + + + 1 + + + root + + + + 0 + + + + + + + + anime_1 + 1 + + 60 + 60 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 59 + 0 + + + 0 + + + root + + + + 0 + + + + + + NewCell + + + + + 0 + NewCell + + + + + + -80 + + + + + 3.66666698455811 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + 0 + + + 0.5 + + + + + + NewCell_1 + + + + + 0 + NewCell_1 + + + + + + 106 + + + + + 5.66666698455811 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + 0 + + + 0.5 + + + + + + NewCell_11 + + + + + 0 + NewCell_11 + + + + + + 2.66666793823242 + + + + + -101.666664123535 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + 0 + + + 360 + + + + + + + + diff --git a/Build/TestData/allAttributeV7/vertex.ssae b/Build/TestData/allAttributeV7/vertex.ssae new file mode 100644 index 00000000..9cd4cee5 --- /dev/null +++ b/Build/TestData/allAttributeV7/vertex.ssae @@ -0,0 +1,228 @@ + + + + 30 + 11 + prio + 320 320 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 10 + 0 + + vertex + + + + + root + 0 + -1 + null + none + self + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_9 + 1 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + + + + + color_bar.ssce + + + + Setup + 1 + + 60 + 1 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 0 + 0 + + + 1 + + + root + + + + 0 + + + + + + + + anime_1 + 1 + + 60 + 60 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 59 + 0 + + + 0 + + + root + + + + 0 + + + + + + NewCell_9 + + + + + 0 + NewCell_9 + + + + + + 0 + + + + + -5.5 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + 0 0 + 0 0 + 0 0 + 0 0 + + + + + -100 100 + 0 0 + 0 0 + 0 0 + + + + + -100 100 + 100 100 + 0 0 + 0 0 + + + + + -100 100 + 100 100 + -100 -100 + 0 0 + + + + + -100 100 + 100 100 + -100 -100 + 100 -100 + + + + + 0 0 + 0 0 + 0 0 + 0 0 + + + + + + + + + diff --git a/Build/TestData/allPartsV7/9slice_64.png b/Build/TestData/allPartsV7/9slice_64.png new file mode 100644 index 00000000..9d5081af Binary files /dev/null and b/Build/TestData/allPartsV7/9slice_64.png differ diff --git a/Build/TestData/allPartsV7/9slice_64.ssce b/Build/TestData/allPartsV7/9slice_64.ssce new file mode 100644 index 00000000..df49ca3a --- /dev/null +++ b/Build/TestData/allPartsV7/9slice_64.ssce @@ -0,0 +1,38 @@ + + + 9slice_64 + + SpriteStudio + 0 + 9slice_64.png + 64 64 + 0 + clamp + linear + + + + 4096 4096 + 1 + 0 + 0 + 1 + + + + 9slice_64 + 0 0 + 64 64 + 0 0 + 0 + + 0 + 0 + unknown + + + + + + + diff --git a/Build/TestData/allPartsV7/9slice_64tile.png b/Build/TestData/allPartsV7/9slice_64tile.png new file mode 100644 index 00000000..4829de1b Binary files /dev/null and b/Build/TestData/allPartsV7/9slice_64tile.png differ diff --git a/Build/TestData/allPartsV7/9slice_64tile.ssce b/Build/TestData/allPartsV7/9slice_64tile.ssce new file mode 100644 index 00000000..534e2f59 --- /dev/null +++ b/Build/TestData/allPartsV7/9slice_64tile.ssce @@ -0,0 +1,38 @@ + + + 9slice_64tile + + SpriteStudio + 0 + 9slice_64tile.png + 64 64 + 0 + clamp + linear + + + + 4096 4096 + 1 + 0 + 0 + 1 + + + + 9slice_64tile + 0 0 + 64 64 + 0 0 + 0 + + 0 + 0 + unknown + + + + + + + diff --git a/Build/TestData/allPartsV7/NewEffect.ssee b/Build/TestData/allPartsV7/NewEffect.ssee new file mode 100644 index 00000000..5fa3f5d6 --- /dev/null +++ b/Build/TestData/allPartsV7/NewEffect.ssee @@ -0,0 +1,62 @@ + + + NewEffect + + + 0 + 0 + 30 + FF000000 + 2 + 100 + 100 + + + Root + Root + 0 + -1 + 1 + + + Emitter_1 + Emmiter + 1 + 0 + 1 + + NewCell + color_bar.ssce + Add + + + Basic + 64 + 20 + 1 + 1 + 30 + + + 0 + 45 + + + + + + Particle_1 + Particle + 2 + 1 + 1 + + + + Add + + + + + + diff --git a/Build/TestData/allPartsV7/allPartsV7.sspj b/Build/TestData/allPartsV7/allPartsV7.sspj new file mode 100644 index 00000000..1a6a22a8 --- /dev/null +++ b/Build/TestData/allPartsV7/allPartsV7.sspj @@ -0,0 +1,240 @@ + + + allPartsV7 + + + + + + + Export + 1 + 1 + SSAX + invalid + 0 + 1 + + custom + + 0 + 0 + 0 + 1 + 1 + 0 + 1 + + none + linear + hermite + bezier + acceleration + deceleration + + + CELL + POSX + POSY + POSZ + ROTX + ROTY + ROTZ + SCLX + SCLY + LSCX + LSCY + ALPH + LALP + PRIO + IFLH + IFLV + FLPH + FLPV + HIDE + PCOL + VCOL + VERT + PVTX + PVTY + ANCX + ANCY + SIZX + SIZY + UVTX + UVTY + UVRZ + UVSX + UVSY + BNDR + MASK + USER + IPRM + EFCT + DEFM + ADIO + TCHG + + + bone + effect + mask + mesh + nines + shape + sound + text + + + POSX + POSY + ROTZ + PRIO + HIDE + + clamp + linear + linear + rate + + + AVI + FF606060 + 0 + 0 + 1 + 100 + 100 + 1 + 1 + 0 + 0 + 0 + 0 + + lossless + 75 + 4 + 1 + 0 + + + 1536000 + + + + 50 + + + 2 + 1 + 0 + 0 + 0 + 1 + 0 + 8192 + 8192 + 73400320 + 100 + 0 + + + + + + + + + + + + + + + + + + + + + + + 60 + 60 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 59 + + + + 1 + 0 0 + 0 0 + 0 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + 0 + + + 4096 4096 + 1 + 0 + 0 + 1 + + + 9slice_64.ssce + 9slice_64tile.ssce + color_bar.ssce + + + font/RoundedMPlus.fnt + font/Sample_PixelMplus12.fnt + + + effect.ssae + instanse.ssae + mask.ssae + mesh.ssae + nineslice.ssae + normal.ssae + null.ssae + root.ssae + shape.ssae + sound.ssae + text.ssae + + + NewEffect.ssee + + + soundlist.ssse + + + + + text.ssae + anime_1 + + color_bar.ssce + NewCell_1 + font/RoundedMPlus.fnt + NewEffect.ssee + 0 + + + diff --git a/Build/TestData/allPartsV7/color_bar.png b/Build/TestData/allPartsV7/color_bar.png new file mode 100644 index 00000000..083018ab Binary files /dev/null and b/Build/TestData/allPartsV7/color_bar.png differ diff --git a/Build/TestData/allPartsV7/color_bar.ssce b/Build/TestData/allPartsV7/color_bar.ssce new file mode 100644 index 00000000..062ca29b --- /dev/null +++ b/Build/TestData/allPartsV7/color_bar.ssce @@ -0,0 +1,354 @@ + + + color_bar + + SpriteStudio + 0 + color_bar.png + 256 256 + 0 + clamp + linear + + + + 4096 4096 + 1 + 0 + 0 + 1 + + + + NewCell + 0 80 + 64 64 + 0 0 + 0 + + 0 + 0 + unknown + + + + + + + NewCell_1 + 64 80 + 64 64 + 0 0 + 0 + + 0 + 0 + unknown + + + + + + + NewCell_10 + 0 145 + 16 15 + 0 0 + 0 + + 0 + 0 + unknown + + + + + + + NewCell_11 + 192 80 + 48 48 + 0 0 + 0 + + 0 + 0 + unknown + + + + + + + NewCell_12 + 192 160 + 48 16 + -0.5 -0.5 + 0 + + 0 + 0 + unknown + + + + + + + NewCell_13 + 0 160 + 16 16 + 0 0 + 0 + + 0 + 0 + unknown + + + + + + + NewCell_14 + 16 160 + 16 16 + 0 0 + 0 + + 0 + 0 + unknown + + + + + + + NewCell_15 + 32 160 + 16 16 + 0 0 + 0 + + 0 + 0 + unknown + + + + + + + NewCell_16 + 48 160 + 16 16 + 0 0 + 0 + + 0 + 0 + unknown + + + + + + + NewCell_2 + 128 80 + 64 64 + 0 0 + 0 + + 0 + 0 + unknown + + + + + + + NewCell_3 + 0 0 + 64 64 + 0 0 + 0 + + 0 + 0 + unknown + + + + + + + color_bar + 0 0 + 256 256 + 0 0 + 0 + + 0 + 0 + unknown + + + + + + + NewCell_4 + 80 0 + 64 64 + 0 0 + 0 + + 0 + 0 + unknown + + + + + + + NewCell_5 + 160 0 + 64 64 + 0 0 + 0 + + 0 + 0 + unknown + + + + + + + NewCell_6 + 64 80 + 64 16 + -0.5 0 + 0 + + 0 + 0 + unknown + + + + + + + NewCell_7 + 128 80 + 64 16 + -0.5 0 + 0 + + 0 + 0 + unknown + + + + + + + NewCell_8 + 0 176 + 80 80 + 0 0 + 0 + + 0 + 0 + unknown + + + + + + + NewCell_9 + 96 176 + 64 64 + 0 0 + 0 + + 0 + 0 + unknown + + + + + + + NewCell_17 + 96 176 + 64 64 + 0 0 + 0 + + 0 + 1 + polyline + + 16 15 + 46 15 + 46 43 + 17 43 + 31 31 + + + 0 0 + 32 0 + 64 0 + 64 32 + 64 64 + 32 64 + 0 64 + 0 32 + + + 0 64 + 17 43 + 32 64 + 0 32 + 16 15 + 31 31 + 46 43 + 64 64 + 64 32 + 46 15 + 64 0 + 32 0 + 0 0 + + + 0 1 2 + 0 3 1 + 1 3 4 + 5 1 4 + 6 1 5 + 2 1 6 + 2 6 7 + 6 8 7 + 8 6 9 + 9 10 8 + 9 11 10 + 4 11 9 + 4 12 11 + 3 12 4 + 5 4 9 + 6 5 9 + + + + diff --git a/Build/TestData/allPartsV7/effect.ssae b/Build/TestData/allPartsV7/effect.ssae new file mode 100644 index 00000000..3e0bea90 --- /dev/null +++ b/Build/TestData/allPartsV7/effect.ssae @@ -0,0 +1,169 @@ + + + + 30 + 11 + prio + 320 320 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 10 + 0 + + effect + + + + + root + 0 + -1 + null + none + self + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + effect_1 + 1 + 0 + effect + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + NewEffect + mix + 1 + 0 + 0 + 1 + + 1 + + + + + + + + + Setup + 1 + + 60 + 1 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 0 + 0 + + + 1 + + + root + + + + 0 + + + + + + + + anime_1 + 1 + + 60 + 60 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 59 + 0 + + + 0 + + + root + + + + 0 + + + + + + effect_1 + + + + 0 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + + + diff --git a/Build/TestData/allPartsV7/font/MPLUSRounded_License.txt b/Build/TestData/allPartsV7/font/MPLUSRounded_License.txt new file mode 100644 index 00000000..4ca6123b --- /dev/null +++ b/Build/TestData/allPartsV7/font/MPLUSRounded_License.txt @@ -0,0 +1,93 @@ +M PLUS Rounded 1c Font + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/Build/TestData/allPartsV7/font/RoundedMPlus.fnt b/Build/TestData/allPartsV7/font/RoundedMPlus.fnt new file mode 100644 index 00000000..594b4d4e --- /dev/null +++ b/Build/TestData/allPartsV7/font/RoundedMPlus.fnt @@ -0,0 +1,299 @@ +info face="PixelMplus12" size=32 bold=0 italic=0 charset="" unicode=1 stretchH=100 smooth=1 aa=1 padding=0,0,0,0 spacing=1,1 outline=2 +common lineHeight=32 base=26 scaleW=512 scaleH=512 pages=1 packed=0 alphaChnl=1 redChnl=0 greenChnl=0 blueChnl=0 +page id=0 file="RoundedMPlus_0.png" +chars count=295 +char id=32 x=205 y=421 width=7 height=5 xoffset=-3 yoffset=29 xadvance=15 page=0 chnl=15 +char id=33 x=503 y=228 width=8 height=27 xoffset=2 yoffset=2 xadvance=15 page=0 chnl=15 +char id=34 x=497 y=386 width=13 height=14 xoffset=0 yoffset=0 xadvance=15 page=0 chnl=15 +char id=35 x=266 y=320 width=18 height=27 xoffset=-3 yoffset=2 xadvance=15 page=0 chnl=15 +char id=36 x=285 y=320 width=18 height=27 xoffset=-3 yoffset=2 xadvance=15 page=0 chnl=15 +char id=37 x=304 y=320 width=18 height=27 xoffset=-3 yoffset=2 xadvance=15 page=0 chnl=15 +char id=38 x=323 y=320 width=18 height=27 xoffset=-3 yoffset=2 xadvance=15 page=0 chnl=15 +char id=39 x=502 y=288 width=8 height=14 xoffset=2 yoffset=0 xadvance=15 page=0 chnl=15 +char id=40 x=496 y=101 width=13 height=32 xoffset=0 yoffset=0 xadvance=15 page=0 chnl=15 +char id=41 x=385 y=167 width=13 height=32 xoffset=0 yoffset=0 xadvance=15 page=0 chnl=15 +char id=42 x=464 y=374 width=18 height=22 xoffset=-3 yoffset=5 xadvance=15 page=0 chnl=15 +char id=43 x=446 y=397 width=18 height=17 xoffset=-3 yoffset=7 xadvance=15 page=0 chnl=15 +char id=44 x=497 y=370 width=13 height=15 xoffset=0 yoffset=17 xadvance=15 page=0 chnl=15 +char id=45 x=167 y=421 width=18 height=7 xoffset=-3 yoffset=12 xadvance=15 page=0 chnl=15 +char id=46 x=66 y=424 width=13 height=12 xoffset=0 yoffset=17 xadvance=15 page=0 chnl=15 +char id=47 x=484 y=229 width=18 height=30 xoffset=-3 yoffset=2 xadvance=15 page=0 chnl=15 +char id=48 x=342 y=320 width=18 height=27 xoffset=-3 yoffset=2 xadvance=15 page=0 chnl=15 +char id=49 x=498 y=260 width=13 height=27 xoffset=-3 yoffset=2 xadvance=15 page=0 chnl=15 +char id=50 x=361 y=320 width=18 height=27 xoffset=-3 yoffset=2 xadvance=15 page=0 chnl=15 +char id=51 x=380 y=320 width=18 height=27 xoffset=-3 yoffset=2 xadvance=15 page=0 chnl=15 +char id=52 x=399 y=320 width=18 height=27 xoffset=-3 yoffset=2 xadvance=15 page=0 chnl=15 +char id=53 x=418 y=320 width=18 height=27 xoffset=-3 yoffset=2 xadvance=15 page=0 chnl=15 +char id=54 x=437 y=320 width=18 height=27 xoffset=-3 yoffset=2 xadvance=15 page=0 chnl=15 +char id=55 x=456 y=320 width=18 height=27 xoffset=-3 yoffset=2 xadvance=15 page=0 chnl=15 +char id=56 x=475 y=317 width=18 height=27 xoffset=-3 yoffset=2 xadvance=15 page=0 chnl=15 +char id=57 x=0 y=351 width=18 height=27 xoffset=-3 yoffset=2 xadvance=15 page=0 chnl=15 +char id=58 x=483 y=370 width=13 height=22 xoffset=0 yoffset=7 xadvance=15 page=0 chnl=15 +char id=59 x=467 y=348 width=13 height=25 xoffset=0 yoffset=7 xadvance=15 page=0 chnl=15 +char id=60 x=19 y=351 width=18 height=27 xoffset=-3 yoffset=2 xadvance=15 page=0 chnl=15 +char id=61 x=11 y=425 width=18 height=12 xoffset=-3 yoffset=10 xadvance=15 page=0 chnl=15 +char id=62 x=38 y=350 width=18 height=27 xoffset=-3 yoffset=2 xadvance=15 page=0 chnl=15 +char id=63 x=57 y=350 width=18 height=27 xoffset=-3 yoffset=2 xadvance=15 page=0 chnl=15 +char id=64 x=179 y=294 width=18 height=27 xoffset=-3 yoffset=2 xadvance=15 page=0 chnl=15 +char id=65 x=198 y=294 width=18 height=27 xoffset=-3 yoffset=2 xadvance=15 page=0 chnl=15 +char id=66 x=217 y=294 width=18 height=27 xoffset=-3 yoffset=2 xadvance=15 page=0 chnl=15 +char id=67 x=236 y=294 width=18 height=27 xoffset=-3 yoffset=2 xadvance=15 page=0 chnl=15 +char id=68 x=247 y=322 width=18 height=27 xoffset=-3 yoffset=2 xadvance=15 page=0 chnl=15 +char id=69 x=255 y=292 width=18 height=27 xoffset=-3 yoffset=2 xadvance=15 page=0 chnl=15 +char id=70 x=274 y=292 width=18 height=27 xoffset=-3 yoffset=2 xadvance=15 page=0 chnl=15 +char id=71 x=293 y=292 width=18 height=27 xoffset=-3 yoffset=2 xadvance=15 page=0 chnl=15 +char id=72 x=312 y=292 width=18 height=27 xoffset=-3 yoffset=2 xadvance=15 page=0 chnl=15 +char id=73 x=76 y=350 width=13 height=27 xoffset=0 yoffset=2 xadvance=15 page=0 chnl=15 +char id=74 x=331 y=292 width=18 height=27 xoffset=-3 yoffset=2 xadvance=15 page=0 chnl=15 +char id=75 x=350 y=292 width=18 height=27 xoffset=-3 yoffset=2 xadvance=15 page=0 chnl=15 +char id=76 x=369 y=292 width=18 height=27 xoffset=-3 yoffset=2 xadvance=15 page=0 chnl=15 +char id=77 x=388 y=292 width=18 height=27 xoffset=-3 yoffset=2 xadvance=15 page=0 chnl=15 +char id=78 x=407 y=292 width=18 height=27 xoffset=-3 yoffset=2 xadvance=15 page=0 chnl=15 +char id=79 x=426 y=292 width=18 height=27 xoffset=-3 yoffset=2 xadvance=15 page=0 chnl=15 +char id=80 x=445 y=292 width=18 height=27 xoffset=-3 yoffset=2 xadvance=15 page=0 chnl=15 +char id=81 x=325 y=167 width=21 height=32 xoffset=-3 yoffset=2 xadvance=15 page=0 chnl=15 +char id=82 x=464 y=289 width=18 height=27 xoffset=-3 yoffset=2 xadvance=15 page=0 chnl=15 +char id=83 x=483 y=289 width=18 height=27 xoffset=-3 yoffset=2 xadvance=15 page=0 chnl=15 +char id=84 x=0 y=323 width=18 height=27 xoffset=-3 yoffset=2 xadvance=15 page=0 chnl=15 +char id=85 x=19 y=323 width=18 height=27 xoffset=-3 yoffset=2 xadvance=15 page=0 chnl=15 +char id=86 x=38 y=322 width=18 height=27 xoffset=-3 yoffset=2 xadvance=15 page=0 chnl=15 +char id=87 x=57 y=322 width=18 height=27 xoffset=-3 yoffset=2 xadvance=15 page=0 chnl=15 +char id=88 x=76 y=322 width=18 height=27 xoffset=-3 yoffset=2 xadvance=15 page=0 chnl=15 +char id=89 x=95 y=322 width=18 height=27 xoffset=-3 yoffset=2 xadvance=15 page=0 chnl=15 +char id=90 x=114 y=322 width=18 height=27 xoffset=-3 yoffset=2 xadvance=15 page=0 chnl=15 +char id=91 x=498 y=0 width=13 height=32 xoffset=0 yoffset=0 xadvance=15 page=0 chnl=15 +char id=92 x=0 y=264 width=18 height=30 xoffset=-3 yoffset=2 xadvance=15 page=0 chnl=15 +char id=93 x=399 y=167 width=13 height=32 xoffset=0 yoffset=0 xadvance=15 page=0 chnl=15 +char id=94 x=30 y=425 width=18 height=12 xoffset=-3 yoffset=0 xadvance=15 page=0 chnl=15 +char id=95 x=186 y=421 width=18 height=7 xoffset=-3 yoffset=25 xadvance=15 page=0 chnl=15 +char id=96 x=0 y=425 width=10 height=14 xoffset=0 yoffset=0 xadvance=15 page=0 chnl=15 +char id=97 x=360 y=397 width=18 height=19 xoffset=-3 yoffset=10 xadvance=15 page=0 chnl=15 +char id=98 x=133 y=322 width=18 height=27 xoffset=-3 yoffset=2 xadvance=15 page=0 chnl=15 +char id=99 x=341 y=399 width=18 height=19 xoffset=-3 yoffset=10 xadvance=15 page=0 chnl=15 +char id=100 x=152 y=322 width=18 height=27 xoffset=-3 yoffset=2 xadvance=15 page=0 chnl=15 +char id=101 x=284 y=401 width=18 height=19 xoffset=-3 yoffset=10 xadvance=15 page=0 chnl=15 +char id=102 x=171 y=322 width=18 height=27 xoffset=-3 yoffset=2 xadvance=15 page=0 chnl=15 +char id=103 x=260 y=376 width=18 height=24 xoffset=-3 yoffset=10 xadvance=15 page=0 chnl=15 +char id=104 x=228 y=322 width=18 height=27 xoffset=-3 yoffset=2 xadvance=15 page=0 chnl=15 +char id=105 x=450 y=262 width=13 height=29 xoffset=0 yoffset=0 xadvance=15 page=0 chnl=15 +char id=106 x=151 y=35 width=16 height=34 xoffset=-3 yoffset=0 xadvance=15 page=0 chnl=15 +char id=107 x=190 y=322 width=18 height=27 xoffset=-3 yoffset=2 xadvance=15 page=0 chnl=15 +char id=108 x=494 y=317 width=13 height=27 xoffset=0 yoffset=2 xadvance=15 page=0 chnl=15 +char id=109 x=132 y=401 width=18 height=19 xoffset=-3 yoffset=10 xadvance=15 page=0 chnl=15 +char id=110 x=151 y=401 width=18 height=19 xoffset=-3 yoffset=10 xadvance=15 page=0 chnl=15 +char id=111 x=170 y=401 width=18 height=19 xoffset=-3 yoffset=10 xadvance=15 page=0 chnl=15 +char id=112 x=279 y=376 width=18 height=24 xoffset=-3 yoffset=10 xadvance=15 page=0 chnl=15 +char id=113 x=298 y=374 width=18 height=24 xoffset=-3 yoffset=10 xadvance=15 page=0 chnl=15 +char id=114 x=189 y=401 width=18 height=19 xoffset=-3 yoffset=10 xadvance=15 page=0 chnl=15 +char id=115 x=208 y=401 width=18 height=19 xoffset=-3 yoffset=10 xadvance=15 page=0 chnl=15 +char id=116 x=209 y=322 width=18 height=27 xoffset=-3 yoffset=2 xadvance=15 page=0 chnl=15 +char id=117 x=227 y=401 width=18 height=19 xoffset=-3 yoffset=10 xadvance=15 page=0 chnl=15 +char id=118 x=246 y=401 width=18 height=19 xoffset=-3 yoffset=10 xadvance=15 page=0 chnl=15 +char id=119 x=265 y=401 width=18 height=19 xoffset=-3 yoffset=10 xadvance=15 page=0 chnl=15 +char id=120 x=303 y=399 width=18 height=19 xoffset=-3 yoffset=10 xadvance=15 page=0 chnl=15 +char id=121 x=241 y=376 width=18 height=24 xoffset=-3 yoffset=10 xadvance=15 page=0 chnl=15 +char id=122 x=322 y=399 width=18 height=19 xoffset=-3 yoffset=10 xadvance=15 page=0 chnl=15 +char id=123 x=366 y=167 width=18 height=32 xoffset=-3 yoffset=0 xadvance=15 page=0 chnl=15 +char id=124 x=413 y=167 width=8 height=32 xoffset=2 yoffset=0 xadvance=15 page=0 chnl=15 +char id=125 x=347 y=167 width=18 height=32 xoffset=-3 yoffset=0 xadvance=15 page=0 chnl=15 +char id=126 x=96 y=423 width=18 height=10 xoffset=-3 yoffset=2 xadvance=15 page=0 chnl=15 +char id=127 x=213 y=421 width=7 height=5 xoffset=-3 yoffset=29 xadvance=15 page=0 chnl=15 +char id=12289 x=127 y=421 width=10 height=10 xoffset=0 yoffset=22 xadvance=30 page=0 chnl=15 +char id=12290 x=465 y=397 width=15 height=15 xoffset=0 yoffset=17 xadvance=30 page=0 chnl=15 +char id=12300 x=317 y=374 width=16 height=24 xoffset=12 yoffset=-2 xadvance=30 page=0 chnl=15 +char id=12301 x=334 y=374 width=15 height=24 xoffset=0 yoffset=10 xadvance=30 page=0 chnl=15 +char id=12353 x=332 y=348 width=23 height=25 xoffset=2 yoffset=7 xadvance=30 page=0 chnl=15 +char id=12354 x=31 y=103 width=30 height=32 xoffset=0 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12355 x=84 y=403 width=23 height=19 xoffset=2 yoffset=10 xadvance=30 page=0 chnl=15 +char id=12356 x=130 y=376 width=30 height=24 xoffset=0 yoffset=5 xadvance=30 page=0 chnl=15 +char id=12357 x=446 y=348 width=20 height=25 xoffset=5 yoffset=7 xadvance=30 page=0 chnl=15 +char id=12358 x=488 y=68 width=23 height=32 xoffset=2 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12359 x=425 y=348 width=20 height=25 xoffset=5 yoffset=7 xadvance=30 page=0 chnl=15 +char id=12360 x=430 y=134 width=28 height=32 xoffset=0 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12361 x=158 y=350 width=26 height=25 xoffset=2 yoffset=7 xadvance=30 page=0 chnl=15 +char id=12362 x=93 y=136 width=30 height=32 xoffset=0 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12363 x=279 y=101 width=30 height=32 xoffset=0 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12364 x=217 y=134 width=30 height=32 xoffset=0 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12365 x=459 y=134 width=28 height=32 xoffset=0 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12366 x=436 y=0 width=30 height=34 xoffset=0 yoffset=-2 xadvance=30 page=0 chnl=15 +char id=12367 x=463 y=230 width=20 height=30 xoffset=5 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12368 x=474 y=198 width=28 height=30 xoffset=2 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12369 x=434 y=101 width=30 height=32 xoffset=0 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12370 x=406 y=35 width=33 height=32 xoffset=-3 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12371 x=152 y=294 width=26 height=27 xoffset=2 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12372 x=63 y=294 width=30 height=27 xoffset=0 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12373 x=87 y=169 width=28 height=32 xoffset=0 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12374 x=68 y=70 width=33 height=32 xoffset=-3 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12375 x=418 y=231 width=23 height=30 xoffset=5 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12376 x=340 y=231 width=26 height=30 xoffset=2 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12377 x=204 y=68 width=33 height=32 xoffset=-3 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12378 x=372 y=35 width=33 height=32 xoffset=-3 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12379 x=124 y=136 width=30 height=32 xoffset=0 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12380 x=304 y=35 width=33 height=32 xoffset=-3 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12381 x=133 y=202 width=30 height=30 xoffset=0 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12382 x=0 y=202 width=33 height=30 xoffset=-3 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12383 x=0 y=103 width=30 height=32 xoffset=0 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12384 x=62 y=35 width=30 height=34 xoffset=0 yoffset=-2 xadvance=30 page=0 chnl=15 +char id=12385 x=248 y=101 width=30 height=32 xoffset=0 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12386 x=340 y=0 width=33 height=34 xoffset=-3 yoffset=-2 xadvance=30 page=0 chnl=15 +char id=12387 x=34 y=404 width=23 height=20 xoffset=2 yoffset=12 xadvance=30 page=0 chnl=15 +char id=12388 x=161 y=376 width=28 height=24 xoffset=0 yoffset=5 xadvance=30 page=0 chnl=15 +char id=12389 x=422 y=167 width=30 height=31 xoffset=0 yoffset=-2 xadvance=30 page=0 chnl=15 +char id=12390 x=0 y=295 width=31 height=27 xoffset=-3 yoffset=5 xadvance=30 page=0 chnl=15 +char id=12391 x=464 y=261 width=33 height=27 xoffset=-3 yoffset=5 xadvance=30 page=0 chnl=15 +char id=12392 x=301 y=167 width=23 height=32 xoffset=2 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12393 x=122 y=35 width=28 height=34 xoffset=0 yoffset=-2 xadvance=30 page=0 chnl=15 +char id=12394 x=338 y=35 width=33 height=32 xoffset=-3 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12395 x=257 y=200 width=30 height=30 xoffset=0 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12396 x=186 y=134 width=30 height=32 xoffset=0 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12397 x=248 y=134 width=30 height=32 xoffset=0 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12398 x=481 y=345 width=30 height=24 xoffset=0 yoffset=5 xadvance=30 page=0 chnl=15 +char id=12399 x=341 y=134 width=30 height=32 xoffset=0 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12400 x=102 y=70 width=33 height=32 xoffset=-3 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12401 x=0 y=70 width=33 height=32 xoffset=-3 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12402 x=412 y=200 width=30 height=30 xoffset=0 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12403 x=426 y=68 width=30 height=32 xoffset=0 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12404 x=217 y=101 width=30 height=32 xoffset=0 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12405 x=195 y=202 width=30 height=30 xoffset=0 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12406 x=364 y=68 width=30 height=32 xoffset=0 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12407 x=333 y=68 width=30 height=32 xoffset=0 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12408 x=412 y=397 width=33 height=17 xoffset=-3 yoffset=10 xadvance=30 page=0 chnl=15 +char id=12409 x=90 y=350 width=33 height=25 xoffset=-3 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12410 x=124 y=350 width=33 height=25 xoffset=-3 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12411 x=102 y=202 width=30 height=30 xoffset=0 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12412 x=136 y=70 width=33 height=32 xoffset=-3 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12413 x=34 y=70 width=33 height=32 xoffset=-3 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12414 x=372 y=134 width=28 height=32 xoffset=0 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12415 x=453 y=167 width=33 height=30 xoffset=-3 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12416 x=372 y=101 width=30 height=32 xoffset=0 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12417 x=302 y=68 width=30 height=32 xoffset=0 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12418 x=401 y=134 width=28 height=32 xoffset=0 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12419 x=380 y=348 width=23 height=25 xoffset=2 yoffset=7 xadvance=30 page=0 chnl=15 +char id=12420 x=31 y=136 width=30 height=32 xoffset=0 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12421 x=185 y=350 width=26 height=25 xoffset=2 yoffset=7 xadvance=30 page=0 chnl=15 +char id=12422 x=62 y=136 width=30 height=32 xoffset=0 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12423 x=404 y=348 width=20 height=25 xoffset=5 yoffset=7 xadvance=30 page=0 chnl=15 +char id=12424 x=251 y=167 width=25 height=32 xoffset=0 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12425 x=143 y=169 width=26 height=32 xoffset=2 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12426 x=442 y=231 width=20 height=30 xoffset=5 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12427 x=232 y=231 width=26 height=30 xoffset=2 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12428 x=310 y=134 width=30 height=32 xoffset=0 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12429 x=286 y=231 width=26 height=30 xoffset=2 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12430 x=284 y=348 width=23 height=25 xoffset=2 yoffset=7 xadvance=30 page=0 chnl=15 +char id=12431 x=279 y=134 width=30 height=32 xoffset=0 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12432 x=381 y=200 width=30 height=30 xoffset=0 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12433 x=403 y=101 width=30 height=32 xoffset=0 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12434 x=29 y=169 width=28 height=32 xoffset=0 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12435 x=350 y=200 width=30 height=30 xoffset=0 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12436 x=93 y=35 width=28 height=34 xoffset=0 yoffset=-2 xadvance=30 page=0 chnl=15 +char id=12443 x=80 y=424 width=15 height=11 xoffset=0 yoffset=-2 xadvance=30 page=0 chnl=15 +char id=12444 x=481 y=397 width=15 height=14 xoffset=0 yoffset=-2 xadvance=30 page=0 chnl=15 +char id=12445 x=379 y=397 width=16 height=19 xoffset=7 yoffset=5 xadvance=30 page=0 chnl=15 +char id=12446 x=217 y=376 width=23 height=24 xoffset=5 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12449 x=374 y=374 width=23 height=22 xoffset=2 yoffset=10 xadvance=30 page=0 chnl=15 +char id=12450 x=319 y=200 width=30 height=30 xoffset=0 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12451 x=443 y=374 width=20 height=22 xoffset=5 yoffset=10 xadvance=30 page=0 chnl=15 +char id=12452 x=58 y=233 width=28 height=30 xoffset=0 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12453 x=308 y=348 width=23 height=25 xoffset=2 yoffset=7 xadvance=30 page=0 chnl=15 +char id=12454 x=58 y=169 width=28 height=32 xoffset=0 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12455 x=108 y=401 width=23 height=19 xoffset=2 yoffset=10 xadvance=30 page=0 chnl=15 +char id=12456 x=0 y=379 width=33 height=24 xoffset=-3 yoffset=5 xadvance=30 page=0 chnl=15 +char id=12457 x=356 y=348 width=23 height=25 xoffset=2 yoffset=7 xadvance=30 page=0 chnl=15 +char id=12458 x=155 y=136 width=30 height=32 xoffset=0 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12459 x=341 y=101 width=30 height=32 xoffset=0 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12460 x=170 y=0 width=33 height=34 xoffset=-3 yoffset=-2 xadvance=30 page=0 chnl=15 +char id=12461 x=395 y=68 width=30 height=32 xoffset=0 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12462 x=440 y=35 width=33 height=32 xoffset=-3 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12463 x=224 y=167 width=26 height=32 xoffset=2 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12464 x=0 y=35 width=30 height=34 xoffset=0 yoffset=-2 xadvance=30 page=0 chnl=15 +char id=12465 x=93 y=103 width=30 height=32 xoffset=0 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12466 x=102 y=0 width=33 height=34 xoffset=-3 yoffset=-2 xadvance=30 page=0 chnl=15 +char id=12467 x=123 y=294 width=28 height=27 xoffset=0 yoffset=5 xadvance=30 page=0 chnl=15 +char id=12468 x=374 y=0 width=30 height=34 xoffset=0 yoffset=-2 xadvance=30 page=0 chnl=15 +char id=12469 x=62 y=103 width=30 height=32 xoffset=0 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12470 x=474 y=35 width=33 height=32 xoffset=-3 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12471 x=226 y=200 width=30 height=30 xoffset=0 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12472 x=467 y=0 width=30 height=34 xoffset=0 yoffset=-2 xadvance=30 page=0 chnl=15 +char id=12473 x=288 y=200 width=30 height=30 xoffset=0 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12474 x=34 y=0 width=33 height=34 xoffset=-3 yoffset=-2 xadvance=30 page=0 chnl=15 +char id=12475 x=168 y=35 width=33 height=32 xoffset=-3 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12476 x=136 y=0 width=33 height=34 xoffset=-3 yoffset=-2 xadvance=30 page=0 chnl=15 +char id=12477 x=203 y=233 width=28 height=30 xoffset=0 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12478 x=68 y=0 width=33 height=34 xoffset=-3 yoffset=-2 xadvance=30 page=0 chnl=15 +char id=12479 x=116 y=169 width=26 height=32 xoffset=2 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12480 x=405 y=0 width=30 height=34 xoffset=0 yoffset=-2 xadvance=30 page=0 chnl=15 +char id=12481 x=68 y=202 width=33 height=30 xoffset=-3 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12482 x=170 y=68 width=33 height=32 xoffset=-3 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12483 x=398 y=374 width=23 height=22 xoffset=2 yoffset=10 xadvance=30 page=0 chnl=15 +char id=12484 x=87 y=233 width=28 height=30 xoffset=0 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12485 x=0 y=0 width=33 height=34 xoffset=-3 yoffset=-2 xadvance=30 page=0 chnl=15 +char id=12486 x=164 y=202 width=30 height=30 xoffset=0 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12487 x=306 y=0 width=33 height=34 xoffset=-3 yoffset=-2 xadvance=30 page=0 chnl=15 +char id=12488 x=488 y=134 width=23 height=32 xoffset=5 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12489 x=197 y=167 width=26 height=32 xoffset=2 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12490 x=457 y=68 width=30 height=32 xoffset=0 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12491 x=68 y=378 width=30 height=24 xoffset=0 yoffset=5 xadvance=30 page=0 chnl=15 +char id=12492 x=0 y=233 width=28 height=30 xoffset=0 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12493 x=202 y=35 width=33 height=32 xoffset=-3 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12494 x=394 y=231 width=23 height=30 xoffset=2 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12495 x=443 y=199 width=30 height=30 xoffset=0 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12496 x=124 y=103 width=30 height=32 xoffset=0 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12497 x=155 y=103 width=30 height=32 xoffset=0 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12498 x=170 y=169 width=26 height=32 xoffset=2 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12499 x=0 y=169 width=28 height=32 xoffset=2 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12500 x=186 y=101 width=30 height=32 xoffset=0 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12501 x=145 y=233 width=28 height=30 xoffset=0 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12502 x=272 y=0 width=33 height=34 xoffset=-3 yoffset=-2 xadvance=30 page=0 chnl=15 +char id=12503 x=238 y=0 width=33 height=34 xoffset=-3 yoffset=-2 xadvance=30 page=0 chnl=15 +char id=12504 x=0 y=404 width=33 height=20 xoffset=-3 yoffset=7 xadvance=30 page=0 chnl=15 +char id=12505 x=19 y=264 width=33 height=29 xoffset=-3 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12506 x=53 y=264 width=33 height=29 xoffset=-3 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12507 x=236 y=35 width=33 height=32 xoffset=-3 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12508 x=204 y=0 width=33 height=34 xoffset=-3 yoffset=-2 xadvance=30 page=0 chnl=15 +char id=12509 x=270 y=35 width=33 height=32 xoffset=-3 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12510 x=32 y=294 width=30 height=27 xoffset=0 yoffset=5 xadvance=30 page=0 chnl=15 +char id=12511 x=487 y=167 width=23 height=30 xoffset=2 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12512 x=238 y=68 width=31 height=32 xoffset=-3 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12513 x=465 y=101 width=30 height=32 xoffset=0 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12514 x=34 y=202 width=33 height=30 xoffset=-3 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12515 x=260 y=350 width=23 height=25 xoffset=2 yoffset=7 xadvance=30 page=0 chnl=15 +char id=12516 x=270 y=68 width=31 height=32 xoffset=-3 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12517 x=58 y=404 width=25 height=19 xoffset=0 yoffset=10 xadvance=30 page=0 chnl=15 +char id=12518 x=34 y=379 width=33 height=24 xoffset=-3 yoffset=5 xadvance=30 page=0 chnl=15 +char id=12519 x=422 y=374 width=20 height=22 xoffset=5 yoffset=10 xadvance=30 page=0 chnl=15 +char id=12520 x=313 y=231 width=26 height=30 xoffset=2 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12521 x=29 y=233 width=28 height=30 xoffset=0 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12522 x=277 y=167 width=23 height=32 xoffset=2 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12523 x=0 y=136 width=30 height=32 xoffset=0 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12524 x=367 y=231 width=26 height=30 xoffset=2 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12525 x=94 y=294 width=28 height=27 xoffset=0 yoffset=5 xadvance=30 page=0 chnl=15 +char id=12526 x=350 y=374 width=23 height=22 xoffset=2 yoffset=10 xadvance=30 page=0 chnl=15 +char id=12527 x=116 y=233 width=28 height=30 xoffset=0 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12528 x=310 y=101 width=30 height=32 xoffset=0 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12529 x=99 y=376 width=30 height=24 xoffset=0 yoffset=5 xadvance=30 page=0 chnl=15 +char id=12530 x=259 y=231 width=26 height=30 xoffset=2 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12531 x=174 y=233 width=28 height=30 xoffset=2 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12532 x=31 y=35 width=30 height=34 xoffset=0 yoffset=-2 xadvance=30 page=0 chnl=15 +char id=12533 x=236 y=350 width=23 height=25 xoffset=2 yoffset=7 xadvance=30 page=0 chnl=15 +char id=12534 x=212 y=350 width=23 height=25 xoffset=2 yoffset=7 xadvance=30 page=0 chnl=15 +char id=12539 x=115 y=421 width=11 height=10 xoffset=7 yoffset=12 xadvance=30 page=0 chnl=15 +char id=12540 x=138 y=421 width=28 height=9 xoffset=0 yoffset=10 xadvance=30 page=0 chnl=15 +char id=12541 x=396 y=397 width=15 height=19 xoffset=5 yoffset=5 xadvance=30 page=0 chnl=15 +char id=12542 x=190 y=376 width=26 height=24 xoffset=2 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12543 x=49 y=425 width=16 height=12 xoffset=17 yoffset=22 xadvance=30 page=0 chnl=15 +char id=65281 x=503 y=198 width=8 height=29 xoffset=10 yoffset=0 xadvance=30 page=0 chnl=15 +char id=65284 x=217 y=264 width=23 height=29 xoffset=2 yoffset=0 xadvance=30 page=0 chnl=15 +char id=65285 x=87 y=264 width=28 height=29 xoffset=0 yoffset=0 xadvance=30 page=0 chnl=15 +char id=65286 x=116 y=264 width=26 height=29 xoffset=2 yoffset=0 xadvance=30 page=0 chnl=15 +char id=65296 x=241 y=262 width=23 height=29 xoffset=2 yoffset=0 xadvance=30 page=0 chnl=15 +char id=65297 x=433 y=262 width=16 height=29 xoffset=2 yoffset=0 xadvance=30 page=0 chnl=15 +char id=65298 x=265 y=262 width=23 height=29 xoffset=2 yoffset=0 xadvance=30 page=0 chnl=15 +char id=65299 x=289 y=262 width=23 height=29 xoffset=2 yoffset=0 xadvance=30 page=0 chnl=15 +char id=65300 x=143 y=264 width=25 height=29 xoffset=0 yoffset=0 xadvance=30 page=0 chnl=15 +char id=65301 x=313 y=262 width=23 height=29 xoffset=2 yoffset=0 xadvance=30 page=0 chnl=15 +char id=65302 x=337 y=262 width=23 height=29 xoffset=2 yoffset=0 xadvance=30 page=0 chnl=15 +char id=65303 x=361 y=262 width=23 height=29 xoffset=2 yoffset=0 xadvance=30 page=0 chnl=15 +char id=65304 x=385 y=262 width=23 height=29 xoffset=2 yoffset=0 xadvance=30 page=0 chnl=15 +char id=65305 x=409 y=262 width=23 height=29 xoffset=2 yoffset=0 xadvance=30 page=0 chnl=15 +char id=65311 x=169 y=264 width=23 height=29 xoffset=2 yoffset=0 xadvance=30 page=0 chnl=15 +char id=65509 x=193 y=264 width=23 height=29 xoffset=2 yoffset=0 xadvance=30 page=0 chnl=15 diff --git a/Build/TestData/allPartsV7/font/RoundedMPlus_0.png b/Build/TestData/allPartsV7/font/RoundedMPlus_0.png new file mode 100644 index 00000000..50169632 Binary files /dev/null and b/Build/TestData/allPartsV7/font/RoundedMPlus_0.png differ diff --git a/Build/TestData/allPartsV7/font/Sample_PixelMplus12.fnt b/Build/TestData/allPartsV7/font/Sample_PixelMplus12.fnt new file mode 100644 index 00000000..e1f48793 --- /dev/null +++ b/Build/TestData/allPartsV7/font/Sample_PixelMplus12.fnt @@ -0,0 +1,214 @@ +info face="PixelMplus12" size=32 bold=0 italic=0 charset="" unicode=1 stretchH=100 smooth=1 aa=1 padding=0,0,0,0 spacing=1,1 outline=0 +common lineHeight=32 base=26 scaleW=512 scaleH=512 pages=1 packed=0 alphaChnl=0 redChnl=0 greenChnl=0 blueChnl=0 +page id=0 file="Sample_PixelMplus12_0.png" +chars count=210 +char id=13 x=332 y=255 width=12 height=15 xoffset=4 yoffset=17 xadvance=15 page=0 chnl=15 +char id=32 x=219 y=122 width=3 height=1 xoffset=-1 yoffset=31 xadvance=15 page=0 chnl=15 +char id=35 x=414 y=207 width=14 height=23 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15 +char id=45 x=434 y=252 width=14 height=3 xoffset=-1 yoffset=14 xadvance=15 page=0 chnl=15 +char id=46 x=384 y=253 width=9 height=8 xoffset=2 yoffset=19 xadvance=15 page=0 chnl=15 +char id=47 x=181 y=211 width=14 height=26 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15 +char id=48 x=399 y=207 width=14 height=23 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15 +char id=49 x=345 y=231 width=9 height=23 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15 +char id=50 x=429 y=207 width=14 height=23 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15 +char id=51 x=444 y=207 width=14 height=23 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15 +char id=52 x=459 y=207 width=14 height=23 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15 +char id=53 x=474 y=207 width=14 height=23 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15 +char id=54 x=489 y=207 width=14 height=23 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15 +char id=55 x=105 y=238 width=14 height=23 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15 +char id=56 x=15 y=238 width=14 height=23 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15 +char id=57 x=30 y=238 width=14 height=23 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15 +char id=58 x=122 y=262 width=9 height=18 xoffset=2 yoffset=9 xadvance=15 page=0 chnl=15 +char id=66 x=45 y=238 width=14 height=23 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15 +char id=69 x=60 y=238 width=14 height=23 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15 +char id=70 x=75 y=238 width=14 height=23 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15 +char id=71 x=330 y=231 width=14 height=23 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15 +char id=73 x=365 y=231 width=9 height=23 xoffset=2 yoffset=4 xadvance=15 page=0 chnl=15 +char id=76 x=120 y=238 width=14 height=23 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15 +char id=77 x=135 y=238 width=14 height=23 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15 +char id=78 x=150 y=238 width=14 height=23 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15 +char id=79 x=255 y=235 width=14 height=23 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15 +char id=80 x=165 y=238 width=14 height=23 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15 +char id=83 x=180 y=238 width=14 height=23 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15 +char id=84 x=195 y=238 width=14 height=23 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15 +char id=85 x=210 y=237 width=14 height=23 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15 +char id=86 x=0 y=238 width=14 height=23 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15 +char id=87 x=270 y=235 width=14 height=23 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15 +char id=88 x=285 y=235 width=14 height=23 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15 +char id=95 x=419 y=252 width=14 height=3 xoffset=-1 yoffset=27 xadvance=15 page=0 chnl=15 +char id=97 x=227 y=261 width=14 height=15 xoffset=-1 yoffset=12 xadvance=15 page=0 chnl=15 +char id=99 x=212 y=261 width=14 height=15 xoffset=-1 yoffset=12 xadvance=15 page=0 chnl=15 +char id=100 x=300 y=231 width=14 height=23 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15 +char id=101 x=182 y=262 width=14 height=15 xoffset=-1 yoffset=12 xadvance=15 page=0 chnl=15 +char id=102 x=315 y=231 width=14 height=23 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15 +char id=104 x=240 y=235 width=14 height=23 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15 +char id=105 x=226 y=211 width=9 height=25 xoffset=2 yoffset=2 xadvance=15 page=0 chnl=15 +char id=107 x=90 y=238 width=14 height=23 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15 +char id=108 x=355 y=231 width=9 height=23 xoffset=2 yoffset=4 xadvance=15 page=0 chnl=15 +char id=109 x=317 y=255 width=14 height=15 xoffset=-1 yoffset=12 xadvance=15 page=0 chnl=15 +char id=110 x=197 y=262 width=14 height=15 xoffset=-1 yoffset=12 xadvance=15 page=0 chnl=15 +char id=111 x=242 y=259 width=14 height=15 xoffset=-1 yoffset=12 xadvance=15 page=0 chnl=15 +char id=112 x=25 y=262 width=14 height=20 xoffset=-1 yoffset=12 xadvance=15 page=0 chnl=15 +char id=114 x=272 y=259 width=14 height=15 xoffset=-1 yoffset=12 xadvance=15 page=0 chnl=15 +char id=115 x=257 y=259 width=14 height=15 xoffset=-1 yoffset=12 xadvance=15 page=0 chnl=15 +char id=116 x=225 y=237 width=14 height=23 xoffset=-1 yoffset=4 xadvance=15 page=0 chnl=15 +char id=117 x=287 y=259 width=14 height=15 xoffset=-1 yoffset=12 xadvance=15 page=0 chnl=15 +char id=119 x=302 y=255 width=14 height=15 xoffset=-1 yoffset=12 xadvance=15 page=0 chnl=15 +char id=121 x=493 y=231 width=14 height=20 xoffset=-1 yoffset=12 xadvance=15 page=0 chnl=15 +char id=8224 x=204 y=93 width=14 height=30 xoffset=7 yoffset=0 xadvance=30 page=0 chnl=15 +char id=8240 x=196 y=211 width=29 height=25 xoffset=-1 yoffset=2 xadvance=30 page=0 chnl=15 +char id=8242 x=374 y=255 width=9 height=8 xoffset=2 yoffset=2 xadvance=30 page=0 chnl=15 +char id=8243 x=357 y=255 width=16 height=8 xoffset=2 yoffset=2 xadvance=30 page=0 chnl=15 +char id=8594 x=236 y=211 width=29 height=23 xoffset=-1 yoffset=4 xadvance=30 page=0 chnl=15 +char id=8765 x=152 y=262 width=29 height=15 xoffset=-1 yoffset=7 xadvance=30 page=0 chnl=15 +char id=8807 x=351 y=207 width=24 height=23 xoffset=2 yoffset=4 xadvance=30 page=0 chnl=15 +char id=12289 x=504 y=151 width=6 height=6 xoffset=2 yoffset=24 xadvance=30 page=0 chnl=15 +char id=12290 x=345 y=255 width=11 height=11 xoffset=2 yoffset=19 xadvance=30 page=0 chnl=15 +char id=12300 x=40 y=262 width=12 height=20 xoffset=14 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12301 x=53 y=262 width=11 height=20 xoffset=2 yoffset=12 xadvance=30 page=0 chnl=15 +char id=12354 x=315 y=151 width=26 height=28 xoffset=2 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12356 x=412 y=231 width=26 height=20 xoffset=2 yoffset=7 xadvance=30 page=0 chnl=15 +char id=12358 x=219 y=182 width=19 height=28 xoffset=4 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12362 x=342 y=151 width=26 height=28 xoffset=2 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12363 x=369 y=151 width=26 height=28 xoffset=2 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12364 x=396 y=151 width=26 height=28 xoffset=2 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12365 x=27 y=182 width=24 height=28 xoffset=2 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12366 x=150 y=93 width=26 height=30 xoffset=2 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12367 x=164 y=211 width=16 height=26 xoffset=7 yoffset=4 xadvance=30 page=0 chnl=15 +char id=12371 x=376 y=207 width=22 height=23 xoffset=4 yoffset=4 xadvance=30 page=0 chnl=15 +char id=12373 x=77 y=182 width=24 height=28 xoffset=2 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12375 x=127 y=211 width=19 height=26 xoffset=7 yoffset=4 xadvance=30 page=0 chnl=15 +char id=12377 x=270 y=122 width=29 height=28 xoffset=-1 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12381 x=432 y=180 width=26 height=26 xoffset=2 yoffset=4 xadvance=30 page=0 chnl=15 +char id=12383 x=207 y=153 width=26 height=28 xoffset=2 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12387 x=132 y=262 width=19 height=16 xoffset=4 yoffset=14 xadvance=30 page=0 chnl=15 +char id=12388 x=0 y=262 width=24 height=20 xoffset=2 yoffset=7 xadvance=30 page=0 chnl=15 +char id=12390 x=296 y=207 width=27 height=23 xoffset=-1 yoffset=7 xadvance=30 page=0 chnl=15 +char id=12391 x=266 y=211 width=29 height=23 xoffset=-1 yoffset=7 xadvance=30 page=0 chnl=15 +char id=12392 x=199 y=182 width=19 height=28 xoffset=4 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12395 x=324 y=180 width=26 height=26 xoffset=2 yoffset=4 xadvance=30 page=0 chnl=15 +char id=12398 x=466 y=231 width=26 height=20 xoffset=2 yoffset=7 xadvance=30 page=0 chnl=15 +char id=12399 x=423 y=151 width=26 height=28 xoffset=2 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12402 x=27 y=211 width=26 height=26 xoffset=2 yoffset=4 xadvance=30 page=0 chnl=15 +char id=12403 x=450 y=151 width=26 height=28 xoffset=2 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12414 x=152 y=182 width=24 height=28 xoffset=2 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12418 x=127 y=182 width=24 height=28 xoffset=2 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12423 x=395 y=231 width=16 height=21 xoffset=7 yoffset=9 xadvance=30 page=0 chnl=15 +char id=12424 x=177 y=182 width=21 height=28 xoffset=2 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12425 x=489 y=93 width=22 height=28 xoffset=4 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12426 x=147 y=211 width=16 height=26 xoffset=7 yoffset=4 xadvance=30 page=0 chnl=15 +char id=12427 x=104 y=211 width=22 height=26 xoffset=4 yoffset=4 xadvance=30 page=0 chnl=15 +char id=12428 x=477 y=151 width=26 height=28 xoffset=2 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12434 x=102 y=182 width=24 height=28 xoffset=2 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12449 x=65 y=262 width=19 height=18 xoffset=4 yoffset=12 xadvance=30 page=0 chnl=15 +char id=12450 x=459 y=180 width=26 height=26 xoffset=2 yoffset=4 xadvance=30 page=0 chnl=15 +char id=12452 x=79 y=211 width=24 height=26 xoffset=2 yoffset=4 xadvance=30 page=0 chnl=15 +char id=12457 x=375 y=231 width=19 height=21 xoffset=4 yoffset=9 xadvance=30 page=0 chnl=15 +char id=12458 x=0 y=182 width=26 height=28 xoffset=2 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12461 x=180 y=153 width=26 height=28 xoffset=2 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12471 x=0 y=211 width=26 height=26 xoffset=2 yoffset=4 xadvance=30 page=0 chnl=15 +char id=12473 x=405 y=180 width=26 height=26 xoffset=2 yoffset=4 xadvance=30 page=0 chnl=15 +char id=12483 x=85 y=262 width=19 height=18 xoffset=4 yoffset=12 xadvance=30 page=0 chnl=15 +char id=12486 x=351 y=180 width=26 height=26 xoffset=2 yoffset=4 xadvance=30 page=0 chnl=15 +char id=12488 x=239 y=182 width=19 height=28 xoffset=7 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12491 x=439 y=231 width=26 height=20 xoffset=2 yoffset=7 xadvance=30 page=0 chnl=15 +char id=12495 x=378 y=180 width=26 height=26 xoffset=2 yoffset=4 xadvance=30 page=0 chnl=15 +char id=12499 x=52 y=182 width=24 height=28 xoffset=4 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12501 x=486 y=180 width=24 height=26 xoffset=2 yoffset=4 xadvance=30 page=0 chnl=15 +char id=12503 x=30 y=31 width=29 height=30 xoffset=-1 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12510 x=324 y=207 width=26 height=23 xoffset=2 yoffset=7 xadvance=30 page=0 chnl=15 +char id=12513 x=234 y=153 width=26 height=28 xoffset=2 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12514 x=294 y=180 width=29 height=26 xoffset=-1 yoffset=4 xadvance=30 page=0 chnl=15 +char id=12519 x=105 y=262 width=16 height=18 xoffset=7 yoffset=12 xadvance=30 page=0 chnl=15 +char id=12522 x=259 y=182 width=19 height=28 xoffset=4 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12523 x=261 y=151 width=26 height=28 xoffset=2 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12531 x=54 y=211 width=24 height=26 xoffset=4 yoffset=4 xadvance=30 page=0 chnl=15 +char id=12532 x=177 y=93 width=26 height=30 xoffset=2 yoffset=0 xadvance=30 page=0 chnl=15 +char id=12540 x=394 y=253 width=24 height=5 xoffset=2 yoffset=12 xadvance=30 page=0 chnl=15 +char id=12849 x=60 y=153 width=29 height=28 xoffset=-1 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12850 x=90 y=124 width=29 height=28 xoffset=-1 yoffset=2 xadvance=30 page=0 chnl=15 +char id=12857 x=60 y=124 width=29 height=28 xoffset=-1 yoffset=2 xadvance=30 page=0 chnl=15 +char id=13110 x=420 y=122 width=29 height=28 xoffset=-1 yoffset=2 xadvance=30 page=0 chnl=15 +char id=19990 x=120 y=0 width=29 height=30 xoffset=-1 yoffset=0 xadvance=30 page=0 chnl=15 +char id=20445 x=120 y=153 width=29 height=28 xoffset=-1 yoffset=2 xadvance=30 page=0 chnl=15 +char id=20559 x=30 y=153 width=29 height=28 xoffset=-1 yoffset=2 xadvance=30 page=0 chnl=15 +char id=20919 x=150 y=153 width=29 height=28 xoffset=-1 yoffset=2 xadvance=30 page=0 chnl=15 +char id=21205 x=30 y=0 width=29 height=30 xoffset=-1 yoffset=0 xadvance=30 page=0 chnl=15 +char id=21280 x=330 y=122 width=29 height=28 xoffset=-1 yoffset=2 xadvance=30 page=0 chnl=15 +char id=21442 x=330 y=62 width=29 height=30 xoffset=-1 yoffset=0 xadvance=30 page=0 chnl=15 +char id=21514 x=90 y=153 width=29 height=28 xoffset=-1 yoffset=2 xadvance=30 page=0 chnl=15 +char id=22633 x=270 y=62 width=29 height=30 xoffset=-1 yoffset=0 xadvance=30 page=0 chnl=15 +char id=22799 x=0 y=153 width=29 height=28 xoffset=-1 yoffset=2 xadvance=30 page=0 chnl=15 +char id=22806 x=240 y=62 width=29 height=30 xoffset=-1 yoffset=0 xadvance=30 page=0 chnl=15 +char id=23384 x=30 y=62 width=29 height=30 xoffset=-1 yoffset=0 xadvance=30 page=0 chnl=15 +char id=23450 x=420 y=31 width=29 height=30 xoffset=-1 yoffset=0 xadvance=30 page=0 chnl=15 +char id=23550 x=300 y=31 width=29 height=30 xoffset=-1 yoffset=0 xadvance=30 page=0 chnl=15 +char id=24066 x=150 y=31 width=29 height=30 xoffset=-1 yoffset=0 xadvance=30 page=0 chnl=15 +char id=24195 x=120 y=31 width=29 height=30 xoffset=-1 yoffset=0 xadvance=30 page=0 chnl=15 +char id=24213 x=90 y=31 width=29 height=30 xoffset=-1 yoffset=0 xadvance=30 page=0 chnl=15 +char id=24540 x=60 y=31 width=29 height=30 xoffset=-1 yoffset=0 xadvance=30 page=0 chnl=15 +char id=24915 x=180 y=124 width=29 height=28 xoffset=-1 yoffset=2 xadvance=30 page=0 chnl=15 +char id=24931 x=150 y=124 width=29 height=28 xoffset=-1 yoffset=2 xadvance=30 page=0 chnl=15 +char id=24936 x=120 y=124 width=29 height=28 xoffset=-1 yoffset=2 xadvance=30 page=0 chnl=15 +char id=24944 x=180 y=0 width=29 height=30 xoffset=-1 yoffset=0 xadvance=30 page=0 chnl=15 +char id=24950 x=90 y=0 width=29 height=30 xoffset=-1 yoffset=0 xadvance=30 page=0 chnl=15 +char id=25351 x=390 y=122 width=29 height=28 xoffset=-1 yoffset=2 xadvance=30 page=0 chnl=15 +char id=25449 x=360 y=122 width=29 height=28 xoffset=-1 yoffset=2 xadvance=30 page=0 chnl=15 +char id=25454 x=300 y=122 width=29 height=28 xoffset=-1 yoffset=2 xadvance=30 page=0 chnl=15 +char id=25551 x=60 y=0 width=29 height=30 xoffset=-1 yoffset=0 xadvance=30 page=0 chnl=15 +char id=25705 x=120 y=93 width=29 height=30 xoffset=-1 yoffset=0 xadvance=30 page=0 chnl=15 +char id=25711 x=90 y=93 width=29 height=30 xoffset=-1 yoffset=0 xadvance=30 page=0 chnl=15 +char id=25955 x=60 y=93 width=29 height=30 xoffset=-1 yoffset=0 xadvance=30 page=0 chnl=15 +char id=25964 x=30 y=93 width=29 height=30 xoffset=-1 yoffset=0 xadvance=30 page=0 chnl=15 +char id=25970 x=330 y=0 width=29 height=30 xoffset=-1 yoffset=0 xadvance=30 page=0 chnl=15 +char id=25973 x=0 y=93 width=29 height=30 xoffset=-1 yoffset=0 xadvance=30 page=0 chnl=15 +char id=26032 x=480 y=62 width=29 height=30 xoffset=-1 yoffset=0 xadvance=30 page=0 chnl=15 +char id=26041 x=450 y=62 width=29 height=30 xoffset=-1 yoffset=0 xadvance=30 page=0 chnl=15 +char id=26144 x=420 y=62 width=29 height=30 xoffset=-1 yoffset=0 xadvance=30 page=0 chnl=15 +char id=26214 x=390 y=62 width=29 height=30 xoffset=-1 yoffset=0 xadvance=30 page=0 chnl=15 +char id=26223 x=450 y=122 width=29 height=28 xoffset=-1 yoffset=2 xadvance=30 page=0 chnl=15 +char id=26356 x=210 y=124 width=29 height=28 xoffset=-1 yoffset=2 xadvance=30 page=0 chnl=15 +char id=26412 x=360 y=62 width=29 height=30 xoffset=-1 yoffset=0 xadvance=30 page=0 chnl=15 +char id=26465 x=480 y=122 width=29 height=28 xoffset=-1 yoffset=2 xadvance=30 page=0 chnl=15 +char id=26691 x=0 y=62 width=29 height=30 xoffset=-1 yoffset=0 xadvance=30 page=0 chnl=15 +char id=26723 x=300 y=62 width=29 height=30 xoffset=-1 yoffset=0 xadvance=30 page=0 chnl=15 +char id=26727 x=30 y=124 width=29 height=28 xoffset=-1 yoffset=2 xadvance=30 page=0 chnl=15 +char id=26740 x=0 y=124 width=29 height=28 xoffset=-1 yoffset=2 xadvance=30 page=0 chnl=15 +char id=26862 x=210 y=62 width=29 height=30 xoffset=-1 yoffset=0 xadvance=30 page=0 chnl=15 +char id=26999 x=180 y=62 width=29 height=30 xoffset=-1 yoffset=0 xadvance=30 page=0 chnl=15 +char id=27231 x=150 y=62 width=29 height=30 xoffset=-1 yoffset=0 xadvance=30 page=0 chnl=15 +char id=27746 x=120 y=62 width=29 height=30 xoffset=-1 yoffset=0 xadvance=30 page=0 chnl=15 +char id=27861 x=90 y=62 width=29 height=30 xoffset=-1 yoffset=0 xadvance=30 page=0 chnl=15 +char id=27874 x=60 y=62 width=29 height=30 xoffset=-1 yoffset=0 xadvance=30 page=0 chnl=15 +char id=28020 x=459 y=93 width=29 height=28 xoffset=-1 yoffset=2 xadvance=30 page=0 chnl=15 +char id=28271 x=240 y=122 width=29 height=28 xoffset=-1 yoffset=2 xadvance=30 page=0 chnl=15 +char id=28448 x=480 y=31 width=29 height=30 xoffset=-1 yoffset=0 xadvance=30 page=0 chnl=15 +char id=28518 x=450 y=31 width=29 height=30 xoffset=-1 yoffset=0 xadvance=30 page=0 chnl=15 +char id=28525 x=429 y=93 width=29 height=28 xoffset=-1 yoffset=2 xadvance=30 page=0 chnl=15 +char id=28536 x=270 y=31 width=29 height=30 xoffset=-1 yoffset=0 xadvance=30 page=0 chnl=15 +char id=29281 x=390 y=31 width=29 height=30 xoffset=-1 yoffset=0 xadvance=30 page=0 chnl=15 +char id=29287 x=360 y=31 width=29 height=30 xoffset=-1 yoffset=0 xadvance=30 page=0 chnl=15 +char id=29554 x=330 y=31 width=29 height=30 xoffset=-1 yoffset=0 xadvance=30 page=0 chnl=15 +char id=29796 x=399 y=93 width=29 height=28 xoffset=-1 yoffset=2 xadvance=30 page=0 chnl=15 +char id=29801 x=240 y=31 width=29 height=30 xoffset=-1 yoffset=0 xadvance=30 page=0 chnl=15 +char id=29807 x=210 y=31 width=29 height=30 xoffset=-1 yoffset=0 xadvance=30 page=0 chnl=15 +char id=29811 x=180 y=31 width=29 height=30 xoffset=-1 yoffset=0 xadvance=30 page=0 chnl=15 +char id=30011 x=369 y=93 width=29 height=28 xoffset=-1 yoffset=2 xadvance=30 page=0 chnl=15 +char id=30028 x=339 y=93 width=29 height=28 xoffset=-1 yoffset=2 xadvance=30 page=0 chnl=15 +char id=30496 x=309 y=93 width=29 height=28 xoffset=-1 yoffset=2 xadvance=30 page=0 chnl=15 +char id=30752 x=279 y=93 width=29 height=28 xoffset=-1 yoffset=2 xadvance=30 page=0 chnl=15 +char id=31337 x=249 y=93 width=29 height=28 xoffset=-1 yoffset=2 xadvance=30 page=0 chnl=15 +char id=32771 x=0 y=31 width=29 height=30 xoffset=-1 yoffset=0 xadvance=30 page=0 chnl=15 +char id=33021 x=480 y=0 width=29 height=30 xoffset=-1 yoffset=0 xadvance=30 page=0 chnl=15 +char id=33152 x=450 y=0 width=29 height=30 xoffset=-1 yoffset=0 xadvance=30 page=0 chnl=15 +char id=33251 x=288 y=151 width=26 height=28 xoffset=2 yoffset=2 xadvance=30 page=0 chnl=15 +char id=33507 x=420 y=0 width=29 height=30 xoffset=-1 yoffset=0 xadvance=30 page=0 chnl=15 +char id=33609 x=390 y=0 width=29 height=30 xoffset=-1 yoffset=0 xadvance=30 page=0 chnl=15 +char id=34946 x=360 y=0 width=29 height=30 xoffset=-1 yoffset=0 xadvance=30 page=0 chnl=15 +char id=36215 x=0 y=0 width=29 height=30 xoffset=-1 yoffset=0 xadvance=30 page=0 chnl=15 +char id=36930 x=300 y=0 width=29 height=30 xoffset=-1 yoffset=0 xadvance=30 page=0 chnl=15 +char id=37066 x=270 y=0 width=29 height=30 xoffset=-1 yoffset=0 xadvance=30 page=0 chnl=15 +char id=38738 x=240 y=0 width=29 height=30 xoffset=-1 yoffset=0 xadvance=30 page=0 chnl=15 +char id=38785 x=210 y=0 width=29 height=30 xoffset=-1 yoffset=0 xadvance=30 page=0 chnl=15 +char id=39080 x=219 y=93 width=29 height=28 xoffset=-1 yoffset=2 xadvance=30 page=0 chnl=15 +char id=39166 x=150 y=0 width=29 height=30 xoffset=-1 yoffset=0 xadvance=30 page=0 chnl=15 diff --git a/Build/TestData/allPartsV7/font/Sample_PixelMplus12_0.png b/Build/TestData/allPartsV7/font/Sample_PixelMplus12_0.png new file mode 100644 index 00000000..d83df46b Binary files /dev/null and b/Build/TestData/allPartsV7/font/Sample_PixelMplus12_0.png differ diff --git a/Build/TestData/allPartsV7/instanse.ssae b/Build/TestData/allPartsV7/instanse.ssae new file mode 100644 index 00000000..b3a8c60b --- /dev/null +++ b/Build/TestData/allPartsV7/instanse.ssae @@ -0,0 +1,170 @@ + + + + 30 + 11 + prio + 320 320 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 10 + 0 + + instanse + + + + + root + 0 + -1 + null + none + self + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + null_anime_1 + 1 + 0 + instance + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + null + anime_1 + mix + 1 + 0 + 0 + 1 + + 1 + + + + + + + + + Setup + 1 + + 60 + 1 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 0 + 0 + + + 1 + + + root + + + + 0 + + + + + + + + anime_1 + 1 + + 60 + 60 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 59 + 0 + + + 0 + + + root + + + + 0 + + + + + + null_anime_1 + + + + 20.3333320617676 + + + + + -0.333333015441895 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + + + diff --git a/Build/TestData/allPartsV7/mask.ssae b/Build/TestData/allPartsV7/mask.ssae new file mode 100644 index 00000000..ee4e18ed --- /dev/null +++ b/Build/TestData/allPartsV7/mask.ssae @@ -0,0 +1,1057 @@ + + + + 30 + 11 + prio + 320 320 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 10 + + + + 1 + 0 0 + 0 0 + 0 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + 0 + + mask + + + + + root + 0 + -1 + null + none + self + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_11 + 1 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_2 + 2 + 0 + mask + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_3 + 3 + 0 + mask + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_4 + 4 + 0 + mask + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_5 + 5 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_6 + 6 + 0 + mask + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_7 + 7 + 0 + mask + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_8 + 8 + 0 + mask + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_9 + 9 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + + + + + color_bar.ssce + + + + Setup + 1 + + 60 + 1 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + 0 + + + 1 + + + root + + + + 0 + + + + + + + + anime_1 + 1 + + 60 + 60 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 59 + + + + 1 + 0 0 + 0 0 + 0 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + 0 + + + 0 + + + root + + + + 0 + + + + + + NewCell_11 + + + + + 0 + NewCell_11 + + + + + + -5.33334350585938 + + + + + -4.66666793823242 + + + + + 0 + + + + + 2 + + + + + 2 + + + + + 0 + + + + + 0 + + + + + + NewCell_2 + + + + + 0 + NewCell_2 + + + + + + -3.33334350585938 + + + + + -6.66666412353516 + + + + + 0 + + + + + 1 + + + + + 1 + + + + + 0 + + + + + 0 + + + + + 0 + + + 255 + + + + + + NewCell_3 + + + + + 0 + NewCell_2 + + + + + + -148.33332824707 + + + + + 125 + + + + + 0 + + + + + 10 + + + + + 0 + + + + + 255 + + + + + + NewCell_4 + + + + + 0 + NewCell_2 + + + + + + -112 + + + + + 106.333335876465 + + + + + 0 + + + + + 10 + + + + + 0 + + + + + 255 + + + + + + NewCell_5 + + + + + 0 + NewCell_5 + + + + + + -132 + + + + + 117.33332824707 + + + + + 0 + + + + + 2.10416650772095 + + + + + 1.45833349227905 + + + + + 0 + + + + + 0 + + + + + + NewCell_6 + + + + + 0 + NewCell_2 + + + + + + -244.5 + + + -244.5 + + + -244.5 + + + -244.5 + + + -244.5 + + + -244.5 + + + -244.5 + + + + + -19 + + + -19 + + + -19 + + + -19 + + + -19 + + + -19 + + + -19 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 10 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + 1 + + + 0 + + + 0 + + + 1 + + + 0 + + + 1 + + + + + 255 + + + + + + NewCell_7 + + + + + 0 + NewCell_2 + + + + + + -214.5 + + + -214.5 + + + -214.5 + + + -214.5 + + + -214.5 + + + -214.5 + + + -214.5 + + + + + -42 + + + -42 + + + -42 + + + -42 + + + -42 + + + -42 + + + -42 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 20 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + 0 + + + 1 + + + 0 + + + 1 + + + 1 + + + 0 + + + + + 255 + + + + + + NewCell_8 + + + + + 0 + NewCell_2 + + + + + + -185.5 + + + -185.5 + + + -185.5 + + + -185.5 + + + -185.5 + + + -185.5 + + + -185.5 + + + + + -68 + + + -68 + + + -68 + + + -68 + + + -68 + + + -68 + + + -68 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 30 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + 0 + + + 0 + + + 1 + + + 0 + + + 1 + + + 1 + + + + + 255 + + + + + + NewCell_9 + + + + + 0 + NewCell_3 + + + + + + -220.5 + + + + + -56 + + + + + 0 + + + + + 3.09374976158142 + + + + + 3.43750023841858 + + + + + -1 + + + + + 0 + + + + + + + + diff --git a/Build/TestData/allPartsV7/mesh.ssae b/Build/TestData/allPartsV7/mesh.ssae new file mode 100644 index 00000000..bf48615d --- /dev/null +++ b/Build/TestData/allPartsV7/mesh.ssae @@ -0,0 +1,1147 @@ + + + + 30 + 11 + prio + 320 320 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 10 + 0 + + mesh + + + + + root + 0 + -1 + null + none + self + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + joint_1 + 1 + 0 + joint + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + bone_1 + 2 + 1 + armature + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + FFFF0000 + + 64 + 0 0 + 90 + 1 + + + bone_2 + 3 + 2 + armature + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + FFFF007F + + 64 + 64 0 + 0 + 1 + + + bone_3 + 4 + 3 + armature + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + FFFF00FF + + 64 + 64 0 + 0 + 1 + + + bone_4 + 5 + 4 + armature + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + FFBF00FF + + 64 + 64 0 + 0 + 1 + + + NewCell_17 + 6 + 1 + mesh + none + parent + 0 + 3 + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + joint_2 + 7 + 0 + joint + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + bone_5 + 8 + 7 + armature + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + FFFF0000 + + 64 + 0 0 + 90 + 1 + + + bone_6 + 9 + 8 + armature + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + FFFF007F + + 64 + 64 0 + 0 + 1 + + + bone_7 + 10 + 9 + armature + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + FFFF00FF + + 64 + 64 0 + 0 + 1 + + + bone_8 + 11 + 10 + armature + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + FFBF00FF + + 64 + 64 0 + 0 + 1 + + + NewCell_18 + 12 + 7 + mesh + none + parent + 0 + 3 + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + joint_3 + 13 + 0 + joint + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_19 + 14 + 13 + mesh + none + parent + 0 + 3 + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + + + 4 0 58 1.67 130.33 1 28 -62.33 130.33 2 10 -126.33 130.33 3 4 -190.33 130.33,4 0 21 86.54 61.62 1 65 22.54 61.62 2 12 -41.46 61.62 3 2 -105.46 61.62,2 0 99 1.67 1.00 1 1 -62.33 1.00,4 0 15 131.00 130.33 1 33 67.00 130.33 2 35 3.00 130.33 3 17 -61.00 130.33,4 0 1 199.71 65.67 1 6 135.71 65.67 2 38 71.71 65.67 3 55 7.71 65.67,3 1 15 71.04 5.04 2 84 7.04 5.04 3 1 -56.96 5.04,4 0 19 86.54 -55.58 1 70 22.54 -55.58 2 10 -41.46 -55.58 3 1 -105.46 -55.58,4 0 59 1.67 -128.33 1 27 -62.33 -128.33 2 10 -126.33 -128.33 3 4 -190.33 -128.33,4 0 15 131.00 -128.33 1 33 67.00 -128.33 2 35 3.00 -128.33 3 17 -61.00 -128.33,4 0 1 199.71 -55.58 1 4 135.71 -55.58 2 36 71.71 -55.58 3 59 7.71 -55.58,4 0 4 260.33 -128.33 1 10 196.33 -128.33 2 27 132.33 -128.33 3 59 68.33 -128.33,2 2 2 132.33 1.00 3 98 68.33 1.00,4 0 4 260.33 130.33 1 10 196.33 130.33 2 27 132.33 130.33 3 59 68.33 130.33, + 4 4 58 1.67 130.33 5 28 -62.33 130.33 6 10 -126.33 130.33 7 4 -190.33 130.33,4 4 21 86.54 61.62 5 65 22.54 61.62 6 12 -41.46 61.62 7 2 -105.46 61.62,2 4 99 1.67 1.00 5 1 -62.33 1.00,4 4 15 131.00 130.33 5 33 67.00 130.33 6 35 3.00 130.33 7 17 -61.00 130.33,4 4 1 199.71 65.67 5 6 135.71 65.67 6 38 71.71 65.67 7 55 7.71 65.67,3 5 15 71.04 5.04 6 84 7.04 5.04 7 1 -56.96 5.04,4 4 19 86.54 -55.58 5 70 22.54 -55.58 6 10 -41.46 -55.58 7 1 -105.46 -55.58,4 4 59 1.67 -128.33 5 27 -62.33 -128.33 6 10 -126.33 -128.33 7 4 -190.33 -128.33,4 4 15 131.00 -128.33 5 33 67.00 -128.33 6 35 3.00 -128.33 7 17 -61.00 -128.33,4 4 1 199.71 -55.58 5 4 135.71 -55.58 6 36 71.71 -55.58 7 59 7.71 -55.58,4 4 4 260.33 -128.33 5 10 196.33 -128.33 6 27 132.33 -128.33 7 59 68.33 -128.33,2 6 2 132.33 1.00 7 98 68.33 1.00,4 4 4 260.33 130.33 5 10 196.33 130.33 6 27 132.33 130.33 7 59 68.33 130.33, + 0,0,0,0,0,0,0,0,0,0,0,0,0, + + + + color_bar.ssce + + + + Setup + 1 + + 60 + 1 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 0 + 0 + + + 1 + + + root + + + + 0 + + + + + + joint_1 + + + + -289.666656494141 + + + + + -1.66666793823242 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + bone_1 + + + + 0 + + + + + 0 + + + + + + bone_2 + + + + 0 + + + + + 0 + + + + + + bone_3 + + + + 0 + + + + + 0 + + + + + + bone_4 + + + + 0 + + + + + 0 + + + + + + NewCell_17 + + + + + 0 + NewCell_17 + + + + + + -1 + + + + + 131 + + + + + 0 + + + + + 4.04166698455811 + + + + + 4.04166698455811 + + + + + 0 + + + + + 0 + + + + + + joint_2 + + + + 267.333343505859 + + + + + -0.666667938232422 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + bone_5 + + + + 0 + + + + + 0 + + + + + + bone_6 + + + + 0 + + + + + 0 + + + + + + bone_7 + + + + 0 + + + + + 0 + + + + + + bone_8 + + + + 0 + + + + + 0 + + + + + + NewCell_18 + + + + + 0 + NewCell_17 + + + + + + -1 + + + + + 131 + + + + + 0 + + + + + 4.04166698455811 + + + + + 4.04166698455811 + + + + + 0 + + + + + 0 + + + + + + joint_3 + + + + -302.5 + + + + + -180 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + NewCell_19 + + + + + 0 + NewCell_17 + + + + + + 0 + + + + + -13 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + + + anime_1 + 1 + + 60 + 60 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 59 + 0 + + + 0 + + + root + + + + 0 + + + + + + bone_1 + + + + 0 + + + + + 0 + + + + + 90 + + + + + 0 + + + + + 0 + + + + + + bone_2 + + + + 64 + + + + + 0 + + + + + 0 + + + -29.1119689941406 + + + + + 0 + + + + + 0 + + + + + + bone_3 + + + + 64 + + + + + 0 + + + + + 0 + + + -38.9464950561523 + + + + + 0 + + + + + 0 + + + + + + bone_4 + + + + 64 + + + + + 0 + + + + + 0 + + + -49.1447525024414 + + + + + 0 + + + + + 0 + + + + + + bone_5 + + + + 0 + + + + + 0 + + + + + 90 + + + + + 1 + + + 0.588107645511627 + + + + + 1 + + + 1 + + + + + 0 + + + + + 0 + + + + + + bone_6 + + + + 64 + + + + + 0 + + + + + 0 + + + + + 1 + + + 0.477430582046509 + + + + + 1 + + + 1 + + + + + 0 + + + + + 0 + + + + + + bone_7 + + + + 64 + + + + + 0 + + + + + 0 + + + + + 1 + + + 2.39090895652771 + + + + + 1 + + + 1 + + + + + 0 + + + + + 0 + + + + + + bone_8 + + + + 64 + + + + + 0 + + + + + 0 + + + + + 1 + + + 1 + + + + + 1 + + + 3.87152647972107 + + + + + 0 + + + + + 0 + + + + + + + + diff --git a/Build/TestData/allPartsV7/nineslice.ssae b/Build/TestData/allPartsV7/nineslice.ssae new file mode 100644 index 00000000..31d7182f --- /dev/null +++ b/Build/TestData/allPartsV7/nineslice.ssae @@ -0,0 +1,257 @@ + + + + 30 + 11 + prio + 320 320 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 10 + + + + 1 + 0 0 + 0 0 + 0 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + 0 + + nineslice + + + + + root + 0 + -1 + null + none + self + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + 1 + + + nineslice_1 + 1 + 0 + nines + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 20 + 20 + 20 + 20 + 0 + 0 + 1 + 0 + 0 + 1 + + 1 + 1 + + + + + + + 9slice_64.ssce + + + + Setup + 1 + + 60 + 1 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + 0 + + + + 1 + + + root + + + + 0 + + + + + + nineslice_1 + + + + + 0 + 9slice_64 + + + + + + + + + anime_1 + 1 + + 60 + 60 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 59 + + + + 1 + 0 0 + 0 0 + 0 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + 0 + + + + 0 + + + root + + + + 0 + + + + + + nineslice_1 + + + + 0 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + 64 + + + 332 + + + + + 64 + + + 174 + + + + + + + + diff --git a/Build/TestData/allPartsV7/normal.ssae b/Build/TestData/allPartsV7/normal.ssae new file mode 100644 index 00000000..01eb9988 --- /dev/null +++ b/Build/TestData/allPartsV7/normal.ssae @@ -0,0 +1,1208 @@ + + + + 30 + 11 + prio + 320 320 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 10 + 0 + + normal + + + + + root + 0 + -1 + null + none + self + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_9 + 1 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_10 + 2 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mul + 1 + 0 + 0 + 1 + + 1 + + + NewCell_11 + 3 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + add + 1 + 0 + 0 + 1 + + 1 + + + NewCell_12 + 4 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + sub + 1 + 0 + 0 + 1 + + 1 + + + NewCell_13 + 5 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mulalpha + 1 + 0 + 0 + 1 + + 1 + + + NewCell_14 + 6 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + screen + 1 + 0 + 0 + 1 + + 1 + + + NewCell_15 + 7 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + exclusion + 1 + 0 + 0 + 1 + + 1 + + + NewCell_16 + 8 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + invert + 1 + 0 + 0 + 1 + + 1 + + + NewCell_5 + 9 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_17 + 10 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_18 + 11 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mul + 1 + 0 + 0 + 1 + + 1 + + + NewCell_19 + 12 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + add + 1 + 0 + 0 + 1 + + 1 + + + NewCell_20 + 13 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + sub + 1 + 0 + 0 + 1 + + 1 + + + NewCell_21 + 14 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mulalpha + 1 + 0 + 0 + 1 + + 1 + + + NewCell_22 + 15 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + screen + 1 + 0 + 0 + 1 + + 1 + + + NewCell_23 + 16 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + exclusion + 1 + 0 + 0 + 1 + + 1 + + + NewCell_24 + 17 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + invert + 1 + 0 + 0 + 1 + + 1 + + + + + + + color_bar.ssce + + + + Setup + 1 + + 60 + 1 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 0 + 0 + + + 1 + + + root + + + + 0 + + + + + + + + anime_1 + 1 + + 60 + 60 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 59 + 0 + + + 0 + + + root + + + + 0 + + + + + + NewCell_9 + + + + + 0 + NewCell_9 + + + + + + -305.333312988281 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + NewCell_10 + + + + + 0 + NewCell_9 + + + + + + -216.33332824707 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + NewCell_11 + + + + + 0 + NewCell_9 + + + + + + -140.666656494141 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + NewCell_12 + + + + + 0 + NewCell_9 + + + + + + -56.3333320617676 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + NewCell_13 + + + + + 0 + NewCell_9 + + + + + + 32 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + NewCell_14 + + + + + 0 + NewCell_9 + + + + + + 129.66667175293 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + NewCell_15 + + + + + 0 + NewCell_9 + + + + + + 228.666656494141 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + NewCell_16 + + + + + 0 + NewCell_9 + + + + + + 332 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + NewCell_5 + + + + + 0 + NewCell_5 + + + + + + 19.6666564941406 + + + + + -35.3333320617676 + + + + + 0 + + + + + 14.1875009536743 + + + + + 3.58333301544189 + + + + + -10 + + + + + 0 + + + + + + NewCell_17 + + + + + 0 + NewCell_9 + + + + + + -305.333312988281 + + + + + -75 + + + + + 0 + + + + + 1 + + + 0 + + + + + 0 + + + + + 0 + + + + + + NewCell_18 + + + + + 0 + NewCell_9 + + + + + + -216.33332824707 + + + + + -75 + + + + + 0 + + + + + 1 + + + 0 + + + + + 0 + + + + + 0 + + + + + + NewCell_19 + + + + + 0 + NewCell_9 + + + + + + -140.666656494141 + + + + + -75 + + + + + 0 + + + + + 1 + + + 0 + + + + + 0 + + + + + 0 + + + + + + NewCell_20 + + + + + 0 + NewCell_9 + + + + + + -56.3333320617676 + + + + + -75 + + + + + 0 + + + + + 1 + + + 0 + + + + + 0 + + + + + 0 + + + + + + NewCell_21 + + + + + 0 + NewCell_9 + + + + + + 32 + + + + + -75 + + + + + 0 + + + + + 1 + + + 0 + + + + + 0 + + + + + 0 + + + + + + NewCell_22 + + + + + 0 + NewCell_9 + + + + + + 129.66667175293 + + + + + -75 + + + + + 0 + + + + + 1 + + + 0 + + + + + 0 + + + + + 0 + + + + + + NewCell_23 + + + + + 0 + NewCell_9 + + + + + + 228.666656494141 + + + + + -75 + + + + + 0 + + + + + 1 + + + 0 + + + + + 0 + + + + + 0 + + + + + + NewCell_24 + + + + + 0 + NewCell_9 + + + + + + 332 + + + + + -75 + + + + + 0 + + + + + 1 + + + 0 + + + + + 0 + + + + + 0 + + + + + + + + diff --git a/Build/TestData/allPartsV7/null.ssae b/Build/TestData/allPartsV7/null.ssae new file mode 100644 index 00000000..48b120e1 --- /dev/null +++ b/Build/TestData/allPartsV7/null.ssae @@ -0,0 +1,489 @@ + + + + 30 + 11 + prio + 320 320 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 10 + 0 + + null + + + + + root + 0 + -1 + null + none + self + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + part_3 + 1 + 0 + null + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + part_4 + 2 + 1 + null + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_1 + 3 + 2 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + part_1 + 4 + 0 + null + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + part_2 + 5 + 4 + null + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell + 6 + 5 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + + + + + color_bar.ssce + + + + Setup + 1 + + 30 + 1 + prio + 320 320 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 0 + 0 + + + 1 + + + root + + + + 0 + + + + + + + + anime_1 + 1 + + 30 + 60 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 59 + 0 + + + 0 + + + root + + + + 0 + + + + + + part_3 + + + + -259 + + + + + 269 + + + + + 0 + + + + + 1 + + + 2 + + + + + 1 + + + 2 + + + + + 0 + + + + + 0 + + + + + + part_4 + + + + 1 + + + + + -89 + + + + + 0 + + + + + 1 + + + 2 + + + + + 1 + + + 2 + + + + + 0 + + + + + 0 + + + + + + NewCell_1 + + + + + 0 + NewCell_1 + + + + + + 0 + + + + + -73 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + part_1 + + + + 48 + + + + + -49 + + + + + 0 + + + 360 + + + + + 0 + + + + + 0 + + + + + + part_2 + + + + 45 + + + + + -44 + + + + + 0 + + + 360 + + + + + 0 + + + + + 0 + + + + + + NewCell + + + + + 0 + NewCell + + + + + + 51 + + + + + -53 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + + + diff --git a/Build/TestData/allPartsV7/root.ssae b/Build/TestData/allPartsV7/root.ssae new file mode 100644 index 00000000..1693111c --- /dev/null +++ b/Build/TestData/allPartsV7/root.ssae @@ -0,0 +1,376 @@ + + + + 30 + 11 + prio + 320 320 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 10 + + + + 1 + 0 0 + 0 0 + 0 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + 0 + + root + + + + + root + 0 + -1 + null + none + self + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_2 + 1 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell + 2 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + NewCell_1 + 3 + 2 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + + + + + + + color_bar.ssce + + + + Setup + 1 + + 60 + 1 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + 0 + + + 1 + + + root + + + + 0 + + + + + + + + anime_1 + 1 + + 60 + 60 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 59 + + + + 1 + 0 0 + 0 0 + 0 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + 0 + + + 0 + + + root + + + + 88 + + + + + -73 + + + + + 0 + + + 360 + + + + + 2.171875 + + + + + 2.171875 + + + + + 0 + + + + + + NewCell_2 + + + + + 0 + NewCell + + + + + + -72.5180587768555 + + + + + 1.38129472732544 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + NewCell + + + + + 0 + NewCell + + + + + + 54 + + + + + -52 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + NewCell_1 + + + + + 0 + NewCell_1 + + + + + + 44 + + + + + -37 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + + + diff --git a/Build/TestData/allPartsV7/shape.ssae b/Build/TestData/allPartsV7/shape.ssae new file mode 100644 index 00000000..6d9842cd --- /dev/null +++ b/Build/TestData/allPartsV7/shape.ssae @@ -0,0 +1,370 @@ + + + + 30 + 11 + prio + 320 320 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 10 + + + + 1 + 0 0 + 0 0 + 0 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + 0 + + shape + + + + + root + 0 + -1 + null + none + self + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + 1 + + + shape_1 + 1 + 0 + shape + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + rectangle + 0 + 1 + 0 + 0 + 1 + + 1 + 1 + + + shape_2 + 2 + 0 + shape + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + rectangle + 0 + 1 + 0 + 0 + 1 + + 1 + 1 + + + shape_3 + 3 + 0 + shape + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + rectangle + 0 + 1 + 0 + 0 + 1 + + 1 + 1 + + + + + + + + + Setup + 1 + + 60 + 1 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + 0 + + + + 1 + + + root + + + + 0 + + + + + + + + anime_1 + 1 + + 60 + 60 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 59 + + + + 1 + 0 0 + 0 0 + 0 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + 0 + + + + 0 + + + root + + + + 0 + + + + + + shape_1 + + + + -175 + + + + + 111 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + shape_2 + + + + 131 + + + + + 108 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + whole + mul + + FF0000FF + 1 + + + + + + + + shape_3 + + + + 0 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + vertex + mul + + FFFF0004 + 1 + + + FF00FF00 + 1 + + + FF0000FF + 1 + + + FFFFFFFF + 1 + + + + + + + + + + diff --git a/Build/TestData/allPartsV7/sound.ssae b/Build/TestData/allPartsV7/sound.ssae new file mode 100644 index 00000000..4a731bb3 --- /dev/null +++ b/Build/TestData/allPartsV7/sound.ssae @@ -0,0 +1,204 @@ + + + + 30 + 11 + prio + 320 320 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 10 + + + + 1 + 0 0 + 0 0 + 0 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + 0 + + sound + + + + + root + 0 + -1 + null + none + self + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + 1 + + + audio_1 + 1 + 0 + ssaudio + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 1 + 1 + + 1 + 1 + + + + + + + + + Setup + 1 + + 60 + 1 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + 0 + + + + 1 + + + root + + + + 0 + + + + + + + + anime_1 + 1 + + 60 + 60 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 59 + + + + 1 + 0 0 + 0 0 + 0 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + 0 + + + + 0 + + + root + + + + 0 + + + + + + audio_1 + + + + + 0 + se_sys_49 + 1 + + + + + + + + + diff --git a/Build/TestData/allPartsV7/sound/se_sys_49.mp3 b/Build/TestData/allPartsV7/sound/se_sys_49.mp3 new file mode 100644 index 00000000..1cfc7360 Binary files /dev/null and b/Build/TestData/allPartsV7/sound/se_sys_49.mp3 differ diff --git a/Build/TestData/allPartsV7/soundlist.ssse b/Build/TestData/allPartsV7/soundlist.ssse new file mode 100644 index 00000000..e91842e3 --- /dev/null +++ b/Build/TestData/allPartsV7/soundlist.ssse @@ -0,0 +1,16 @@ + + + soundlist + + + 0 + + + + se_sys_49 + sound/se_sys_49.mp3 + 809 + + +
+
diff --git a/Build/TestData/allPartsV7/text.ssae b/Build/TestData/allPartsV7/text.ssae new file mode 100644 index 00000000..b64b893f --- /dev/null +++ b/Build/TestData/allPartsV7/text.ssae @@ -0,0 +1,360 @@ + + + + 30 + 11 + prio + 320 320 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 10 + + + + 1 + 0 0 + 0 0 + 0 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + 0 + + text + + + + + root + 0 + -1 + null + none + self + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + 1 + + + color_bar + 1 + 0 + normal + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + 1 + 0 + 0 + 1 + + 1 + 1 + + + text_2 + 2 + 0 + text + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + システムフォント + 0 + Arial + font/myFont.fnt + 20 + 0 + 1 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 1 + + 1 + 1 + + + text_1 + 3 + 0 + text + none + parent + + 1 + 0 + 0 + 0 + 0 + 0 + + mix + bitmapフォント + 1 + Agency FB + font/RoundedMPlus.fnt + 50 + 2 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 1 + + 1 + 1 + + + + + + + color_bar.ssce + + + + Setup + 1 + + 60 + 1 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + 0 + + + + 1 + + + root + + + + 0 + + + + + + + + anime_1 + 1 + + 60 + 60 + prio + 1280 720 + 0 0 + FF323232 + 32 + FF808080 + 3 + 0 + 59 + + + + 1 + 0 0 + 0 0 + 0 0 + + + + 1 + 0 0 + 0 0 + 0 0 + + + 0 + + + + 0 + + + root + + + + 0 + + + + + + color_bar + + + + + 0 + color_bar + + + + + + -17 + + + + + 177 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + text_2 + + + + -12 + + + + + -41 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + text_1 + + + + 0 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + + + diff --git a/Build/Viewer2/CMakeLists.txt b/Build/Viewer2/CMakeLists.txt index a86932e4..8d7471bb 100644 --- a/Build/Viewer2/CMakeLists.txt +++ b/Build/Viewer2/CMakeLists.txt @@ -98,7 +98,17 @@ set(SDKs_Drawer ../../Common/Drawer/ssplayer_render_gl.cpp ../../Common/Drawer/ssplayer_render_gl.h ../../Common/Drawer/ssplayer_shader_gl.cpp - ../../Common/Drawer/ssplayer_shader_gl.h) + ../../Common/Drawer/ssplayer_shader_gl.h + + ../../Common/Drawer/ssopenglninesdrawer.h + ../../Common/Drawer/ssopenglshapedrawer.h + ../../Common/Drawer/ssopenglninesdrawer.cpp + ../../Common/Drawer/ssopenglshapedrawer.cpp + + #../../Common/Drawer/font/ssfonttexture.h + #../../Common/Drawer/font/ssfonttexture.cpp + + ) include_directories(../../Common/Drawer) # generate JuceHeader.h diff --git a/Build/Viewer2/Source/Model/Loader.cpp b/Build/Viewer2/Source/Model/Loader.cpp index af9065a2..64b7b8be 100644 --- a/Build/Viewer2/Source/Model/Loader.cpp +++ b/Build/Viewer2/Source/Model/Loader.cpp @@ -27,14 +27,18 @@ void AsyncAnimeLoader::run() ViewerMainWindow::get()->getOpenGLContext().executeOnGLThread([&](OpenGLContext& openGLContext) { p->changeState(p->stateLoading.get()); - spritestudio6::SsAnimePackList & alist = p->currentProj->getAnimePackList(); - spritestudio6::SsAnimePack * animePack = alist[packIndex].get(); - spritestudio6::SsAnimation * anime = animePack->animeList[animeIndex]; - spritestudio6::SsModel* model = &animePack->Model; + SpriteStudio::SsAnimePackList & alist = p->currentProj->getAnimePackList(); + SpriteStudio::SsAnimePack * animePack = alist[packIndex].get(); + SpriteStudio::SsAnimation * anime = animePack->animeList[animeIndex]; + SpriteStudio::SsModel* model = &animePack->Model; - p->decoder.reset(new spritestudio6::SsAnimeDecoder()); - p->cellmap = new spritestudio6::SsCellMapList(); + p->decoder.reset(new SpriteStudio::SsAnimeDecoder()); + p->cellmap = new SpriteStudio::SsCellMapList(); p->cellmap->set(p->currentProj.get(), animePack); + + p->fonttextureMng = new SpriteStudio::FontTextureManager(p->currentProj.get()); + + p->decoder->setFontManager(p->fonttextureMng); p->decoder->setAnimation(model, anime, p->cellmap, p->currentProj.get()); int startFrame = static_cast(p->decoder->getAnimeStartFrame()); @@ -89,10 +93,10 @@ void AsyncProjectLoader::run() { p->changeState(p->stateLoading.get()); -// std::string fileName = spritestudio6::SsCharConverter::convert_path_string(projectName.toStdString()); +// std::string fileName = SpriteStudio::SsCharConverter::convert_path_string(projectName.toStdString()); std::string fileName = projectName.toStdString(); - spritestudio6::SsProject* proj = spritestudio6::ssloader_sspj::Load(fileName); + SpriteStudio::SsProject* proj = SpriteStudio::ssloader_sspj::Load(fileName); if (!proj) { diff --git a/Build/Viewer2/Source/Model/Player.cpp b/Build/Viewer2/Source/Model/Player.cpp index dfcb9697..3f66add2 100644 --- a/Build/Viewer2/Source/Model/Player.cpp +++ b/Build/Viewer2/Source/Model/Player.cpp @@ -30,6 +30,7 @@ Player::~Player() { stopTimer(); myInst = nullptr; + delete fonttextureMng; } Player * Player::get() @@ -73,6 +74,7 @@ Player::Player() stateInitial.reset(new StateInitial()); currentState = stateInitial.get(); + fonttextureMng = 0; stopTimer(); } diff --git a/Build/Viewer2/Source/Model/Player.h b/Build/Viewer2/Source/Model/Player.h index 091bd0b2..f6bdd2ae 100644 --- a/Build/Viewer2/Source/Model/Player.h +++ b/Build/Viewer2/Source/Model/Player.h @@ -11,14 +11,15 @@ #pragma once #include "../JuceLibraryCode/JuceHeader.h" -namespace spritestudio6 +namespace SpriteStudio { class SsProject; class SsAnimePack; class SsAnimeDecoder; class SsCellMapList; class SSTextureFactory; -} // namespace spritestudio6 +class FontTextureManager; +} // namespace SpriteStudio class Player : public juce::HighResolutionTimer { @@ -124,9 +125,10 @@ class Player : public juce::HighResolutionTimer std::unique_ptr statePaused; std::unique_ptr stateLoading; std::unique_ptr stateInitial; - std::unique_ptr currentProj; - std::unique_ptr decoder; - spritestudio6::SsCellMapList * cellmap = nullptr; // decoderのデストラクタでdeleteされる + std::unique_ptr currentProj; + std::unique_ptr decoder; + SpriteStudio::SsCellMapList * cellmap = nullptr; + SpriteStudio::FontTextureManager* fonttextureMng = nullptr; friend class AsyncAnimeLoader; friend class AsyncProjectLoader; diff --git a/Build/Viewer2/Source/View/DocumentView3D.cpp b/Build/Viewer2/Source/View/DocumentView3D.cpp index a6051c81..c03c9179 100644 --- a/Build/Viewer2/Source/View/DocumentView3D.cpp +++ b/Build/Viewer2/Source/View/DocumentView3D.cpp @@ -55,15 +55,15 @@ void DocumentView3D::initialise() #endif initOpenGL(); - rendererGL.reset(new spritestudio6::SsRenderGL()); - spritestudio6::SsCurrentRenderer::SetCurrentRender(rendererGL.get()); - texfactory.reset(new spritestudio6::SSTextureFactory(new spritestudio6::SSTextureGL())); + rendererGL.reset(new SpriteStudio::SsRenderGL()); + SpriteStudio::SsCurrentRenderer::SetCurrentRender(rendererGL.get()); + texfactory.reset(new SpriteStudio::SSTextureFactory(new SpriteStudio::SSTextureGL())); } void DocumentView3D::shutdown() { - spritestudio6::SSTextureFactory::releaseAllTexture(); - spritestudio6::SSOpenGLShaderMan::Destory(); + SpriteStudio::SSTextureFactory::releaseAllTexture(); + SpriteStudio::SSOpenGLShaderMan::Destory(); } void DocumentView3D::render() diff --git a/Build/Viewer2/Source/View/DocumentView3D.h b/Build/Viewer2/Source/View/DocumentView3D.h index 892af021..94c0f5d6 100644 --- a/Build/Viewer2/Source/View/DocumentView3D.h +++ b/Build/Viewer2/Source/View/DocumentView3D.h @@ -1,11 +1,11 @@ #pragma once #include "../JuceLibraryCode/JuceHeader.h" -namespace spritestudio6 +namespace SpriteStudio { class SSTextureFactory; class SsRenderGL; -} // namespace spritestudio6 +} // namespace SpriteStudio class DocumentView3D : public OpenGLAppComponent { @@ -38,8 +38,8 @@ class DocumentView3D : public OpenGLAppComponent Value view_camera_scale; private: - std::unique_ptr texfactory; - std::unique_ptr rendererGL; + std::unique_ptr texfactory; + std::unique_ptr rendererGL; Colour backGroundColour; //============================================================================== // private member variables diff --git a/Build/Viewer2/Source/View/MainWindow.cpp b/Build/Viewer2/Source/View/MainWindow.cpp index 092d3932..6d166224 100644 --- a/Build/Viewer2/Source/View/MainWindow.cpp +++ b/Build/Viewer2/Source/View/MainWindow.cpp @@ -477,19 +477,19 @@ ValueTree ViewerMainWindow::createTree() return createTreeItem("", 0, -1); } - spritestudio6::SsProject * proj = Player::get()->currentProj.get(); + SpriteStudio::SsProject * proj = Player::get()->currentProj.get(); auto root = createTreeItem("proj", -1, -1); - spritestudio6::SsAnimePackList & alist = proj->getAnimePackList(); + SpriteStudio::SsAnimePackList & alist = proj->getAnimePackList(); for (int i = 0; i < alist.size(); i++) { // アニメパック名 - spritestudio6::SsAnimePack* animepack = alist[i].get(); + SpriteStudio::SsAnimePack* animepack = alist[i].get(); String animepackName(animepack->name); ValueTree ssae = createTreeItem(animepackName, i, -1); for (int j = 0; j < animepack->animeList.size(); j++) { - spritestudio6::SsAnimation* anime = animepack->animeList[j]; + SpriteStudio::SsAnimation* anime = animepack->animeList[j]; // アニメ名 String animeName(anime->name); if (animeName == "Setup") diff --git a/Common/Animator/CMakeLists.txt b/Common/Animator/CMakeLists.txt index 7995e191..318e218a 100644 --- a/Common/Animator/CMakeLists.txt +++ b/Common/Animator/CMakeLists.txt @@ -22,6 +22,25 @@ set(ssAnimator_SRCS ssplayer_animedecode.cpp ssplayer_effect2.cpp ssplayer_mesh.cpp + ssplayer_math.cpp + ssplayer_fonttexmng.cpp +# partvalues/sspartvalue.cpp +# partvalues/sspartvalueshape.cpp +# partvalues/sspartvaluetext.cpp +# partvalues/sspartvaluenines.cpp + +#shape/sspolygon.cpp +#shape/ssvertex.cpp + +#shape/ssshape.cpp +#shape/ssshapearrow.cpp +#shape/ssshaperectangle.cpp +#shape/ssshapestar.cpp +#shape/ssshapetriangle.cpp + +#nineslice/ssnines.cpp +font/ssfonttexture.cpp + ) set(ssAnimator_HEADERS @@ -36,7 +55,28 @@ set(ssAnimator_HEADERS ssplayer_animedecode.h ssplayer_effect2.h ssplayer_mesh.h + ssplayer_math.h ${CMAKE_CURRENT_SOURCE_DIR}/../Loader/sstypes.h + + ssplayer_fonttexmng.h + +# partvalues/sspartvalue.h +# partvalues/sspartvalueshape.h +# partvalues/sspartvaluetext.h +# partvalues/sspartvaluenines.h + +#shape/sspolygon.h +#shape/ssvertex.h + +#shape/ssshape.h +#shape/ssshapearrow.h +#shape/ssshaperectangle.h +#shape/ssshapestar.h +#shape/ssshapetriangle.h +#nineslice/ssnines.h +font/ssfonttexture.h + + ) include_directories(${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/Common/Animator/ISsEffectRender.h b/Common/Animator/ISsEffectRender.h index c96afc2f..b699b3db 100644 --- a/Common/Animator/ISsEffectRender.h +++ b/Common/Animator/ISsEffectRender.h @@ -1,7 +1,7 @@ #ifndef __ISSEFFECTRENDER__ #define __ISSEFFECTRENDER__ -namespace spritestudio6 +namespace SpriteStudio { class SsPartState; @@ -46,6 +46,6 @@ class ISsEffectRenderer }; -} // namespace spritestudio6 +} // namespace SpriteStudio #endif diff --git a/Common/Animator/font/ssfonttexture.cpp b/Common/Animator/font/ssfonttexture.cpp new file mode 100644 index 00000000..1ee51465 --- /dev/null +++ b/Common/Animator/font/ssfonttexture.cpp @@ -0,0 +1,599 @@ +/*! + * \file ssfonttexture.cpp + * \author CRI Middleware Co., Ltd. +*/ +#include "ssfonttexture.h" + +#include "sstypes.h" +#include "ssplayer_math.h" +#include "sscharmap.h" + +#include"../Helper/SsTextureFactory.h" +#include "../Helper/SsRawImage.h" + +#include "../Helper/UnicodeConv.h" + +namespace SpriteStudio +{ + +#if 0 + //#include "SsController.h" + + //! 白を調整 + /*! + * \param pBitmap イメージ + */ + static void adjustWhite(QImage* pBitmap) + { + unsigned char* pData; + int iWidth; + int iHeight; + int iPixCount; + int iPixIdx; + int iA; + + pData = reinterpret_cast(pBitmap->bits()); + iWidth = pBitmap->width(); + iHeight = pBitmap->height(); + + iPixCount = iWidth * iHeight; + + for (int i = 0; i < iPixCount; i++) { + iPixIdx = i * 4; + +#ifdef _WIN32 + iA = (pData[iPixIdx + 0] + pData[iPixIdx + 1] + pData[iPixIdx + 2]) / 3; +#else + iA = (pData[iPixIdx + 3]); +#endif + + if (iA < 0x00) iA = 0x00; + if (iA > 0xFF) iA = 0xFF; + + iA >>= 4; + iA &= 0x0F; + iA |= ((iA << 4) & 0xF0); + + pData[iPixIdx + 3] = static_cast(iA); + + pData[iPixIdx + 0] = pData[iPixIdx + 1] = pData[iPixIdx + 2] = 0xFF; + } + } + +#endif + + static SsRectI makeDstRect(const SsPoint2& point, const SsRectI& rectSrc, double dScale) + { + SsRectI rectDst; + + rectDst.setX(point.x); + rectDst.setY(point.y); + + int width = rectSrc.width(); + + rectDst.setWidth((int)((double)rectSrc.width() * dScale)); + rectDst.setHeight((int)((double)rectSrc.height() * dScale)); + + return rectDst; + } + +#if 0 // updateFromFamilyで使用 + static SsString toWrappedText(const SsString& strText, int iWidth, const QFont& font) + { + SsString strLine = ""; + SsString strResult = ""; + + foreach(const QChar & e, strText) { + if (e == '\n') { + strLine.clear(); + strResult.push_back('\n'); + continue; + } + + QStaticText text(strLine.push_back(e)); + + text.prepare(QTransform(), font); + + SsSizeF size = text.size(); + + if (size.width() > iWidth) { + strLine.clear(); + strLine.push_back(e); + strResult.push_back('\n'); + } + + strResult.push_back(e); + } + + return strResult; + } +#endif + + //! コンストラクタ + SsFontTexture::SsFontTexture() + { + //m_myProject = 0; + m_pCharMap = nullptr; + + setText(""); + setGridSize(SsSize(0, 0)); + setFixedSize(SsSize(0, 0)); + + m_iImageWidth = 0; + m_iImageHeight = 0; + m_iTextureWidth = 0; + m_iTextureHeight = 0; + + m_bUpdate = true; + + m_pImage = nullptr; + m_pTexture = nullptr; + +#if 0 + m_pText = nullptr; +#endif + m_pBitmap = nullptr; + } + + //! デストラクタ + SsFontTexture::~SsFontTexture() + { + + delete m_pTexture; +#if 0 + // SsOpenGLImage メンバの SsBitmap のデストラクタでは破棄されないようなので。 + if (m_pBitmap) + { + delete m_pBitmap; + m_pBitmap = nullptr; + } + + if (m_pImage) { + delete m_pImage; + m_pImage = nullptr; + } + if (m_pTexture) { + SsOpenGLTextureManager::instance()->deleteTexture(m_pTexture); + m_pTexture = nullptr; + } + + if (m_pText) { + delete m_pText; + m_pText = nullptr; + } +#endif + } + + //! テキストを設定 + void SsFontTexture::setText(const SsString& strText) + { + if (m_strText != strText) { + m_strText = strText; + m_bUpdate = true; + } + } + + //! フォント設定を設定 + void SsFontTexture::setFontDesc(const SsFontDesc& fontDesc) + { + if (m_FontDesc != fontDesc) { + m_FontDesc = fontDesc; + m_bUpdate = true; + } + } + + //! グリッドサイズを設定 + void SsFontTexture::setGridSize(const SsSize& size) + { + if (m_GridSize != size) { + m_GridSize = size; + m_bUpdate = true; + } + } + + //! 固定サイズを設定 + void SsFontTexture::setFixedSize(const SsSize& size) + { + if (m_FixedSize != size) { + m_FixedSize = size; + m_bUpdate = true; + } + } + + //! テキストを取得 + SsString SsFontTexture::getText() const + { + return m_strText; + } + + //! フォント設定を取得 + SsFontDesc SsFontTexture::getFontDesc() const + { + return m_FontDesc; + } + + //! グリッドサイズを取得 + SsSize SsFontTexture::getGridSize() const + { + return m_GridSize; + } + + //! 固定サイズを取得 + SsSize SsFontTexture::getFixedSize() const + { + return m_FixedSize; + } + + //! 更新 + void SsFontTexture::update() + { + if (!m_bUpdate) { + return; + } + + if (m_FontDesc.isBitmap()) { + updateFromCharMap(); + } + else { + updateFromFamily(); + } + + + m_bUpdate = false; + } + + //! イメージ幅を取得 + int SsFontTexture::getImageWidth() const + { + return m_iImageWidth; + } + + //! イメージ高さを取得 + int SsFontTexture::getImageHeight() const + { + return m_iImageHeight; + } + + //! テクスチャ幅を取得 + int SsFontTexture::getTextureWidth() const + { + return m_iTextureWidth; + } + + //! テクスチャ高さを取得 + int SsFontTexture::getTextureHeight() const + { + return m_iTextureHeight; + } + + //! GLテクスチャを取得 + ISSTexture* SsFontTexture::getTexture() const + { + return m_pTexture; + } + +#ifdef SSFONTTEXTURE_SET_BITMAP + //! イメージを設定 + void SsFontTexture::setBitmap(QImage* pImage) + { + + m_bUpdate = false; + } +#endif // SSFONTTEXTURE_SET_BITMAP + +#ifdef SSFONTTEXTURE_GET_BITMAP + //! イメージを取得 + QImage* SsFontTexture::getBitmap() const + { + return m_pBitmap; + } +#endif // SSFONTTEXTURE_GET_BITMAP + + //! ファミリから更新 + void SsFontTexture::updateFromFamily() + { + + } + + //! キャラマップから更新 + void SsFontTexture::updateFromCharMap() + { + + + SsString chamapName = m_FontDesc.getCharMap(); + SsCharMap* pCharMap = m_pCharMap; + + + if (!pCharMap) { + return; + } + + + typedef std::pair> Shape; + + SsRectI bound; + int iLineHeight; + int iPage; + SsPoint2 point; + SsRectI rectSrc; + SsRectI rectDst; + int iAdvance; + SsPoint2 offset; + bool bInit; + int iL, iR, iT, iB; + iL = iR = iT = iB = 0; + double dScale; + float fSpace; + bool bFixed = (m_FixedSize.width() > 0) || (m_FixedSize.height() > 0); + + std::map*> map; + std::list* pListShape; + Shape shape; + std::vector listL; + std::vector listR; + std::vector listW; + int iLine; + bool bLine; + + bInit = true; + listL.clear(); + listR.clear(); + listW.clear(); + listL.push_back(0); + listR.push_back(0); + iLine = 0; + bLine = true; + + iLineHeight = pCharMap->getCommon().getLineHeight(); + + dScale = (double)m_FontDesc.getSize() / (double)iLineHeight; + fSpace = m_FontDesc.getSpace(); + + + SsString str = getText(); + int char_size = 0; + unsigned char lead;; + + ///u8 -> u16文字列へ + SsString temp = getText(); + std::u16string text_list; + ConvU8ToU16(temp, text_list); + + for(SsChar e : text_list ){ + + if (pCharMap->getChars().hasKey(e)) { + iPage = pCharMap->getChars().getPage(e); + point = offset + ((*pCharMap->getChars().getOffset(e) - *pCharMap->getChars().getOffset()) * dScale); + rectSrc = *pCharMap->getChars().getSrcRect(e); + rectDst = makeDstRect(point, rectSrc, dScale); + iAdvance = (pCharMap->getChars().getAdvance(e) * dScale); + + if (bFixed) { + if (point.x + rectDst.width() > m_FixedSize.width()) { + listL.push_back(0); + listR.push_back(0); + iLine++; + bLine = true; + offset.setX(0); + offset.setY(offset.y + m_FontDesc.getSize()); + + point = offset + ((*pCharMap->getChars().getOffset(e) - *pCharMap->getChars().getOffset()) * dScale); + rectDst = makeDstRect(point, rectSrc, dScale); + } + } + + if (!map.count(iPage)>0) { + map[iPage] = new std::list(); + } + pListShape = map[iPage]; + + shape.first = iLine; + shape.second = std::make_pair(rectSrc, rectDst); + pListShape->push_back(shape); + + if (bInit) { + iL = point.x; + iT = point.y; + iR = iL + rectDst.width(); + iB = iT + rectDst.height(); + bInit = false; + } + else { + if (iL > point.x) iL = point.x; + if (iT > point.y) iT = point.y; + if (iR < point.x + rectDst.width()) iR = point.x + rectDst.width(); + if (iB < point.y + rectDst.height()) iB = point.y + rectDst.height(); + } + + if (bLine || listL[iLine] > point.x) { + listL[iLine] = point.x; + } + if (bLine || listR[iLine] < point.x + rectDst.width()) { + listR[iLine] = point.x + rectDst.width(); + } + bLine = false; + + offset.setX(offset.x + iAdvance + fSpace); + } + else + if (e == '\n') { + listL.push_back(0); + listR.push_back(0); + iLine++; + bLine = true; + offset.setX(0); + offset.setY(offset.y + m_FontDesc.getSize()); + } + } + + bound.setCoords(iL, iT, iR, iB); + + m_iImageWidth = bound.left() * 2 + bound.width(); + m_iImageHeight = bound.top() * 2 + bound.height(); + + if (bFixed) { + if (m_FixedSize.width() > 0) m_iImageWidth = m_FixedSize.width(); + if (m_FixedSize.height() > 0) m_iImageHeight = m_FixedSize.height(); + } + + if (m_iImageWidth < 8) m_iImageWidth = 8; + if (m_iImageHeight < 8) m_iImageHeight = 8; + if (m_iImageWidth > 8192) m_iImageWidth = 8192; + if (m_iImageHeight > 8192) m_iImageHeight = 8192; + + m_iTextureWidth = SsMath::convPow2(m_iImageWidth); + m_iTextureHeight = SsMath::convPow2(m_iImageHeight); + + +#if 1 + //Bitmapイメージを作成する + if (!m_pBitmap) { + + m_pBitmap = new SsRawImage(m_iTextureWidth, m_iTextureHeight); + } + else { + //サイズが異なっている + if ((m_pBitmap->getWidth() != m_iTextureWidth) || (m_pBitmap->getHeight() != m_iTextureHeight)) { + if (m_pImage) { + delete m_pImage; + m_pImage = nullptr; + } + + //if (m_pTexture) { + // SsOpenGLTextureManager::instance()->deleteTexture(m_pTexture); + // m_pTexture = nullptr; + //} + + m_pBitmap = new SsRawImage(m_iTextureWidth, m_iTextureHeight); + } + } + +#endif + //m_pBitmap->fill(SsColor(0xffffffff)); + + int a = SsAnchorButton::toAlignment(m_FontDesc.getAnchor()); + + for (int i = 0; i < listL.size(); i++) { + listW.push_back(m_iImageWidth - (listR[i])); + } + + if (a & SsAnchorButton::AlignLeft) { + for (int i = 0; i < listW.size(); i++) { + listW[i] *= 0; + } + } + else + if (a & SsAnchorButton::AlignHCenter) { + for (int i = 0; i < listW.size(); i++) { + listW[i] /= 2; + } + } + else + if (a & SsAnchorButton::AlignRight) { + for (int i = 0; i < listW.size(); i++) { + listW[i] *= 1; + } + } + + iLine = m_iImageHeight - (iB); + + if (a & SsAnchorButton::AlignTop) { + iLine *= 0; + } + else { + + if (a & SsAnchorButton::AlignVCenter) { + iLine /= 2; + } + else if (a & SsAnchorButton::AlignBottom) + { + iLine *= 1; + } + } + + + //Bitmapfontから転送 + for(auto item: map) { + int e = item.first; + + SsRawImage* pImage = pCharMap->getPages().getImage(e); + + for (auto item2 : *map[e]) //Shape + { + SsRectI srcRect = item2.second.first; + SsRectI dstRect = item2.second.second; + + int offsetx = listW[item2.first]; + int offsety = iLine; + + m_pBitmap->Bitblt(pImage, srcRect, dstRect); + + } + + } + +// foreach(int e, map.keys()) { + for(auto e : map ) { + delete map[e.first]; + } + map.clear(); + + // adjustWhite( m_pBitmap ); + + if (m_pTexture) + { + delete m_pTexture; + } + + //表示用のテクスチャを作成する + m_pTexture = SSTextureFactory::create(m_pBitmap); + + calcCell(); + +#if 0 + if (!m_pImage) { + m_pImage = new SsOpenGLImage(m_pBitmap); + } + + bool bResend = false; + + if (m_pTexture == nullptr) { + m_pTexture = SsOpenGLTextureManager::instance()->newTexture(m_pImage); + if (m_pTexture) m_pTexture->setGroup(1); + } + else { + bResend = true; + } + + if (m_pTexture != nullptr) { + if (bResend) { + SsOpenGLTextureManager::instance()->resend(m_pTexture); + } + else { + SsOpenGLTextureManager::instance()->send(m_pTexture); + } + } +#endif + } + void SsFontTexture::calcCell() + { + + m_CellMap.pixelSize = SsPoint2(getTextureWidth(), getTextureHeight()); + //m_CellMap.parent = nullptr; + + m_CellMap.overrideTexSettings = true; + bool m_bSmooth = m_valueText->isSmooth(); + + m_CellMap.filterMode = m_bSmooth ? SsTexFilterMode::linear : SsTexFilterMode::nearlest; + m_CellMap.wrapMode = SsTexWrapMode::clamp; + + //m_CellMap.image = &m_Image; + + //m_Cell.map = &m_CellMap; + m_Cell.pos = SsVector2(0, 0); + m_Cell.size = SsVector2(this->getImageWidth(), this->getImageHeight()); + m_Cell.pivot = SsVector2(0, 0); + + m_Cell.parentSize = SsPoint2(this->getTextureWidth(), this->getTextureHeight()); + } +}; \ No newline at end of file diff --git a/Common/Animator/font/ssfonttexture.h b/Common/Animator/font/ssfonttexture.h new file mode 100644 index 00000000..46f1b76d --- /dev/null +++ b/Common/Animator/font/ssfonttexture.h @@ -0,0 +1,207 @@ +/*! + * \file ssfonttexture.h + * \author CRI Middleware Co., Ltd. +*/ +#ifndef SSFONTTEXTURE_H +#define SSFONTTEXTURE_H + +//#define SSFONTTEXTURE_SET_BITMAP +//#define SSFONTTEXTURE_GET_BITMAP + +//#include +#include "sstypes.h" + +#include "../Loader/text/ssfontdesc.h" +#include "../Helper/SsTextureFactory.h" +#include "../Loader/ssloader_sspj.h" + +//#include "SsOpenGLTexture.h" +//#include "SsOpenGLImage.h" + + +namespace SpriteStudio +{ + /*! + * \class SsFontTexture + * \brief フォントテクスチャ + */ + class SsFontTexture + { + public: + //! コンストラクタ + SsFontTexture(); + + //! デストラクタ + ~SsFontTexture(); + + //! テキストを設定 + /*! + * \param strText テキスト + */ + void setText(const SsString& strText); + + //! フォント設定を設定 + /*! + * \param fontDesc フォント設定 + */ + void setFontDesc(const SsFontDesc& fontDesc); + + //! グリッドサイズを設定 + /*! + * \param size グリッドサイズ + */ + void setGridSize(const SsSize& size); + + //! 固定サイズを設定 + /*! + * \param size 固定サイズ + */ + void setFixedSize(const SsSize& size); + + //! テキストを取得 + /*! + * \return テキスト + */ + SsString getText() const; + + //! フォント設定を取得 + /*! + * \return フォント設定 + */ + SsFontDesc getFontDesc() const; + + //! グリッドサイズを取得 + /*! + * \return グリッドサイズ + */ + SsSize getGridSize() const; + + //! 固定サイズを取得 + /*! + * \return 固定サイズ + */ + SsSize getFixedSize() const; + + //! 更新 + void update(); + + //! イメージ幅を取得 + /*! + * \return イメージ幅 + */ + int getImageWidth() const; + + //! イメージ高さを取得 + /*! + * \return イメージ高さ + */ + int getImageHeight() const; + + //! テクスチャ幅を取得 + /*! + * \return テクスチャ幅 + */ + int getTextureWidth() const; + + //! テクスチャ高さを取得 + /*! + * \return テクスチャ高さ + */ + int getTextureHeight() const; + + //! GLテクスチャを取得 + /*! + * \return GLテクスチャ + */ + ISSTexture* getTexture() const; + + + //void setProject(SsProject* proj) { + // m_myProject = proj; + //} + + //void setCharMap(SsCharMap* charmap, SsRawImage* charamapIma) { + void setCharMap(SsCharMap* charmap ) { + m_pCharMap = charmap; + } + + void setPartValue(SsPartValueText* v) + { + m_valueText = v; + } + + SsCell* getCell() { + return &m_Cell; + } + + SsCellMap* getCellMap() { + return &m_CellMap; + } + +#ifdef SSFONTTEXTURE_SET_BITMAP + //! イメージを設定 + /*! + * \param pImage イメージ + */ + void setBitmap(QImage* pImage); +#endif // SSFONTTEXTURE_SET_BITMAP + +#ifdef SSFONTTEXTURE_GET_BITMAP + //! イメージを取得 + /*! + * \return イメージ + */ + SsImage* getBitmap() const; +#endif // SSFONTTEXTURE_GET_BITMAP + + private: + SsString m_strText; //!< テキスト + SsFontDesc m_FontDesc; //!< フォント設定 + SsSize m_GridSize; //!< グリッドサイズ + SsSize m_FixedSize; //!< 固定サイズ + + int m_iImageWidth; //!< イメージ幅 + int m_iImageHeight; //!< イメージ高さ + int m_iTextureWidth; //!< テクスチャ幅 + int m_iTextureHeight; //!< テクスチャ高さ + + bool m_bUpdate; //!< 更新が必要かどうか + +// SsProject* m_myProject; //!< 自身が所属しているプロジェクト + + SsCharMap* m_pCharMap; + SsRawImage* m_pBitmap; //!< イメージ + + + ISSTexture* m_pTexture; //!< GLテクスチャ + + SsCellMap m_CellMap; //!< セルマップ + SsCell m_Cell; //!< セル + SsPartValueText* m_valueText; + +#if 0 + SsOpenGLImage* m_pImage; //!< GLイメージ + SsOpenGLTexture* m_pTexture; //!< GLテクスチャ + +#endif + SsRawImage* m_pImage; //!< GLイメージ + //SsCellValue m_CellValue; + + //! ファミリから更新 + void updateFromFamily(); + + + //! キャラマップから更新 + void updateFromCharMap(); + + //cellmap計算 + void calcCell(); + + public: + + + }; + +}; + +#endif // SSFONTTEXTURE_H diff --git a/Common/Animator/font/ssfonttexturemng.cpp b/Common/Animator/font/ssfonttexturemng.cpp new file mode 100644 index 00000000..3c3fc5d5 --- /dev/null +++ b/Common/Animator/font/ssfonttexturemng.cpp @@ -0,0 +1,232 @@ +/*! + * \file ssfonttexturemng.cpp + * \author CRI Middleware Co., Ltd. +*/ +#include "ssfonttexturemng.h" + +//! コンストラクタ +SsFontTextureMng::SsFontTextureMng() +{ + m_mapValue.clear(); +} + +//! デストラクタ +SsFontTextureMng::~SsFontTextureMng() +{ + m_mapValue.clear(); +} + +//! シングルトンインスタンスを取得 +SsFontTextureMng& SsFontTextureMng::getInstance() +{ + static SsFontTextureMng s_Self; + + return s_Self; +} + +//! 取得 +SsFontTexture* SsFontTextureMng::get( const SsString& strText, const SsFontDesc& fontDesc, const SsSize& sizeGrid, const SsSize& sizeFixed ) +{ + Key key( strText, fontDesc, sizeGrid, sizeFixed ); + + if ( m_mapValue.contains( key ) ) { + return m_mapValue[key].inc(); + } + + Value value( strText, fontDesc, sizeGrid, sizeFixed ); + + m_mapValue[key] = value; + + return m_mapValue[key].inc(); +} + +//! 解放 +void SsFontTextureMng::release( SsFontTexture* pFontTexture ) +{ + if ( !pFontTexture ) { + return; + } + + Key key( pFontTexture->getText(), pFontTexture->getFontDesc(), pFontTexture->getGridSize(), pFontTexture->getFixedSize() ); + + if ( m_mapValue.contains( key ) ) { + if ( m_mapValue[key].dec() ) { + m_mapValue.remove( key ); + } + } +} + +//! 取得カウンタを取得 +int SsFontTextureMng::count( SsFontTexture* pFontTexture ) +{ + if ( !pFontTexture ) { + return 0; + } + + Key key( pFontTexture->getText(), pFontTexture->getFontDesc(), pFontTexture->getGridSize(), pFontTexture->getFixedSize() ); + + if ( m_mapValue.contains( key ) ) { + return m_mapValue[key].count(); + } + + return 0; +} + +//! コンストラクタ +SsFontTextureMng::Key::Key( const SsString& strText, const SsFontDesc& fontDesc, const SsSize& sizeGrid, const SsSize& sizeFixed ) +{ + m_strText = strText; + m_FontDesc = fontDesc; + m_GridSize = sizeGrid; + m_FixedSize = sizeFixed; +} + +//! デストラクタ +SsFontTextureMng::Key::~Key() +{ +} + +SsFontTextureMng::Key& SsFontTextureMng::Key::operator =( const Key& right ) +{ + m_strText = right.m_strText; + m_FontDesc = right.m_FontDesc; + m_GridSize = right.m_GridSize; + m_FixedSize = right.m_FixedSize; + + return *this; +} + +bool SsFontTextureMng::Key::operator ==( const Key& right ) const +{ + if ( + ( m_strText == right.m_strText ) && + ( m_FontDesc == right.m_FontDesc ) && + ( m_GridSize == right.m_GridSize ) && + ( m_FixedSize == right.m_FixedSize ) + ) { + return true; + } + + return false; +} + +bool SsFontTextureMng::Key::operator !=( const Key& right ) const +{ + return !( *this == right ); +} + +bool SsFontTextureMng::Key::operator <( const Key& right ) const +{ + if ( m_strText < right.m_strText ) return true; + if ( m_strText > right.m_strText ) return false; + + if ( m_FontDesc < right.m_FontDesc ) return true; + if ( m_FontDesc > right.m_FontDesc ) return false; + + if ( m_GridSize.width() < right.m_GridSize.width() ) return true; + if ( m_GridSize.width() > right.m_GridSize.width() ) return false; + + if ( m_GridSize.height() < right.m_GridSize.height() ) return true; + if ( m_GridSize.height() > right.m_GridSize.height() ) return false; + + if ( m_FixedSize.width() < right.m_FixedSize.width() ) return true; + if ( m_FixedSize.width() > right.m_FixedSize.width() ) return false; + + if ( m_FixedSize.height() < right.m_FixedSize.height() ) return true; + if ( m_FixedSize.height() > right.m_FixedSize.height() ) return false; + + return false; +} + +bool SsFontTextureMng::Key::operator >( const Key& right ) const +{ + if ( m_strText > right.m_strText ) return true; + if ( m_strText < right.m_strText ) return false; + + if ( m_FontDesc > right.m_FontDesc ) return true; + if ( m_FontDesc < right.m_FontDesc ) return false; + + if ( m_GridSize.width() > right.m_GridSize.width() ) return true; + if ( m_GridSize.width() < right.m_GridSize.width() ) return false; + + if ( m_GridSize.height() > right.m_GridSize.height() ) return true; + if ( m_GridSize.height() < right.m_GridSize.height() ) return false; + + if ( m_FixedSize.width() > right.m_FixedSize.width() ) return true; + if ( m_FixedSize.width() < right.m_FixedSize.width() ) return false; + + if ( m_FixedSize.height() > right.m_FixedSize.height() ) return true; + if ( m_FixedSize.height() < right.m_FixedSize.height() ) return false; + + return false; +} + +//! コンストラクタ +SsFontTextureMng::Value::Value() +{ + m_iCnt = 0; +} + +//! コンストラクタ +SsFontTextureMng::Value::Value( const SsString& strText, const SsFontDesc& fontDesc, const SsSize& sizeGrid, const SsSize& sizeFixed ) +{ + m_iCnt = 0; + m_FontTexture.setText( strText ); + m_FontTexture.setFontDesc( fontDesc ); + m_FontTexture.setGridSize( sizeGrid ); + m_FontTexture.setFixedSize( sizeFixed ); +} + +//! デストラクタ +SsFontTextureMng::Value::~Value() +{ +} + +SsFontTextureMng::Value& SsFontTextureMng::Value::operator =( const Value& right ) +{ + m_FontTexture.setText( right.m_FontTexture.getText() ); + m_FontTexture.setFontDesc( right.m_FontTexture.getFontDesc() ); + m_FontTexture.setGridSize( right.m_FontTexture.getGridSize() ); + m_FontTexture.setFixedSize( right.m_FontTexture.getFixedSize() ); + + return *this; +} + +bool SsFontTextureMng::Value::operator ==( const Value& right ) const +{ + if ( + ( m_FontTexture.getText() == right.m_FontTexture.getText() ) && + ( m_FontTexture.getFontDesc() == right.m_FontTexture.getFontDesc() ) && + ( m_FontTexture.getGridSize() == right.m_FontTexture.getGridSize() ) && + ( m_FontTexture.getFixedSize() == right.m_FontTexture.getFixedSize() ) + ) { + return true; + } + + return false; +} + +bool SsFontTextureMng::Value::operator !=( const Value& right ) const +{ + return !( *this == right ); +} + +//! 取得カウンタを増やす +SsFontTexture* SsFontTextureMng::Value::inc() +{ + m_iCnt++; + return &m_FontTexture; +} + +//! 取得カウンタを減らす +bool SsFontTextureMng::Value::dec() +{ + m_iCnt--; + return ( m_iCnt <= 0 ); +} + +//! 取得カウンタを取得 +int SsFontTextureMng::Value::count() +{ + return m_iCnt; +} diff --git a/Common/Animator/font/ssfonttexturemng.h b/Common/Animator/font/ssfonttexturemng.h new file mode 100644 index 00000000..6bf45b23 --- /dev/null +++ b/Common/Animator/font/ssfonttexturemng.h @@ -0,0 +1,140 @@ +/*! + * \file ssfonttexturemng.h + * \author CRI Middleware Co., Ltd. +*/ +#ifndef SSFONTTEXTUREMNG_H +#define SSFONTTEXTUREMNG_H + +#include + +#include "ssfonttexture.h" + +/*! + * \class SsFontTextureMng + * \brief フォントテクスチャマネージャ +*/ +class SsFontTextureMng +{ +private : + //! コンストラクタ + SsFontTextureMng(); + +public : + //! デストラクタ + ~SsFontTextureMng(); + + //! シングルトンインスタンスを取得 + /*! + * \return フォントテクスチャマネージャ + */ + static SsFontTextureMng& getInstance(); + + //! 取得 + /*! + * \param strText テキスト + * \param fontDesc フォント設定 + * \param sizeGrid グリッドサイズ + * \param sizeFixed 固定サイズ + * \return フォントテクスチャ + */ + SsFontTexture* get( const SsString& strText, const SsFontDesc& fontDesc, const SsSize& sizeGrid, const SsSize& sizeFixed ); + + //! 解放 + /*! + * \param pFontTexture フォントテクスチャ + */ + void release( SsFontTexture* pFontTexture ); + + //! 取得カウンタを取得 + /*! + * \param pFontTexture フォントテクスチャ + * \return 取得カウンタ + */ + int count( SsFontTexture* pFontTexture ); + +private : + /*! + * \class SsFontTextureMng::Key + * \brief キー + */ + class Key + { + public : + //! コンストラクタ + /*! + * \param strText テキスト + * \param fontDesc フォント設定 + * \param sizeGrid グリッドサイズ + * \param sizeFixed 固定サイズ + */ + Key( const SsString& strText, const SsFontDesc& fontDesc, const SsSize& sizeGrid, const SsSize& sizeFixed ); + + //! デストラクタ + ~Key(); + + Key& operator =( const Key& right ); + bool operator ==( const Key& right ) const; + bool operator !=( const Key& right ) const; + bool operator <( const Key& right ) const; + bool operator >( const Key& right ) const; + + private : + SsString m_strText; //!< テキスト + SsFontDesc m_FontDesc; //!< フォント設定 + SsSize m_GridSize; //!< グリッドサイズ + SsSize m_FixedSize; //!< 固定サイズ + }; + + /*! + * \class SsFontTextureMng::Value + * \brief 値 + */ + class Value + { + public : + //! コンストラクタ + Value(); + + //! コンストラクタ + /*! + * \param strText テキスト + * \param fontDesc フォント設定 + * \param sizeGrid グリッドサイズ + * \param sizeFixed 固定サイズ + */ + Value( const SsString& strText, const SsFontDesc& fontDesc, const SsSize& sizeGrid, const SsSize& sizeFixed ); + + //! デストラクタ + ~Value(); + + Value& operator =( const Value& right ); + bool operator ==( const Value& right ) const; + bool operator !=( const Value& right ) const; + + //! 取得カウンタを増やす + /*! + * \return フォントテクスチャ + */ + SsFontTexture* inc(); + + //! 取得カウンタを減らす + /*! + * \return 取得カウンタが0以下になった場合に true + */ + bool dec(); + + //! 取得カウンタを取得 + /*! + * \return 取得カウンタ + */ + int count(); + + private : + int m_iCnt; //!< 取得カウンタ + SsFontTexture m_FontTexture; //!< フォントテクスチャ + }; + + QMap m_mapValue; //!< 値マップ +}; + +#endif // SSFONTTEXTUREMNG_H diff --git a/Common/Animator/ssplayer_PartState.cpp b/Common/Animator/ssplayer_PartState.cpp index a1ca0ba4..fcd29438 100644 --- a/Common/Animator/ssplayer_PartState.cpp +++ b/Common/Animator/ssplayer_PartState.cpp @@ -2,7 +2,7 @@ #include "ssplayer_animedecode.h" #include "ssplayer_PartState.h" -namespace spritestudio6 +namespace SpriteStudio { @@ -54,6 +54,7 @@ void SsPartState::init() anchor = SsVector2( 0 , 0 ); size = SsVector2( 1 , 1 ); + imageFlipH = false; imageFlipV = false; uvTranslate = SsVector2(0, 0); @@ -112,4 +113,4 @@ void SsPartState::reset() } -} // namespace spritestudio6 +} // namespace SpriteStudio diff --git a/Common/Animator/ssplayer_PartState.h b/Common/Animator/ssplayer_PartState.h index 9ec8c151..4fe515f3 100644 --- a/Common/Animator/ssplayer_PartState.h +++ b/Common/Animator/ssplayer_PartState.h @@ -8,7 +8,10 @@ #include -namespace spritestudio6 +#include "shape/ssshape.h" +//#include "text/ssfontdesc.h" + +namespace SpriteStudio { class SsAnimeDecoder; @@ -18,6 +21,7 @@ class SsMeshPart; + ///パーツの状態を保持するクラスです。 struct SsPartState { @@ -80,6 +84,10 @@ struct SsPartState std::unique_ptr refAnime; std::unique_ptr refEffect; + //add SS7.1 + //std::unique_ptr partTypeAnimeVaule; + //-- + //V4互換計算用 SsVector3 _temp_position; SsVector3 _temp_rotation; @@ -93,9 +101,13 @@ struct SsPartState std::unique_ptr meshPart; SsDeformAttr deformValue; + SsAudioAttr audioValue; + SsTexChangeAttr changeTextureValue; SsPart* part; + + SsPartState(); virtual ~SsPartState(); @@ -106,6 +118,6 @@ struct SsPartState }; -} // namespace spritestudio6 +} // namespace SpriteStudio #endif diff --git a/Common/Animator/ssplayer_animedecode.cpp b/Common/Animator/ssplayer_animedecode.cpp index ba53167b..31d63531 100644 --- a/Common/Animator/ssplayer_animedecode.cpp +++ b/Common/Animator/ssplayer_animedecode.cpp @@ -15,7 +15,7 @@ -namespace spritestudio6 +namespace SpriteStudio { //stdでののforeach宣言  @@ -47,7 +47,8 @@ SsAnimeDecoder::SsAnimeDecoder() : seedOffset(0), maskFuncFlag(true), maskParentSetting(true), - meshAnimator() + meshAnimator(), + fontTexManager(nullptr) { } @@ -116,6 +117,138 @@ bool SsAnimeDecoder::getFirstCell(SsPart* part , SsCellValue& out) return retFlag; } +void SsAnimeDecoder::initPartTypeInstance(SsPart* p ,SsPartState& state) +{ + //参照アニメーションを取得 +// SsAnimePack* refpack = sspj->findAnimationPack(p->refAnimePack); + SsAnimePack* refpack = project->findAnimationPack(p->refAnimePack); + SsAnimation* refanime = refpack->findAnimation(p->refAnime); + + //インスタンスパーツの設定setAnimationでソースアニメになるパーツに適用するので先に設定を行う + SsAnimeDecoder* animedecoder = new SsAnimeDecoder(); + animedecoder->setMaskFuncFlag(false); //マスク機能を無効にする + animedecoder->setMaskParentSetting(p->maskInfluence); //親のマスク対象を設定する + + //MEMO: __cellmapはsetAnimation関数内でスマートポインタ化されています + SsCellMapList* __cellmap = new SsCellMapList(); + __cellmap->set(project, refpack); + animedecoder->setAnimation(&refpack->Model, refanime, __cellmap, project); +// partStateRaw[i].refAnime.reset(animedecoder); + state.refAnime.reset(animedecoder); + + //親子関係を付ける + std::vector& partStateRawInstance = *(animedecoder->partState.get()); +// partStateRawInstance[0].parent = &partStateRaw[i]; + partStateRawInstance[0].parent = &state; + +} + +void SsAnimeDecoder::initPartTypeEffect(SsPart* p ,SsPartState& state) +{ + SsEffectFile* f = project->findEffect(p->refEffectName); + if (f) + { + state.refEffect.reset(new SsEffectRenderV2()); + SsEffectRenderV2* er = state.refEffect.get(); + + er->setParentAnimeState(&state); + er->setCellmapManager(this->curCellMapManager.get()); + er->setEffectData(&f->effectData); + er->setSeed(getRandomSeed()); + er->reload(); + er->stop(); + er->setLoop(false); + } + +} + +void SsAnimeDecoder::initPartTypeMask(SsPart* p, SsPartState& state) +{ + partStatesMask_.push_back(&state); + +} + + +void SsAnimeDecoder::initPartTypeMesh(SsPart* p, SsPartState& state) +{ + state.meshPart.reset(new SsMeshPart()); + SsMeshPart* mesh = state.meshPart.get(); + + mesh->myPartState = &state; + //使用するセルを調査する + bool ret; + SsCellValue cellv; + if (ret = getFirstCell(p, cellv)) + { + mesh->targetCell = cellv.cell; + mesh->targetTexture = cellv.texture; + mesh->makeMesh(); + } + else { + //not found cell + } +} + +void SsAnimeDecoder::initPartTypeShape(SsPart* p, SsPartState& state) +{ + state.size.x = state.size.y = 64.0f; + + + if (p->m_pPartValueInfo.get()) + { + if (p->m_pPartValueInfo->getTag() == "shape") + { + const SsPartValueShape* info = static_cast(p->m_pPartValueInfo.get()); + if (info->isMask()) + { + partStatesMask_.push_back(&state); + } + + //SsShape* shape = new SsShape(); + //state.partTypeAnimeVaule.reset(shape); + } + } + +} + +void SsAnimeDecoder::initPartTypeText(SsPart* p, SsPartState& state) +{ + if (p->m_pPartValueInfo.get()) + { + if (p->m_pPartValueInfo->getTag() == "text") + { + + const SsPartValueText* info = static_cast(p->m_pPartValueInfo.get()); + SsCharMap* charmap = project->findCharMap(info->getCharMap()); + + if (info->isMask()) + { + partStatesMask_.push_back(&state); + } + } + } + +} + +void SsAnimeDecoder::initPartTypeNineslice(SsPart* p, SsPartState& state) +{ + if (p->m_pPartValueInfo.get()) + { + if (p->m_pPartValueInfo->getTag() == "nines") + { + const SsPartValueNines* info = static_cast(p->m_pPartValueInfo.get()); + if (info->isMask()) + { + partStatesMask_.push_back(&state); + } + } + } + +} +void SsAnimeDecoder::initPartTypeAudio(SsPart* p, SsPartState& state) +{ + +} //void SsAnimeDecoder::setAnimation(SsModel* model, SsAnimation* anime, SsAnimePack *animepack, SsCellMapList* cellmap, SsProject* sspj ) @@ -138,6 +271,7 @@ void SsAnimeDecoder::setAnimation( SsModel* model , SsAnimation* anime , SsCellM myModel = model; + //パーツの数 size_t panum = anime->partAnimes.size(); for ( size_t i = 0 ; i < panum ; i++ ) @@ -200,75 +334,38 @@ void SsAnimeDecoder::setAnimation( SsModel* model , SsAnimation* anime , SsCellM if (sspj) { - //インスタンスパーツの場合の初期設定 - if ( p->type == SsPartType::instance ) - { - - //参照アニメーションを取得 - SsAnimePack* refpack = sspj->findAnimationPack( p->refAnimePack ); - SsAnimation* refanime = refpack->findAnimation( p->refAnime ); - - //インスタンスパーツの設定setAnimationでソースアニメになるパーツに適用するので先に設定を行う - SsAnimeDecoder* animedecoder = new SsAnimeDecoder(); - animedecoder->setMaskFuncFlag( false ); //マスク機能を無効にする - animedecoder->setMaskParentSetting( p->maskInfluence ); //親のマスク対象を設定する - - //MEMO: __cellmapはsetAnimation関数内でスマートポインタ化されています - SsCellMapList* __cellmap = new SsCellMapList(); - __cellmap->set( sspj , refpack ); - animedecoder->setAnimation( &refpack->Model , refanime, __cellmap , sspj ); - partStateRaw[i].refAnime.reset(animedecoder); - //親子関係を付ける - std::vector& partStateRawInstance = *(animedecoder->partState.get()); - partStateRawInstance[0].parent = &partStateRaw[i]; - } - - //エフェクトデータの初期設定 - if ( p->type == SsPartType::effect ) + switch (p->type) { - SsEffectFile* f = sspj->findEffect( p->refEffectName ); - if ( f ) - { - partStateRaw[i].refEffect.reset( new SsEffectRenderV2() ); - SsEffectRenderV2* er = partStateRaw[i].refEffect.get(); - - er->setParentAnimeState( &partStateRaw[i] ); - er->setCellmapManager( this->curCellMapManager.get() ); - er->setEffectData( &f->effectData ); - er->setSeed(getRandomSeed()); - er->reload(); - er->stop(); - er->setLoop(false); - } - } + case SsPartType::instance: + initPartTypeInstance(p, partStateRaw[i]); + break; + case SsPartType::effect: + initPartTypeEffect(p, partStateRaw[i]); + break; + case SsPartType::mask: + initPartTypeMask(p, partStateRaw[i]); + break; + case SsPartType::mesh: + initPartTypeMesh(p, partStateRaw[i]); + break; + case SsPartType::shape: + initPartTypeShape(p, partStateRaw[i]); + break; + case SsPartType::text: + initPartTypeText(p, partStateRaw[i]); + break; + case SsPartType::nines: + initPartTypeNineslice(p, partStateRaw[i]); + break; + case SsPartType::audio: + initPartTypeAudio(p, partStateRaw[i]); + break; + //default: - //マスクパーツの追加 - if (p->type == SsPartType::mask ) - { - partStatesMask_.push_back( &partStateRaw[i] ); } - //メッシュパーツの追加 - if (p->type == SsPartType::mesh) - { - partStateRaw[i].meshPart.reset( new SsMeshPart() ); - SsMeshPart* mesh = partStateRaw[i].meshPart.get(); - - mesh->myPartState = &partStateRaw[i]; - //使用するセルを調査する - bool ret; - SsCellValue cellv; - if (ret = getFirstCell(p, cellv)) - { - mesh->targetCell = cellv.cell; - mesh->targetTexture = cellv.texture; - mesh->makeMesh(); - } - else { - //not found cell - } - } + } sortList.push_back( &partStateRaw[i] ); @@ -326,12 +423,14 @@ void SsAnimeDecoder::SsInterpolationValue( int time , const SsKeyframe* leftkey curve.endKeyTime = (float)rightkey->time; } - float rate = SsInterpolate( leftkey->ipType , now , 0.0f , 1.0f , &curve ); + float easingRate = leftkey->easingRate; + + float rate = SsInterpolate( leftkey->ipType , easingRate, now , 0.0f , 1.0f , &curve ); for ( int i = 0 ; i < 4 ; i++ ) { - v.offsets[i].x = SsInterpolate( SsInterpolationType::linear , rate , lv.offsets[i].x , rv.offsets[i].x , 0 ); - v.offsets[i].y = SsInterpolate( SsInterpolationType::linear , rate , lv.offsets[i].y , rv.offsets[i].y , 0 ); + v.offsets[i].x = SsInterpolate( SsInterpolationType::linear , easingRate , rate , lv.offsets[i].x , rv.offsets[i].x , 0 ); + v.offsets[i].y = SsInterpolate( SsInterpolationType::linear , easingRate , rate , lv.offsets[i].y , rv.offsets[i].y , 0 ); // v.offsets[i].x = SsInterpolate( leftkey->ipType , now , lv.offsets[i].x , rv.offsets[i].x , &curve ); // v.offsets[i].y = SsInterpolate( leftkey->ipType , now , lv.offsets[i].y , rv.offsets[i].y , &curve ); } @@ -386,7 +485,8 @@ void SsAnimeDecoder::SsInterpolationValue(int time, const SsKeyframe* leftkey, c v.target = SsColorBlendTarget::vertex; v.blendType = leftv.blendType; - now = SsInterpolate(leftkey->ipType, now, 0.0f, 1.0f, &curve); + float easingRate = leftkey->easingRate; + now = SsInterpolate(leftkey->ipType, easingRate, now, 0.0f, 1.0f, &curve); if (leftv.target == SsColorBlendTarget::vertex) { @@ -395,11 +495,11 @@ void SsAnimeDecoder::SsInterpolationValue(int time, const SsKeyframe* leftkey, c //両方とも4頂点カラー for (int i = 0; i < 4; i++) { - v.colors[i].rate = clamp(SsInterpolate(SsInterpolationType::linear, now, leftv.colors[i].rate, rightv.colors[i].rate, &curve), 0.0f, 1.0f); - v.colors[i].rgba.a = (u32)(clamp(SsInterpolate(SsInterpolationType::linear, now, (float)leftv.colors[i].rgba.a, (float)rightv.colors[i].rgba.a, &curve), 0.0f, 255.0f)); - v.colors[i].rgba.r = (u32)(clamp(SsInterpolate(SsInterpolationType::linear, now, (float)leftv.colors[i].rgba.r, (float)rightv.colors[i].rgba.r, &curve), 0.0f, 255.0f)); - v.colors[i].rgba.g = (u32)(clamp(SsInterpolate(SsInterpolationType::linear, now, (float)leftv.colors[i].rgba.g, (float)rightv.colors[i].rgba.g, &curve), 0.0f, 255.0f)); - v.colors[i].rgba.b = (u32)(clamp(SsInterpolate(SsInterpolationType::linear, now, (float)leftv.colors[i].rgba.b, (float)rightv.colors[i].rgba.b, &curve), 0.0f, 255.0f)); + v.colors[i].rate = clamp(SsInterpolate(SsInterpolationType::linear, easingRate , now, leftv.colors[i].rate, rightv.colors[i].rate, &curve), 0.0f, 1.0f); + v.colors[i].rgba.a = (u32)(clamp(SsInterpolate(SsInterpolationType::linear, easingRate , now, (float)leftv.colors[i].rgba.a, (float)rightv.colors[i].rgba.a, &curve), 0.0f, 255.0f)); + v.colors[i].rgba.r = (u32)(clamp(SsInterpolate(SsInterpolationType::linear, easingRate , now, (float)leftv.colors[i].rgba.r, (float)rightv.colors[i].rgba.r, &curve), 0.0f, 255.0f)); + v.colors[i].rgba.g = (u32)(clamp(SsInterpolate(SsInterpolationType::linear, easingRate , now, (float)leftv.colors[i].rgba.g, (float)rightv.colors[i].rgba.g, &curve), 0.0f, 255.0f)); + v.colors[i].rgba.b = (u32)(clamp(SsInterpolate(SsInterpolationType::linear, easingRate , now, (float)leftv.colors[i].rgba.b, (float)rightv.colors[i].rgba.b, &curve), 0.0f, 255.0f)); } } else @@ -407,11 +507,11 @@ void SsAnimeDecoder::SsInterpolationValue(int time, const SsKeyframe* leftkey, c //左は4頂点、右は単色 for (int i = 0; i < 4; i++) { - v.colors[i].rate = clamp(SsInterpolate(SsInterpolationType::linear, now, leftv.colors[i].rate, rightv.color.rate, &curve), 0.0f, 1.0f); - v.colors[i].rgba.a = (u32)(clamp(SsInterpolate(SsInterpolationType::linear, now, (float)leftv.colors[i].rgba.a, (float)rightv.color.rgba.a, &curve), 0.0f, 255.0f)); - v.colors[i].rgba.r = (u32)(clamp(SsInterpolate(SsInterpolationType::linear, now, (float)leftv.colors[i].rgba.r, (float)rightv.color.rgba.r, &curve), 0.0f, 255.0f)); - v.colors[i].rgba.g = (u32)(clamp(SsInterpolate(SsInterpolationType::linear, now, (float)leftv.colors[i].rgba.g, (float)rightv.color.rgba.g, &curve), 0.0f, 255.0f)); - v.colors[i].rgba.b = (u32)(clamp(SsInterpolate(SsInterpolationType::linear, now, (float)leftv.colors[i].rgba.b, (float)rightv.color.rgba.b, &curve), 0.0f, 255.0f)); + v.colors[i].rate = clamp(SsInterpolate(SsInterpolationType::linear, easingRate , now, leftv.colors[i].rate, rightv.color.rate, &curve), 0.0f, 1.0f); + v.colors[i].rgba.a = (u32)(clamp(SsInterpolate(SsInterpolationType::linear, easingRate , now, (float)leftv.colors[i].rgba.a, (float)rightv.color.rgba.a, &curve), 0.0f, 255.0f)); + v.colors[i].rgba.r = (u32)(clamp(SsInterpolate(SsInterpolationType::linear, easingRate , now, (float)leftv.colors[i].rgba.r, (float)rightv.color.rgba.r, &curve), 0.0f, 255.0f)); + v.colors[i].rgba.g = (u32)(clamp(SsInterpolate(SsInterpolationType::linear, easingRate , now, (float)leftv.colors[i].rgba.g, (float)rightv.color.rgba.g, &curve), 0.0f, 255.0f)); + v.colors[i].rgba.b = (u32)(clamp(SsInterpolate(SsInterpolationType::linear, easingRate , now, (float)leftv.colors[i].rgba.b, (float)rightv.color.rgba.b, &curve), 0.0f, 255.0f)); } } } @@ -422,21 +522,21 @@ void SsAnimeDecoder::SsInterpolationValue(int time, const SsKeyframe* leftkey, c //左は単色、右は4頂点カラー for (int i = 0; i < 4; i++) { - v.colors[i].rate = clamp(SsInterpolate(SsInterpolationType::linear, now, leftv.color.rate, rightv.colors[i].rate, &curve), 0.0f, 1.0f); - v.colors[i].rgba.a = (u32)(clamp(SsInterpolate(SsInterpolationType::linear, now, (float)leftv.color.rgba.a, (float)rightv.colors[i].rgba.a, &curve), 0.0f, 255.0f)); - v.colors[i].rgba.r = (u32)(clamp(SsInterpolate(SsInterpolationType::linear, now, (float)leftv.color.rgba.r, (float)rightv.colors[i].rgba.r, &curve), 0.0f, 255.0f)); - v.colors[i].rgba.g = (u32)(clamp(SsInterpolate(SsInterpolationType::linear, now, (float)leftv.color.rgba.g, (float)rightv.colors[i].rgba.g, &curve), 0.0f, 255.0f)); - v.colors[i].rgba.b = (u32)(clamp(SsInterpolate(SsInterpolationType::linear, now, (float)leftv.color.rgba.b, (float)rightv.colors[i].rgba.b, &curve), 0.0f, 255.0f)); + v.colors[i].rate = clamp(SsInterpolate(SsInterpolationType::linear, easingRate , now, leftv.color.rate, rightv.colors[i].rate, &curve), 0.0f, 1.0f); + v.colors[i].rgba.a = (u32)(clamp(SsInterpolate(SsInterpolationType::linear, easingRate, now, (float)leftv.color.rgba.a, (float)rightv.colors[i].rgba.a, &curve), 0.0f, 255.0f)); + v.colors[i].rgba.r = (u32)(clamp(SsInterpolate(SsInterpolationType::linear, easingRate, now, (float)leftv.color.rgba.r, (float)rightv.colors[i].rgba.r, &curve), 0.0f, 255.0f)); + v.colors[i].rgba.g = (u32)(clamp(SsInterpolate(SsInterpolationType::linear, easingRate, now, (float)leftv.color.rgba.g, (float)rightv.colors[i].rgba.g, &curve), 0.0f, 255.0f)); + v.colors[i].rgba.b = (u32)(clamp(SsInterpolate(SsInterpolationType::linear, easingRate, now, (float)leftv.color.rgba.b, (float)rightv.colors[i].rgba.b, &curve), 0.0f, 255.0f)); } } else { //両方とも単色 - v.color.rate = clamp(SsInterpolate(SsInterpolationType::linear, now, leftv.color.rate, rightv.color.rate, &curve), 0.0f, 1.0f); - v.color.rgba.a = (u32)(clamp(SsInterpolate(SsInterpolationType::linear, now, (float)leftv.color.rgba.a, (float)rightv.color.rgba.a, &curve), 0.0f, 255.0f)); - v.color.rgba.r = (u32)(clamp(SsInterpolate(SsInterpolationType::linear, now, (float)leftv.color.rgba.r, (float)rightv.color.rgba.r, &curve), 0.0f, 255.0f)); - v.color.rgba.g = (u32)(clamp(SsInterpolate(SsInterpolationType::linear, now, (float)leftv.color.rgba.g, (float)rightv.color.rgba.g, &curve), 0.0f, 255.0f)); - v.color.rgba.b = (u32)(clamp(SsInterpolate(SsInterpolationType::linear, now, (float)leftv.color.rgba.b, (float)rightv.color.rgba.b, &curve), 0.0f, 255.0f)); + v.color.rate = clamp(SsInterpolate(SsInterpolationType::linear, easingRate, now, leftv.color.rate, rightv.color.rate, &curve), 0.0f, 1.0f); + v.color.rgba.a = (u32)(clamp(SsInterpolate(SsInterpolationType::linear, easingRate, now, (float)leftv.color.rgba.a, (float)rightv.color.rgba.a, &curve), 0.0f, 255.0f)); + v.color.rgba.r = (u32)(clamp(SsInterpolate(SsInterpolationType::linear, easingRate, now, (float)leftv.color.rgba.r, (float)rightv.color.rgba.r, &curve), 0.0f, 255.0f)); + v.color.rgba.g = (u32)(clamp(SsInterpolate(SsInterpolationType::linear, easingRate, now, (float)leftv.color.rgba.g, (float)rightv.color.rgba.g, &curve), 0.0f, 255.0f)); + v.color.rgba.b = (u32)(clamp(SsInterpolate(SsInterpolationType::linear, easingRate, now, (float)leftv.color.rgba.b, (float)rightv.color.rgba.b, &curve), 0.0f, 255.0f)); v.target = SsColorBlendTarget::whole; } } @@ -479,7 +579,8 @@ void SsAnimeDecoder::SsInterpolationValue( int time , const SsKeyframe* leftkey v.target = SsColorBlendTarget::vertex; v.blendType = leftv.blendType; - now = SsInterpolate( leftkey->ipType , now , 0.0f , 1.0f , &curve ); + float easingRate = leftkey->easingRate; + now = SsInterpolate( leftkey->ipType , easingRate , now , 0.0f , 1.0f , &curve ); if ( leftv.target == SsColorBlendTarget::vertex ) { @@ -488,11 +589,11 @@ void SsAnimeDecoder::SsInterpolationValue( int time , const SsKeyframe* leftkey //両方とも4頂点カラー for ( int i = 0 ; i < 4 ; i++ ) { - v.colors[i].rate = clamp( SsInterpolate( SsInterpolationType::linear , now , leftv.colors[i].rate , rightv.colors[i].rate , &curve ) , 0.0f , 1.0f ); - v.colors[i].rgba.a = (u32)(clamp( SsInterpolate( SsInterpolationType::linear , now , (float)leftv.colors[i].rgba.a , (float)rightv.colors[i].rgba.a , &curve ) , 0.0f , 255.0f )); - v.colors[i].rgba.r = (u32)(clamp( SsInterpolate( SsInterpolationType::linear , now , (float)leftv.colors[i].rgba.r , (float)rightv.colors[i].rgba.r , &curve ) , 0.0f , 255.0f )); - v.colors[i].rgba.g = (u32)(clamp( SsInterpolate( SsInterpolationType::linear , now , (float)leftv.colors[i].rgba.g , (float)rightv.colors[i].rgba.g , &curve ) , 0.0f , 255.0f )); - v.colors[i].rgba.b = (u32)(clamp( SsInterpolate( SsInterpolationType::linear , now , (float)leftv.colors[i].rgba.b , (float)rightv.colors[i].rgba.b , &curve ) , 0.0f , 255.0f )); + v.colors[i].rate = clamp( SsInterpolate( SsInterpolationType::linear , easingRate , now , leftv.colors[i].rate , rightv.colors[i].rate , &curve ) , 0.0f , 1.0f ); + v.colors[i].rgba.a = (u32)(clamp( SsInterpolate( SsInterpolationType::linear , easingRate, now , (float)leftv.colors[i].rgba.a , (float)rightv.colors[i].rgba.a , &curve ) , 0.0f , 255.0f )); + v.colors[i].rgba.r = (u32)(clamp( SsInterpolate( SsInterpolationType::linear , easingRate, now , (float)leftv.colors[i].rgba.r , (float)rightv.colors[i].rgba.r , &curve ) , 0.0f , 255.0f )); + v.colors[i].rgba.g = (u32)(clamp( SsInterpolate( SsInterpolationType::linear , easingRate, now , (float)leftv.colors[i].rgba.g , (float)rightv.colors[i].rgba.g , &curve ) , 0.0f , 255.0f )); + v.colors[i].rgba.b = (u32)(clamp( SsInterpolate( SsInterpolationType::linear , easingRate, now , (float)leftv.colors[i].rgba.b , (float)rightv.colors[i].rgba.b , &curve ) , 0.0f , 255.0f )); } } else @@ -500,11 +601,11 @@ void SsAnimeDecoder::SsInterpolationValue( int time , const SsKeyframe* leftkey //左は4頂点、右は単色 for ( int i = 0 ; i < 4 ; i++ ) { - v.colors[i].rate = clamp( SsInterpolate( SsInterpolationType::linear , now , leftv.colors[i].rate , rightv.color.rate , &curve ) , 0.0f , 1.0f ); - v.colors[i].rgba.a = (u32)(clamp( SsInterpolate( SsInterpolationType::linear , now , (float)leftv.colors[i].rgba.a , (float)rightv.color.rgba.a , &curve ) , 0.0f , 255.0f )); - v.colors[i].rgba.r = (u32)(clamp( SsInterpolate( SsInterpolationType::linear , now , (float)leftv.colors[i].rgba.r , (float)rightv.color.rgba.r , &curve ) , 0.0f , 255.0f )); - v.colors[i].rgba.g = (u32)(clamp( SsInterpolate( SsInterpolationType::linear , now , (float)leftv.colors[i].rgba.g , (float)rightv.color.rgba.g , &curve ) , 0.0f , 255.0f )); - v.colors[i].rgba.b = (u32)(clamp( SsInterpolate( SsInterpolationType::linear , now , (float)leftv.colors[i].rgba.b , (float)rightv.color.rgba.b , &curve ) , 0.0f , 255.0f )); + v.colors[i].rate = clamp( SsInterpolate( SsInterpolationType::linear , easingRate, now , leftv.colors[i].rate , rightv.color.rate , &curve ) , 0.0f , 1.0f ); + v.colors[i].rgba.a = (u32)(clamp( SsInterpolate( SsInterpolationType::linear , easingRate, now , (float)leftv.colors[i].rgba.a , (float)rightv.color.rgba.a , &curve ) , 0.0f , 255.0f )); + v.colors[i].rgba.r = (u32)(clamp( SsInterpolate( SsInterpolationType::linear , easingRate, now , (float)leftv.colors[i].rgba.r , (float)rightv.color.rgba.r , &curve ) , 0.0f , 255.0f )); + v.colors[i].rgba.g = (u32)(clamp( SsInterpolate( SsInterpolationType::linear , easingRate, now , (float)leftv.colors[i].rgba.g , (float)rightv.color.rgba.g , &curve ) , 0.0f , 255.0f )); + v.colors[i].rgba.b = (u32)(clamp( SsInterpolate( SsInterpolationType::linear , easingRate, now , (float)leftv.colors[i].rgba.b , (float)rightv.color.rgba.b , &curve ) , 0.0f , 255.0f )); } } } @@ -515,21 +616,21 @@ void SsAnimeDecoder::SsInterpolationValue( int time , const SsKeyframe* leftkey //左は単色、右は4頂点カラー for ( int i = 0 ; i < 4 ; i++ ) { - v.colors[i].rate = clamp( SsInterpolate( SsInterpolationType::linear , now , leftv.color.rate , rightv.colors[i].rate , &curve ) , 0.0f , 1.0f ); - v.colors[i].rgba.a = (u32)(clamp( SsInterpolate( SsInterpolationType::linear , now , (float)leftv.color.rgba.a , (float)rightv.colors[i].rgba.a , &curve ) , 0.0f , 255.0f )); - v.colors[i].rgba.r = (u32)(clamp( SsInterpolate( SsInterpolationType::linear , now , (float)leftv.color.rgba.r , (float)rightv.colors[i].rgba.r , &curve ) , 0.0f , 255.0f )); - v.colors[i].rgba.g = (u32)(clamp( SsInterpolate( SsInterpolationType::linear , now , (float)leftv.color.rgba.g , (float)rightv.colors[i].rgba.g , &curve ) , 0.0f , 255.0f )); - v.colors[i].rgba.b = (u32)(clamp( SsInterpolate( SsInterpolationType::linear , now , (float)leftv.color.rgba.b , (float)rightv.colors[i].rgba.b , &curve ) , 0.0f , 255.0f )); + v.colors[i].rate = clamp( SsInterpolate( SsInterpolationType::linear , easingRate, now , leftv.color.rate , rightv.colors[i].rate , &curve ) , 0.0f , 1.0f ); + v.colors[i].rgba.a = (u32)(clamp( SsInterpolate( SsInterpolationType::linear , easingRate, now , (float)leftv.color.rgba.a , (float)rightv.colors[i].rgba.a , &curve ) , 0.0f , 255.0f )); + v.colors[i].rgba.r = (u32)(clamp( SsInterpolate( SsInterpolationType::linear , easingRate, now , (float)leftv.color.rgba.r , (float)rightv.colors[i].rgba.r , &curve ) , 0.0f , 255.0f )); + v.colors[i].rgba.g = (u32)(clamp( SsInterpolate( SsInterpolationType::linear , easingRate, now , (float)leftv.color.rgba.g , (float)rightv.colors[i].rgba.g , &curve ) , 0.0f , 255.0f )); + v.colors[i].rgba.b = (u32)(clamp( SsInterpolate( SsInterpolationType::linear , easingRate, now , (float)leftv.color.rgba.b , (float)rightv.colors[i].rgba.b , &curve ) , 0.0f , 255.0f )); } } else { //両方とも単色 - v.color.rate = clamp( SsInterpolate( SsInterpolationType::linear , now , leftv.color.rate , rightv.color.rate , &curve ) , 0.0f , 1.0f ); - v.color.rgba.a = (u32)(clamp( SsInterpolate( SsInterpolationType::linear , now , (float)leftv.color.rgba.a , (float)rightv.color.rgba.a , &curve ) , 0.0f , 255.0f )); - v.color.rgba.r = (u32)(clamp( SsInterpolate( SsInterpolationType::linear , now , (float)leftv.color.rgba.r , (float)rightv.color.rgba.r , &curve ) , 0.0f , 255.0f )); - v.color.rgba.g = (u32)(clamp( SsInterpolate( SsInterpolationType::linear , now , (float)leftv.color.rgba.g , (float)rightv.color.rgba.g , &curve ) , 0.0f , 255.0f )); - v.color.rgba.b = (u32)(clamp( SsInterpolate( SsInterpolationType::linear , now , (float)leftv.color.rgba.b , (float)rightv.color.rgba.b , &curve ) , 0.0f , 255.0f )); + v.color.rate = clamp( SsInterpolate( SsInterpolationType::linear , easingRate, now , leftv.color.rate , rightv.color.rate , &curve ) , 0.0f , 1.0f ); + v.color.rgba.a = (u32)(clamp( SsInterpolate( SsInterpolationType::linear , easingRate, now , (float)leftv.color.rgba.a , (float)rightv.color.rgba.a , &curve ) , 0.0f , 255.0f )); + v.color.rgba.r = (u32)(clamp( SsInterpolate( SsInterpolationType::linear , easingRate, now , (float)leftv.color.rgba.r , (float)rightv.color.rgba.r , &curve ) , 0.0f , 255.0f )); + v.color.rgba.g = (u32)(clamp( SsInterpolate( SsInterpolationType::linear , easingRate, now , (float)leftv.color.rgba.g , (float)rightv.color.rgba.g , &curve ) , 0.0f , 255.0f )); + v.color.rgba.b = (u32)(clamp( SsInterpolate( SsInterpolationType::linear , easingRate, now , (float)leftv.color.rgba.b , (float)rightv.color.rgba.b , &curve ) , 0.0f , 255.0f )); v.target = SsColorBlendTarget::whole; } } @@ -571,12 +672,13 @@ void SsAnimeDecoder::SsInterpolationValue( int time , const SsKeyframe* leftkey v.param[2] = 0.0f; v.param[3] = 0.0f; - now = SsInterpolate( leftkey->ipType , now , 0.0f , 1.0f , &curve ); + float easingRate = leftkey->easingRate; + now = SsInterpolate( leftkey->ipType , easingRate , now , 0.0f , 1.0f , &curve ); - v.param[0] = SsInterpolate( SsInterpolationType::linear , now , leftv.param[0] , rightv.param[0] , &curve ); - v.param[1] = SsInterpolate( SsInterpolationType::linear , now , leftv.param[1] , rightv.param[1] , &curve ); - v.param[2] = SsInterpolate( SsInterpolationType::linear , now , leftv.param[2] , rightv.param[2] , &curve ); - v.param[3] = SsInterpolate( SsInterpolationType::linear , now , leftv.param[3] , rightv.param[3] , &curve ); + v.param[0] = SsInterpolate( SsInterpolationType::linear , easingRate , now , leftv.param[0] , rightv.param[0] , &curve ); + v.param[1] = SsInterpolate( SsInterpolationType::linear , easingRate , now , leftv.param[1] , rightv.param[1] , &curve ); + v.param[2] = SsInterpolate( SsInterpolationType::linear , easingRate , now , leftv.param[2] , rightv.param[2] , &curve ); + v.param[3] = SsInterpolate( SsInterpolationType::linear , easingRate , now , leftv.param[3] , rightv.param[3] , &curve ); } @@ -609,6 +711,19 @@ void SsAnimeDecoder::SsInterpolationValue( int time , const SsKeyframe* leftkey } +void SsAnimeDecoder::SsInterpolationValue(int time, const SsKeyframe* leftkey, const SsKeyframe* rightkey, SsAudioAttr& v) +{ + //補間は行わないので、常に左のキーを出力する + GetSsAudioAttr(leftkey, v); + +} + +void SsAnimeDecoder::SsInterpolationValue(int time, const SsKeyframe* leftkey, const SsKeyframe* rightkey, SsTexChangeAttr& v) +{ + //補間は行わないので、常に左のキーを出力する + GetSsTexChangeAttr(leftkey, v); + +} void SsAnimeDecoder::SsInterpolationValue(int time, const SsKeyframe* leftkey, const SsKeyframe* rightkey, SsDeformAttr& v) { @@ -638,7 +753,8 @@ void SsAnimeDecoder::SsInterpolationValue(int time, const SsKeyframe* leftkey, c curve.endKeyTime = (float)rightkey->time; } - float rate = SsInterpolate(leftkey->ipType, now, 0.0f, 1.0f, &curve); + float easingRate = leftkey->easingRate; + float rate = SsInterpolate(leftkey->ipType, easingRate , now, 0.0f, 1.0f, &curve); //スタートとエンドの頂点数を比較し、多い方に合わせる(足りない部分は0とみなす) int numPoints = std::max(static_cast(startValue.verticeChgList.size()), static_cast(endValue.verticeChgList.size())); @@ -663,7 +779,7 @@ void SsAnimeDecoder::SsInterpolationValue(int time, const SsKeyframe* leftkey, c { SsVector2 outVec; - outVec = SsInterpolate(SsInterpolationType::linear, rate, start[i], end[i], 0); + outVec = SsInterpolate(SsInterpolationType::linear, easingRate , rate, start[i], end[i], 0); v.verticeChgList.push_back(outVec); } @@ -688,6 +804,7 @@ void SsAnimeDecoder::SsInterpolationValue( int time , const SsKeyframe* leftkey int range = rightkey->time - leftkey->time; float now = (float)(time - leftkey->time) / range; + float easingRate = leftkey->easingRate; if (leftkey->ipType == SsInterpolationType::bezier) { // ベジェのみキーの開始・終了時間が必要 @@ -695,10 +812,10 @@ void SsAnimeDecoder::SsInterpolationValue( int time , const SsKeyframe* leftkey curve = leftkey->curve; curve.startKeyTime = (float)leftkey->time; curve.endKeyTime = (float)rightkey->time; - v = (mytype)(SsInterpolate( leftkey->ipType , now , v1 , v2 , &curve )); + v = (mytype)(SsInterpolate( leftkey->ipType , easingRate, now , v1 , v2 , &curve )); } else{ - v = (mytype)(SsInterpolate( leftkey->ipType , now , v1 , v2 , &leftkey->curve )); + v = (mytype)(SsInterpolate( leftkey->ipType , easingRate, now , v1 , v2 , &leftkey->curve )); } } @@ -821,6 +938,11 @@ void SsAnimeDecoder::updateState( int nowTime , SsPart* part , SsPartAnime* anim //ステートの初期値を設定 state->init(); + if (part->type == SsPartType::shape) + { + state->size = SsVector2(64.0f, 64.0f); + } + state->inheritRates = part->inheritRates; SsPartAnime* setupAnime = setupPartAnimeDic[part->name]; //セットアップアニメを取得する @@ -1072,6 +1194,12 @@ void SsAnimeDecoder::updateState( int nowTime , SsPart* part , SsPartAnime* anim state->is_defrom = true; SsGetKeyValue(part, nowTime, attr, state->deformValue); break; + case SsAttributeKind::audio: + SsGetKeyValue(part, nowTime, attr, state->audioValue); + break; + case SsAttributeKind::texchange: + SsGetKeyValue(part, nowTime, attr, state->changeTextureValue); + break; } } @@ -1118,7 +1246,7 @@ void SsAnimeDecoder::updateState( int nowTime , SsPart* part , SsPartAnime* anim } // 頂点の設定 - if ( part->type == SsPartType::normal || part->type == SsPartType::mask ) + if ( part->type == SsPartType::normal || part->type == SsPartType::mask || part->type == SsPartType::text ) { SsCell * cell = state->cellValue.cell; if (cell && ( anime || setupAnime ) ) @@ -1132,6 +1260,12 @@ void SsAnimeDecoder::updateState( int nowTime , SsPart* part , SsPartAnime* anim } + // add SS7.1 + if (part->type == SsPartType::nines || + part->type == SsPartType::shape ) //|| + { + updateVertices(part, anime, state); + } } @@ -1188,14 +1322,185 @@ void SsAnimeDecoder::updateMatrix(SsPart* part , SsPartAnime* anime , SsPartStat } +void SsAnimeDecoder::updateShape(SsPart* part , SsPartState* state) +{ + + if (part->m_pPartValueInfo->getTag() == SsPartValueShape::TAG) + { + SsPartValue* value = part->m_pPartValueInfo.get(); + SsPartValueShape* valueShape = static_cast(value); + + valueShape->setSize(SsSizeF( state->size.x, state->size.y)); + + } +} + + +class SsPartValueTextDraw : public SsPartValueText +{ +public: + SsPartValueTextDraw() {} + + virtual ~SsPartValueTextDraw() {} + + virtual bool update() + { + } + +}; + + +//bool SsPartValueText::update()とほぼ等価 +static SsFontTexture* getFontTexture(SsProject* project , FontTextureManager* fontman , SsPartValueText* textvalue) +{ + if (fontman) + { + //bitmap Imageを作成 同じ条件の場合は同じImageを帰すs + std::pair text_desc = fontman->findShareTexture( + textvalue->getText(), + textvalue->getFontDesc(), + SsSize(0, 0), + SsSize(textvalue->getWidth(), textvalue->getHeight()) + ); + + //SsRawImage* image = text_desc.first; + SsFontTexture* textDrawTex = text_desc.second; + + if (textvalue->needUpdate()) + { + textDrawTex->setPartValue(textvalue); + + //以下は setPartValue してるのでそっちで取った方が一貫性あると思う + SsString text = textvalue->getText(); + textDrawTex->setText(text); + textDrawTex->setFontDesc(textvalue->getFontDesc()); + textDrawTex->setGridSize(SsSize(0, 0)); + textDrawTex->setFixedSize(SsSize(textvalue->getWidth(), textvalue->getHeight())); + + //使用するCharaMapを特定する + if (textvalue->isBitmap()) + { + SsCharMap* pCharMap = project->findCharMap(textvalue->getCharMap()); + + textDrawTex->setCharMap(pCharMap); + } + + textDrawTex->update(); + + + } + + return textDrawTex; + } + + return 0; +} + + +void SsAnimeDecoder::updateText(SsPart* part , SsPartState* state) +{ + if (part->m_pPartValueInfo->getTag() == SsPartValueText::TAG) + { + SsPartValue* value = part->m_pPartValueInfo.get(); + SsPartValueText* valueText = static_cast(value); + + //valueText->setText(part->text.c_str()); + + //valueText->updateが中呼ばれていた。 + //valueTextの中でFontTetxtureのUpdateが必要な場合に再構築を行っていた + //Loaderに配置できない関係から別途こちら側に関数化を行う + + + SsFontTexture* fontTex = getFontTexture(this->project,this->getFontmanager(),valueText); + + // + state->cellValue.texture = fontTex->getTexture(); + if (state->cellValue.texture) + { + state->cellValue.cell = fontTex->getCell(); + //state->cellValue.calcUvs(); + + state->cellValue.uvs[0] = SsVector2(0, 0); + state->cellValue.uvs[1] = SsVector2(1.0f, 0); + state->cellValue.uvs[2] = SsVector2(0.0f, 1.0f); + state->cellValue.uvs[3] = SsVector2(1.0f, 1.0f); + state->cellValue.uvs[4] = SsVector2(0, 0); + + + state->cellValue.filterMode = fontTex->getCellMap()->filterMode; + state->cellValue.wrapMode = fontTex->getCellMap()->wrapMode; + + } + else { + state->noCells = true; + } + + int debug = 1; + + } + +} + +void SsAnimeDecoder::updateNineSlice(SsPart* part , SsPartState* state) +{ + SsPartValue* value = part->m_pPartValueInfo.get(); + + if (!value) { + return; + } + if (value->getTag() != SsPartValueNines::TAG) { + return; + } + + SsPartValueNines* valueNines = static_cast(value); + + SsCell* pCell = state->cellValue.cell; + + //SsCellMap* pCellMap = pCell ? pCell->map : nullptr; + ISSTexture* pCellMap = pCell ? state->cellValue.texture : nullptr; + + SsRectF coord; + SsRectF region; + + if (pCell) { + coord.setRect(pCell->pos.x, pCell->pos.y, pCell->size.x, pCell->size.y); + region = SsRectF(SsPoint2(), SsSize(coord.width(), coord.height())); + } + if (pCellMap) { + region = SsRectF(SsPoint2(), SsSize(pCellMap->getWidth(), pCellMap->getHeight())); + } + + valueNines->setCoord(coord); + valueNines->setRegion(region); + valueNines->setSize(SsSizeF(state->size.x, state->size.y)); +} void SsAnimeDecoder::updateVertices(SsPart* part , SsPartAnime* anime , SsPartState* state) { + static SsCellValue* refCellDebug = 0; SsCell * cell = state->cellValue.cell; SsVector2 pivot; + if (part->type == SsPartType::shape) + { + updateShape(part ,state); + cell = nullptr; + } + if (part->type == SsPartType::text) + { + updateText(part,state); + + cell = state->cellValue.cell; + + } + + if (part->type == SsPartType::nines) + { + updateNineSlice(part, state); + } + if (cell) { // セルに設定された原点オフセットを適用する @@ -1683,5 +1988,5 @@ void SsAnimeDecoder::draw() SsCurrentRenderer::getRender()->enableMask(false); } -} // namespace spritestudio6 +} // namespace SpriteStudio diff --git a/Common/Animator/ssplayer_animedecode.h b/Common/Animator/ssplayer_animedecode.h index 28a4d6df..8bdb3241 100644 --- a/Common/Animator/ssplayer_animedecode.h +++ b/Common/Animator/ssplayer_animedecode.h @@ -8,8 +8,9 @@ #include "ssplayer_types.h" #include "ssplayer_cellmap.h" #include "ssplayer_PartState.h" -#include "ssplayer_macro.h" +#include "ssplayer_math.h" #include "ssplayer_mesh.h" +#include "ssplayer_fonttexmng.h" #include @@ -18,7 +19,7 @@ //0の場合はZ型の2ポリゴンで変形します。 #define SPRITESTUDIO6SDK_USE_TRIANGLE_FIN (1) -namespace spritestudio6 +namespace SpriteStudio { @@ -48,6 +49,7 @@ namespace spritestudio6 ///プロジェクト情報 SsProject* project; + FontTextureManager* fontTexManager; ///パーツ情報とパーツアニメーションを結びつけアレイにしたもの std::vector partAnime; @@ -144,6 +146,8 @@ namespace spritestudio6 void SsInterpolationValue( int time , const SsKeyframe* leftkey , const SsKeyframe* rightkey , SsInstanceAttr& v ); void SsInterpolationValue( int time , const SsKeyframe* leftkey , const SsKeyframe* rightkey , SsEffectAttr& v ); void SsInterpolationValue( int time , const SsKeyframe* leftkey , const SsKeyframe* rightkey , SsDeformAttr& v ); + void SsInterpolationValue(int time, const SsKeyframe* leftkey, const SsKeyframe* rightkey, SsAudioAttr& v); + void SsInterpolationValue(int time, const SsKeyframe* leftkey, const SsKeyframe* rightkey, SsTexChangeAttr& v); void setInstancePartsHide(bool hide){ @@ -159,9 +163,32 @@ namespace spritestudio6 void setMaskParentSetting(bool flg); //親のマスク対象を設定する bool getMaskParentSetting(void) { return maskParentSetting; }; //設定された親のマスク対象を取得する + //特殊パーツ系の初期化 + void initPartTypeInstance(SsPart* p , SsPartState& state); + void initPartTypeEffect(SsPart* p , SsPartState& state); + void initPartTypeMask(SsPart* p, SsPartState& state); + void initPartTypeMesh(SsPart* p, SsPartState& state); + + //add SS7.1 + void initPartTypeShape(SsPart* p, SsPartState& state); + void initPartTypeText(SsPart* p, SsPartState& state); + void initPartTypeNineslice(SsPart* p, SsPartState& state); + void initPartTypeAudio(SsPart* p, SsPartState& state); + + void updateShape(SsPart* part , SsPartState* state ); + void updateText(SsPart* part , SsPartState* state ); + void updateNineSlice(SsPart* part , SsPartState* state ); + + void setFontManager(FontTextureManager* manager) + { + fontTexManager = manager; + } + + FontTextureManager* getFontmanager() { return fontTexManager; } + }; -} // namespace spritestudio6 +} // namespace SpriteStudio #endif diff --git a/Common/Animator/ssplayer_cellmap.cpp b/Common/Animator/ssplayer_cellmap.cpp index 13ddb48a..17ca897b 100644 --- a/Common/Animator/ssplayer_cellmap.cpp +++ b/Common/Animator/ssplayer_cellmap.cpp @@ -15,7 +15,7 @@ #include -namespace spritestudio6 +namespace SpriteStudio { bool SsCellMapList::preloadTexture(SsProject* proj) @@ -251,5 +251,5 @@ void calcUvs( SsCellValue* cellv ) } } -} // namespace spritestudio6 +} // namespace SpriteStudio diff --git a/Common/Animator/ssplayer_cellmap.h b/Common/Animator/ssplayer_cellmap.h index b52255b9..4b0dbfaa 100644 --- a/Common/Animator/ssplayer_cellmap.h +++ b/Common/Animator/ssplayer_cellmap.h @@ -5,7 +5,7 @@ #include -namespace spritestudio6 +namespace SpriteStudio { class SsAnimeDecoder; @@ -24,8 +24,73 @@ struct SsCellValue cell(0) , texture(0) {} + + int convPow2(int n) + { + for (int i = 0; i < 30; i++) + { + if (n <= (1 << i)) + { + return 1 << i; + } + } + return 0x40000000; + } + + SsCellValue& operator =(SsCellValue& r) { + this->cell = r.cell; + this->texture = r.texture; + for (int i = 0; i < 5; i++) + { + uvs[i] = r.uvs[i]; + } + this->wrapMode = r.wrapMode; + this->filterMode = r.filterMode; + + return *this; + } + + void calcUvs() + { + if (texture == nullptr) return; + SsVector2 wh = SsVector2(texture->getWidth(), texture->getHeight()); + + wh.x = convPow2(wh.x); + wh.y = convPow2(wh.y); + + // 右上に向かって+になる + float left = cell->pos.x / wh.x; + float right = (cell->pos.x + cell->size.x) / wh.x; + // LB->RB->LT->RT 順 + // 頂点をZ順にしている都合上UV値は上下逆転させている + float top = cell->pos.y / wh.y; + float bottom = (cell->pos.y + cell->size.y) / wh.y; + + if (cell->rotated) + { + // 反時計回りに90度回転されているため起こして描画されるようにしてやる。 + // 13 + // 02 + uvs[0].x = uvs[1].x = left; + uvs[2].x = uvs[3].x = right; + uvs[1].y = uvs[3].y = top; + uvs[0].y = uvs[2].y = bottom; + } + else + { + // そのまま。頂点の順番は下記の通り + // 01 + // 23 + uvs[0].x = uvs[2].x = left; + uvs[1].x = uvs[3].x = right; + uvs[0].y = uvs[1].y = top; + uvs[2].y = uvs[3].y = bottom; + } + } }; + +//cellMapは数値、文字列のみの情報としているので画像ファイルの実体と紐づける class SsCelMapLinker { public: @@ -123,6 +188,6 @@ void getCellValue( SsCellMapList* cellList, SsString& cellMapName , SsString& ce void calcUvs( SsCellValue* cellv ); -} // namespace spritestudio6 +} // namespace SpriteStudio #endif diff --git a/Common/Animator/ssplayer_effect.cpp b/Common/Animator/ssplayer_effect.cpp index 0d1444f6..6e5b4e64 100644 --- a/Common/Animator/ssplayer_effect.cpp +++ b/Common/Animator/ssplayer_effect.cpp @@ -5,13 +5,13 @@ #include "ssplayer_animedecode.h" #include "ssplayer_effect.h" -#include "ssplayer_macro.h" +#include "ssplayer_math.h" #include "ssplayer_matrix.h" #include "ssplayer_render.h" #include "ssplayer_effectfunction.h" -namespace spritestudio6 +namespace SpriteStudio { @@ -832,6 +832,6 @@ bool SsEffectRenderer::getPlayStatus(void) -} // namespace spritestudio6 +} // namespace SpriteStudio diff --git a/Common/Animator/ssplayer_effect.h b/Common/Animator/ssplayer_effect.h index ebfd7a5b..ddbfd55c 100644 --- a/Common/Animator/ssplayer_effect.h +++ b/Common/Animator/ssplayer_effect.h @@ -11,7 +11,7 @@ // PFMEM_TEST #define SPRITESTUDIO6SDK_PFMEM_TEST ( 1 ) -namespace spritestudio6 +namespace SpriteStudio { class SsEffectModel; @@ -526,6 +526,6 @@ class SsEffectRenderer }; -} // namespace spritestudio6 +} // namespace SpriteStudio #endif \ No newline at end of file diff --git a/Common/Animator/ssplayer_effect2.cpp b/Common/Animator/ssplayer_effect2.cpp index 29d13269..6fa99c8b 100644 --- a/Common/Animator/ssplayer_effect2.cpp +++ b/Common/Animator/ssplayer_effect2.cpp @@ -6,7 +6,7 @@ #include "ssplayer_animedecode.h" #include "ssplayer_effect2.h" -#include "ssplayer_macro.h" +#include "ssplayer_math.h" #include "ssplayer_matrix.h" #include "ssplayer_render.h" #include "ssplayer_effectfunction.h" @@ -16,7 +16,7 @@ #define SPRITESTUDIO6SDK_DEBUG_DISP (0) #define SPRITESTUDIO6SDK_BUILD_ERROR_0418 (0) -namespace spritestudio6 +namespace SpriteStudio { @@ -972,5 +972,5 @@ int SsEffectRenderV2::getCurrentFPS(){ return 30; } -} // namespace spritestudio6 +} // namespace SpriteStudio diff --git a/Common/Animator/ssplayer_effect2.h b/Common/Animator/ssplayer_effect2.h index 71b3e88c..62df858d 100644 --- a/Common/Animator/ssplayer_effect2.h +++ b/Common/Animator/ssplayer_effect2.h @@ -17,7 +17,7 @@ #define SPRITESTUDIO6SDK_LOOP_TYPE2 (0) #define SPRITESTUDIO6SDK_LOOP_TYPE3 (1) -namespace spritestudio6 +namespace SpriteStudio { class SsEffectModel; @@ -479,6 +479,6 @@ class SsEffectRenderV2 }; -} // namespace spritestudio6 +} // namespace SpriteStudio #endif \ No newline at end of file diff --git a/Common/Animator/ssplayer_effectfunction.cpp b/Common/Animator/ssplayer_effectfunction.cpp index 055d7f9d..c79a95dc 100644 --- a/Common/Animator/ssplayer_effectfunction.cpp +++ b/Common/Animator/ssplayer_effectfunction.cpp @@ -4,13 +4,13 @@ #include "../Loader/ssloader.h" #include "ssplayer_animedecode.h" #include "ssplayer_effect.h" -#include "ssplayer_macro.h" +#include "ssplayer_math.h" #include "ssplayer_matrix.h" #include "ssplayer_render.h" #include "ssplayer_effectfunction.h" -namespace spritestudio6 +namespace SpriteStudio { @@ -935,4 +935,4 @@ void SsEffectFunctionExecuter::initializeEffect( SsEffectBehavior* beh , SsEffe -} // namespace spritestudio6 +} // namespace SpriteStudio diff --git a/Common/Animator/ssplayer_effectfunction.h b/Common/Animator/ssplayer_effectfunction.h index 79a6d512..d0f46ed1 100644 --- a/Common/Animator/ssplayer_effectfunction.h +++ b/Common/Animator/ssplayer_effectfunction.h @@ -4,7 +4,7 @@ #include "ssplayer_effect.h" #include "ssplayer_effect2.h" -namespace spritestudio6 +namespace SpriteStudio { class SsEffectFunctionExecuter @@ -26,6 +26,6 @@ class SsEffectFunctionExecuter }; -} // namespace spritestudio6 +} // namespace SpriteStudio #endif diff --git a/Common/Animator/ssplayer_fonttexmng.cpp b/Common/Animator/ssplayer_fonttexmng.cpp new file mode 100644 index 00000000..7b1cc132 --- /dev/null +++ b/Common/Animator/ssplayer_fonttexmng.cpp @@ -0,0 +1,123 @@ +#include "ssplayer_fonttexmng.h" +#include "sstypes.h" +#include "../Loader/ssloader_sspj.h" + + +//#include "../Helper/IsshTexture.h" +#include "../Helper/DebugPrint.h" +#include "../Helper/SsRawImage.h" + +namespace SpriteStudio +{ + FontTextureManager::FontTextureManager() + { + + } + + FontTextureManager::FontTextureManager(SsProject* myproject) + { + loadTextureFromProject(myproject); + } + + FontTextureManager::~FontTextureManager() + { + releaseRawImageAll(); + releasePartsTextureAll(); + } + + std::pair FontTextureManager::findShareTexture(const SsString& text, const SsFontDesc& desc, const SsSize& sizeGrid, const SsSize& sizeFixed) + { + for (auto e : m_part_textures) + { + if (e.compare(text, desc, sizeGrid, sizeFixed)) + { + return std::make_pair(e.image, e.fontTexture); + } + } + + ShareTextureDesc sharedesc; + sharedesc.text = text; + sharedesc.desc = desc; + sharedesc.sizeGrid = sizeGrid; + sharedesc.sizeFixed = sizeFixed; + + SsRawImage* image = new SsRawImage(); + image->create(sizeFixed.width(), sizeFixed.height()); + + sharedesc.image = new SsRawImage(); + sharedesc.fontTexture = new SsFontTexture(); + //sharedesc.fontTexture->setProject(myproject); + + m_part_textures.push_back(sharedesc); + + return std::make_pair(sharedesc.image, sharedesc.fontTexture); + } + + + //RAWC[WێĂ + //RAWC[Wp[cƂ̃eNX`𐶐邽߂̑fނƂăLbV + bool FontTextureManager::loadTextureFromProject(SsProject* pj) + { + + for (auto& item : pj->charmapDic) + { + SsCharMap* c = item.second.get(); + const std::list pages = c->getCharMapPages(); + for (auto n : pages) + { + int width, height, bpp; + + SsString loadfile = n->getFilenamePath(); + + if (m_charamap_images.count(loadfile) > 0) + { + DEBUG_PRINTF("Font RawImage Exist : %s \n", loadfile.c_str()); + + n->imagePtr = m_charamap_images[loadfile].imgptr; + } + else { + + SsRawImage* image = new SsRawImage(); + bool ret = image->Load(loadfile.c_str()); + + if (!ret) + { + DEBUG_PRINTF("Texture Load Failed : %s \n", loadfile.c_str()); + } + + CharaMapImage imageInfo; + imageInfo.bpp = image->getBpp(); + imageInfo.width = image->getWidth(); + imageInfo.height = image->getHeight(); + imageInfo.imgptr = image; + + n->imagePtr = image; + m_charamap_images[loadfile] = imageInfo; + DEBUG_PRINTF("Font RawImage cached : %s \n", loadfile.c_str()); + } + } + } + + return true; + } + + void FontTextureManager::releaseRawImageAll() + { + for (auto i : m_charamap_images) + { + //SSTextureLoader::DecodeEndImageFile(i.second.imgptr);//free + delete i.second.imgptr; + } + m_charamap_images.clear(); + } + + void FontTextureManager::releasePartsTextureAll() + { + for (auto i : m_part_textures) + { + i.release(); + } + } + + +}; \ No newline at end of file diff --git a/Common/Animator/ssplayer_fonttexmng.h b/Common/Animator/ssplayer_fonttexmng.h new file mode 100644 index 00000000..e37f168a --- /dev/null +++ b/Common/Animator/ssplayer_fonttexmng.h @@ -0,0 +1,83 @@ +#ifndef __SSPLAYER_FONTMNG__ +#define __SSPLAYER_FONTMNG__ + +#include "../Helper/SsTextureFactory.h" +#include "font/ssfonttexture.h" +#include "sstypes.h" +#include + + +namespace SpriteStudio +{ + class SsProject; + + class FontTextureManager + { + private : + class ShareTextureDesc + { + public: + SsString text; + SsFontDesc desc; + SsSize sizeGrid; + SsSize sizeFixed; + SsRawImage* image; + SsFontTexture* fontTexture; + + bool compare(const SsString text, + const SsFontDesc& desc, + const SsSize& sizeGrid, + const SsSize& sizeFixed + ) { + return + (text == this->text && + desc == this->desc && + sizeGrid == this->sizeGrid && + sizeFixed == this->sizeFixed + ); + } + + void release() + { + delete fontTexture; + fontTexture = 0; + delete image; + image = 0; + } + }; + + public: + struct CharaMapImage { + int width; + int height; + int bpp; + SsRawImage* imgptr; + }; + + private: + std::map m_charamap_images; + std::vector m_part_textures; + + public: + + std::pair findShareTexture(const SsString& text, const SsFontDesc& desc, const SsSize& sizeGrid, const SsSize& sizeFixed); + + FontTextureManager(); + FontTextureManager(SsProject* myproject); + + virtual ~FontTextureManager(); + + //SsProjectN_ƂătHgt@C[h܂B + bool loadTextureFromProject(SsProject* pj); + + void releaseRawImageAll(); + void releasePartsTextureAll(); + + + }; + + +}; + +#endif + diff --git a/Common/Animator/ssplayer_math.cpp b/Common/Animator/ssplayer_math.cpp new file mode 100644 index 00000000..f044f88d --- /dev/null +++ b/Common/Animator/ssplayer_math.cpp @@ -0,0 +1,98 @@ + +#include "ssplayer_math.h" + +namespace SpriteStudio +{ + + + SsMath::SsMath() + { + } + + SsMath::~SsMath() + { + } + + int SsMath::convPow2(int n) + { + for (int i = 0; i < 30; i++) { + if (n <= (1 << i)) { + return 1 << i; + } + } + + return 0x40000000; + } + + bool SsMath::isPow2(int n) + { + for (int i = 0; i < 30; i++) { + if (n == (1 << i)) { + return true; + } + } + + return false; + } + + int SsMath::Floor(const float X) + { + return static_cast(floor(X)); + } + + int SsMath::Ceil(const float X) + { + return static_cast(ceil(X)); + } + + double SsMath::RoundTo(double dValue, int iDigit) + { + double dHi = floor(dValue); + double dLo = dValue - dHi; + double dMul = 1; + + if (iDigit < 0) { + for (int i = 0; i > iDigit; i--) { + dMul *= 10; + } + dValue = dHi + floor(dLo * dMul) / dMul; + } + else { + for (int i = 0; i < iDigit; i++) { + dMul *= 0.1; + } + dValue = floor(dHi * dMul) / dMul; + } + + return dValue; + } + + SsIRect SsMath::adjustInside(const SsIRect& rect, const SsIRect& region) + { + SsIRect result = rect; + SsIRect inside = region; + + inside.moveRight(inside.right() - result.width()); + inside.moveBottom(inside.bottom() - result.height()); + + if (result.left() < inside.left()) { + result.moveLeft(inside.left()); + } + else + if (result.left() > inside.right()) { + result.moveLeft(inside.right()); + } + + if (result.top() < inside.top()) { + result.moveTop(inside.top()); + } + else + if (result.top() > inside.bottom()) { + result.moveTop(inside.bottom()); + } + + return result; + } + + +}; // namespace SpriteStudio diff --git a/Common/Animator/ssplayer_math.h b/Common/Animator/ssplayer_math.h new file mode 100644 index 00000000..2553d13a --- /dev/null +++ b/Common/Animator/ssplayer_math.h @@ -0,0 +1,57 @@ +#ifndef __SSPLAYER_MACRO__ +#define __SSPLAYER_MACRO__ + +#include +#include "sstypes.h" + +namespace SpriteStudio +{ +#if 0 + constexpr auto __PI__ = (3.14159265358979323846f); + // #define RadianToDegree(Radian) ((double)Radian * (180.0f / __PI__)) + template inline double RadianToDegree(T Radian) + { + return((double)Radian * (180.0f / __PI__)); + } + // #define DegreeToRadian(Degree) ((double)Degree * (__PI__ / 180.0f)) + template inline double DegreeToRadian(T Degree) + { + return((double)Degree * (__PI__ / 180.0f)); + } + +#endif + + #define SPRITESTUDIO6SDK_foreach(T, c, i) for(T::iterator i = c.begin(); i!=c.end(); ++i) + + #define SS_PI ( 3.14159265358979323846f ) + #define RadianToDegree( _r ) ( static_cast( _r ) * ( 180.0f / SS_PI ) ) + #define DegreeToRadian( _d ) ( static_cast( _d ) * ( SS_PI / 180.0f ) ) + + #define SS_MAX( _l, _r ) ( ( ( _l ) > ( _r ) ) ? ( _l ) : ( _r ) ) + #define SS_MIN( _l, _r ) ( ( ( _l ) < ( _r ) ) ? ( _l ) : ( _r ) ) + + #define SS_SINF( _r ) ( sinf( _r ) ) + #define SS_COSF( _r ) ( cosf( _r ) ) + + class SsMath + { + private: + SsMath(); + ~SsMath(); + + public: + static int convPow2(int n); + static bool isPow2(int n); + + static int Floor(const float X); + static int Ceil(const float X); + + static double RoundTo(double dValue, int iDigit); + + static SsIRect adjustInside(const SsIRect& rect, const SsIRect& region); + }; + + +} // namespace SpriteStudio + +#endif diff --git a/Common/Animator/ssplayer_matrix.cpp b/Common/Animator/ssplayer_matrix.cpp index 84fb57c0..82765870 100644 --- a/Common/Animator/ssplayer_matrix.cpp +++ b/Common/Animator/ssplayer_matrix.cpp @@ -5,7 +5,7 @@ #include #include -namespace spritestudio6 +namespace SpriteStudio { @@ -460,4 +460,4 @@ void SsOpenGLMatrix::TransformVector3(SsVector3& src, SsVector3& dst) } -} // namespace spritestudio6 +} // namespace SpriteStudio diff --git a/Common/Animator/ssplayer_matrix.h b/Common/Animator/ssplayer_matrix.h index 133e7d92..bc1b54b1 100644 --- a/Common/Animator/ssplayer_matrix.h +++ b/Common/Animator/ssplayer_matrix.h @@ -4,7 +4,7 @@ #include "../Loader/sstypes.h" #include -namespace spritestudio6 +namespace SpriteStudio { void IdentityMatrix( float* matrix ); @@ -162,7 +162,7 @@ class SsOpenGLMatrix }; -} // namespace spritestudio6 +} // namespace SpriteStudio #endif diff --git a/Common/Animator/ssplayer_mesh.cpp b/Common/Animator/ssplayer_mesh.cpp index e6c76c60..1ad0d613 100644 --- a/Common/Animator/ssplayer_mesh.cpp +++ b/Common/Animator/ssplayer_mesh.cpp @@ -5,11 +5,11 @@ #include "ssplayer_animedecode.h" #include "ssplayer_mesh.h" -#include "ssplayer_macro.h" +#include "ssplayer_math.h" #include "ssplayer_matrix.h" // #include "ssplayer_animedecode.h" -namespace spritestudio6 +namespace SpriteStudio { @@ -455,4 +455,4 @@ void SsMeshAnimator::modelLoad() } } -} // namespace spritestudio6 +} // namespace SpriteStudio diff --git a/Common/Animator/ssplayer_mesh.h b/Common/Animator/ssplayer_mesh.h index eaa5ca49..2e4b124d 100644 --- a/Common/Animator/ssplayer_mesh.h +++ b/Common/Animator/ssplayer_mesh.h @@ -4,7 +4,7 @@ #include -namespace spritestudio6 +namespace SpriteStudio { class ISSTexture; @@ -181,6 +181,6 @@ class SsMeshAnimator -} // namespace spritestudio6 +} // namespace SpriteStudio #endif diff --git a/Common/Animator/ssplayer_render.cpp b/Common/Animator/ssplayer_render.cpp index 66942f3a..ae22682b 100644 --- a/Common/Animator/ssplayer_render.cpp +++ b/Common/Animator/ssplayer_render.cpp @@ -1,8 +1,8 @@ #include "ssplayer_render.h" -namespace spritestudio6 +namespace SpriteStudio { ISsRenderer* SsCurrentRenderer::m_currentrender = 0; -} // namespace spritestudio6 +} // namespace SpriteStudio diff --git a/Common/Animator/ssplayer_render.h b/Common/Animator/ssplayer_render.h index 997c2217..58f7ffe4 100644 --- a/Common/Animator/ssplayer_render.h +++ b/Common/Animator/ssplayer_render.h @@ -5,7 +5,7 @@ #include "../Loader/sstypes.h" -namespace spritestudio6 +namespace SpriteStudio { struct SsPartState; @@ -58,6 +58,6 @@ class SsCurrentRenderer }; -} // namespace spritestudio6 +} // namespace SpriteStudio #endif diff --git a/Common/Animator/ssplayer_types.h b/Common/Animator/ssplayer_types.h index adf651bc..33587e16 100644 --- a/Common/Animator/ssplayer_types.h +++ b/Common/Animator/ssplayer_types.h @@ -5,10 +5,10 @@ #include "../Helper/ssHelper.h" -namespace spritestudio6 +namespace SpriteStudio { -} // namespace spritestudio6 +} // namespace SpriteStudio #endif diff --git a/Common/Animator/xorshift32.h b/Common/Animator/xorshift32.h index dbf62374..de61dc98 100644 --- a/Common/Animator/xorshift32.h +++ b/Common/Animator/xorshift32.h @@ -1,7 +1,7 @@ #ifndef __XORSHIFT32__ #define __XORSHIFT32__ -namespace spritestudio6 +namespace SpriteStudio { #ifdef WIN32 @@ -46,7 +46,7 @@ class xorshift32 } ; -} // namespace spritestudio6 +} // namespace SpriteStudio #endif diff --git a/Common/Drawer/ssopenglninesdrawer.cpp b/Common/Drawer/ssopenglninesdrawer.cpp new file mode 100644 index 00000000..d3376019 --- /dev/null +++ b/Common/Drawer/ssopenglninesdrawer.cpp @@ -0,0 +1,233 @@ +#include "ssopenglninesdrawer.h" + +#include "ssOpenGLSetting.h" + + + +namespace SpriteStudio +{ + class QuadLeap + { + public: + class Rate + { + public: + Rate() + { + set(0.0f, 0.0f, 0.0f, 0.0f); + } + + ~Rate() + { + } + + void set(float fLT, float fRT, float fLB, float fRB) + { + m_fLT = fLT; + m_fRT = fRT; + m_fLB = fLB; + m_fRB = fRB; + } + + float getLT() const + { + return m_fLT; + } + + float getRT() const + { + return m_fRT; + } + + float getLB() const + { + return m_fLB; + } + + float getRB() const + { + return m_fRB; + } + + private: + float m_fLT; + float m_fRT; + float m_fLB; + float m_fRB; + }; + + QuadLeap() + { + set(-0.5f, 0.5f, 0.5f, -0.5); + } + + ~QuadLeap() + { + } + + void set(float fL, float fR, float fT, float fB) + { + m_fL = fL; + m_fR = fR; + m_fT = fT; + m_fB = fB; + } + + void updateRate(const SsPoint2& point) + { + float fL = 0.0f; + float fR = 0.0f; + float fT = 0.0f; + float fB = 0.0f; + float fH = 0.0f; + float fV = 0.0f; + float fX = 0.0f; + float fY = 0.0f; + + if (m_fL < m_fR) { + fL = m_fL; + fR = m_fR; + } + else { + fL = m_fR; + fR = m_fL; + } + + if (m_fT < m_fB) { + fT = m_fT; + fB = m_fB; + } + else { + fT = m_fB; + fB = m_fT; + } + + fH = fR - fL; + fV = fB - fT; + + fX = (point.x - fL) / fH; + fY = (point.y - fT) / fV; + + if (m_fL < m_fR) { + fX = 1.0f - fX; + } + + if (m_fT < m_fB) { + fY = 1.0f - fY; + } + + m_Rate.set( + fX * fY, + (1.0f - fX) * fY, + fX * (1.0f - fY), + (1.0f - fX) * (1.0f - fY) + ); + } + + template + T getLeapValue(const T& vLT, const T& vRT, const T& vLB, const T& vRB) + { + return (vLT * m_Rate.getLT()) + (vRT * m_Rate.getRT()) + (vLB * m_Rate.getLB()) + (vRB * m_Rate.getRB()); + } + + private: + float m_fL; + float m_fR; + float m_fT; + float m_fB; + + Rate m_Rate; + }; + + SsOpenGLNinesDrawer::SsOpenGLNinesDrawer() + { + } + + bool SsOpenGLNinesDrawer::execute(const SsNines& nines, const float* vertices, const float* colors) + { + const SsPolygon& polygon = nines.getPolygon(); + int iVertexCount = polygon.getVertexCount(); + int iVertexIndexCount = polygon.getVertexIndexCount(); + + if (iVertexCount >= 3) { + const std::list& listVertex = polygon.getVertices(); + const std::list& listVertexIndex = polygon.getVertexIndices(); + const std::list& listStride = polygon.getStrides(); + + int iVertexSize = sizeof(float) * 3; + int iCoordSize = sizeof(float) * 2; + int iColorSize = sizeof(float) * 4; + int iIndexSize = sizeof(uint16_t) * 1; + float* pVertices = (float*)malloc(iVertexSize * iVertexCount); + float* pCoords = (float*)malloc(iCoordSize * iVertexCount); + float* pColors = (float*)malloc(iColorSize * iVertexCount); + //ushort* pIndices = (ushort*)malloc(iIndexSize * iVertexIndexCount); + uint16_t* pIndices = (uint16_t*)malloc(iIndexSize * iVertexIndexCount); + + + float* pVertexSeek = pVertices; + float* pCoordSeek = pCoords; + float* pColorSeek = pColors; + uint16_t* pIndexSeek = pIndices; + int iSeek = 0; + + QuadLeap quadLeap; + SsVector4 cLT(colors[0 * 4 + 0], colors[0 * 4 + 1], colors[0 * 4 + 2], colors[0 * 4 + 3]); + SsVector4 cRT(colors[1 * 4 + 0], colors[1 * 4 + 1], colors[1 * 4 + 2], colors[1 * 4 + 3]); + SsVector4 cLB(colors[2 * 4 + 0], colors[2 * 4 + 1], colors[2 * 4 + 2], colors[2 * 4 + 3]); + SsVector4 cRB(colors[3 * 4 + 0], colors[3 * 4 + 1], colors[3 * 4 + 2], colors[3 * 4 + 3]); + SsVector4 cCC; + SsSizeF size = nines.getSize(); + float fX2 = size.width() * 0.5f; + float fY2 = size.height() * 0.5f; + + quadLeap.set(-fX2, fX2, fY2, -fY2); + + for(const SsVertex & e : listVertex) { + //foreach(const SsVertex & e, listVertex) { + const SsPoint2& position = e.getPosition(); + const SsPoint2& coord = e.getCoord(); + + quadLeap.updateRate(position); + + cCC = quadLeap.getLeapValue(cLT, cRT, cLB, cRB); + + *pVertexSeek++ = position.x; + *pVertexSeek++ = position.y; + *pVertexSeek++ = 0.0f; + + *pCoordSeek++ = coord.x; + *pCoordSeek++ = coord.y; + + *pColorSeek++ = cCC.x; + *pColorSeek++ = cCC.y; + *pColorSeek++ = cCC.z; + *pColorSeek++ = cCC.w; + + } + + for(const uint32_t& e: listVertexIndex) { + // foreach(const quint32 & e, listVertexIndex) { + *pIndexSeek++ = e; + } + + glVertexPointer(3, GL_FLOAT, 0, (GLvoid*)pVertices); + glTexCoordPointer(2, GL_FLOAT, 0, (GLvoid*)pCoords); + glColorPointer(4, GL_FLOAT, 0, (GLvoid*)pColors); + + iSeek = 0; + //foreach(const quint32 & e, listStride) { + for( auto & e : listStride) { + glDrawElements(GL_TRIANGLE_STRIP, e, GL_UNSIGNED_SHORT, (GLvoid*)&pIndices[iSeek]); + iSeek += e; + } + + free(pVertices); + free(pCoords); + free(pColors); + free(pIndices); + } + + return true; + } +} \ No newline at end of file diff --git a/Common/Drawer/ssopenglninesdrawer.h b/Common/Drawer/ssopenglninesdrawer.h new file mode 100644 index 00000000..5a5b71a2 --- /dev/null +++ b/Common/Drawer/ssopenglninesdrawer.h @@ -0,0 +1,15 @@ +#ifndef SSOPENGLNINESDRAWER_H +#define SSOPENGLNINESDRAWER_H + +#include "../Loader/nineslice/ssnines.h" +namespace SpriteStudio +{ + class SsOpenGLNinesDrawer + { + public: + SsOpenGLNinesDrawer(); + + bool execute(const SsNines& nines, const float* vertices, const float* colors); + }; +}; +#endif // SSOPENGLNINESDRAWER_H diff --git a/Common/Drawer/ssopenglshapedrawer.cpp b/Common/Drawer/ssopenglshapedrawer.cpp new file mode 100644 index 00000000..c9b9f045 --- /dev/null +++ b/Common/Drawer/ssopenglshapedrawer.cpp @@ -0,0 +1,210 @@ +#include "ssopenglshapedrawer.h" +#include "ssOpenGLSetting.h" + +#include "sstypes.h" +//#include "SsOpenGL.h" +namespace SpriteStudio +{ + class QuadLeap + { + public: + class Rate + { + public: + Rate() + { + set(0.0f, 0.0f, 0.0f, 0.0f); + } + + ~Rate() + { + } + + void set(float fLT, float fRT, float fLB, float fRB) + { + m_fLT = fLT; + m_fRT = fRT; + m_fLB = fLB; + m_fRB = fRB; + } + + float getLT() const + { + return m_fLT; + } + + float getRT() const + { + return m_fRT; + } + + float getLB() const + { + return m_fLB; + } + + float getRB() const + { + return m_fRB; + } + + private: + float m_fLT; + float m_fRT; + float m_fLB; + float m_fRB; + }; + + QuadLeap() + { + set(-0.5f, 0.5f, 0.5f, -0.5); + } + + ~QuadLeap() + { + } + + void set(float fL, float fR, float fT, float fB) + { + m_fL = fL; + m_fR = fR; + m_fT = fT; + m_fB = fB; + } + + void updateRate(const SsPoint2& point) + { + float fL = 0.0f; + float fR = 0.0f; + float fT = 0.0f; + float fB = 0.0f; + float fH = 0.0f; + float fV = 0.0f; + float fX = 0.0f; + float fY = 0.0f; + + if (m_fL < m_fR) { + fL = m_fL; + fR = m_fR; + } + else { + fL = m_fR; + fR = m_fL; + } + + if (m_fT < m_fB) { + fT = m_fT; + fB = m_fB; + } + else { + fT = m_fB; + fB = m_fT; + } + + fH = fR - fL; + fV = fB - fT; + +// fX = (point.x() - fL) / fH; +// fY = (point.y() - fT) / fV; + fX = (point.x - fL) / fH; + fY = (point.y - fT) / fV; + + if (m_fL < m_fR) { + fX = 1.0f - fX; + } + + if (m_fT < m_fB) { + fY = 1.0f - fY; + } + + m_Rate.set( + fX * fY, + (1.0f - fX) * fY, + fX * (1.0f - fY), + (1.0f - fX) * (1.0f - fY) + ); + } + + template + T getLeapValue(const T& vLT, const T& vRT, const T& vLB, const T& vRB) + { + return (vLT * m_Rate.getLT()) + (vRT * m_Rate.getRT()) + (vLB * m_Rate.getLB()) + (vRB * m_Rate.getRB()); + } + + private: + float m_fL; + float m_fR; + float m_fT; + float m_fB; + + Rate m_Rate; + }; + + + SsOpenGLShapeDrawer::SsOpenGLShapeDrawer() + { + SsVector4 v; + v * 1.0f; + + } + + bool SsOpenGLShapeDrawer::execute(const SsShape& shape, const float* vertices, const float* colors) + { + const SsPolygon& polygon = shape.getPolygon(); + int iCount = polygon.getVertexCount(); + + if (iCount >= 3) { + const std::list& listVertex = polygon.getVertices(); + + int iVertexSize = sizeof(float) * 3; + int iColorSize = sizeof(float) * 4; + float* pVertices = (float*)malloc(iVertexSize * iCount); + float* pColors = (float*)malloc(iColorSize * iCount); + float* pVertexSeek = pVertices; + float* pColorSeek = pColors; + + QuadLeap quadLeap; + SsVector4 cLT(colors[0 * 4 + 0], colors[0 * 4 + 1], colors[0 * 4 + 2], colors[0 * 4 + 3]); + SsVector4 cRT(colors[1 * 4 + 0], colors[1 * 4 + 1], colors[1 * 4 + 2], colors[1 * 4 + 3]); + SsVector4 cLB(colors[2 * 4 + 0], colors[2 * 4 + 1], colors[2 * 4 + 2], colors[2 * 4 + 3]); + SsVector4 cRB(colors[3 * 4 + 0], colors[3 * 4 + 1], colors[3 * 4 + 2], colors[3 * 4 + 3]); + SsVector4 cCC; + SsSizeF size = shape.getSize(); + float fX2 = size.width() * 0.5f; + float fY2 = size.height() * 0.5f; + + quadLeap.set(-fX2, fX2, fY2, -fY2); + + //foreach(const SsVertex & e, listVertex) { + for(const SsVertex & e : listVertex) { + //const SsPoint2F& position = e.getPosition(); + const SsPoint2& position = e.getPosition(); + + quadLeap.updateRate(position); + + cCC = quadLeap.getLeapValue(cLT, cRT, cLB, cRB); + + *pVertexSeek++ = position.x; + *pVertexSeek++ = position.y; + *pVertexSeek++ = 0.0f; + + *pColorSeek++ = cCC.x; + *pColorSeek++ = cCC.y; + *pColorSeek++ = cCC.z; + *pColorSeek++ = cCC.w; + } + + glDisable(GL_TEXTURE_2D); + + glColorPointer(4, GL_FLOAT, 0, (GLvoid*)pColors); + glVertexPointer(3, GL_FLOAT, 0, (GLvoid*)pVertices); + + glDrawArrays(GL_TRIANGLE_FAN, 0, iCount); + + free(pVertices); + free(pColors); + } + + return true; + } +} \ No newline at end of file diff --git a/Common/Drawer/ssopenglshapedrawer.h b/Common/Drawer/ssopenglshapedrawer.h new file mode 100644 index 00000000..8207f194 --- /dev/null +++ b/Common/Drawer/ssopenglshapedrawer.h @@ -0,0 +1,15 @@ +#ifndef SSOPENGLSHAPEDRAWER_H +#define SSOPENGLSHAPEDRAWER_H + +#include "../Loader/shape/ssshape.h" +namespace SpriteStudio +{ + class SsOpenGLShapeDrawer + { + public: + SsOpenGLShapeDrawer(); + + bool execute(const SsShape& shape, const float* vertices, const float* colors); + }; +} +#endif // SSOPENGLSHAPEDRAWER_H diff --git a/Common/Drawer/ssplayer_render_dx9.cpp b/Common/Drawer/ssplayer_render_dx9.cpp index ae33f756..70fde1d3 100644 --- a/Common/Drawer/ssplayer_render_dx9.cpp +++ b/Common/Drawer/ssplayer_render_dx9.cpp @@ -10,7 +10,7 @@ //#include "ssplayer_shader_gl.h" -namespace spritestudio6 +namespace SpriteStudio { enum{ @@ -75,4 +75,4 @@ void SsRenderDX9::renderPart( SsPartState* state ) } -} // namespace spritestudio6 +} // namespace SpriteStudio diff --git a/Common/Drawer/ssplayer_render_dx9.h b/Common/Drawer/ssplayer_render_dx9.h index c050e747..c46c8dc7 100644 --- a/Common/Drawer/ssplayer_render_dx9.h +++ b/Common/Drawer/ssplayer_render_dx9.h @@ -3,7 +3,7 @@ #include "ssplayer_render.h" -namespace spritestudio6 +namespace SpriteStudio { struct SsPartState; @@ -40,6 +40,6 @@ class SsRenderDX9 : public ISsRenderer }; -} // namespace spritestudio6 +} // namespace SpriteStudio #endif diff --git a/Common/Drawer/ssplayer_render_gl.cpp b/Common/Drawer/ssplayer_render_gl.cpp index 31171953..4426c932 100644 --- a/Common/Drawer/ssplayer_render_gl.cpp +++ b/Common/Drawer/ssplayer_render_gl.cpp @@ -19,9 +19,12 @@ #include "ssplayer_cellmap.h" #include "ssplayer_mesh.h" +#include "../Drawer/ssopenglninesdrawer.h" +#include "../Drawer/ssopenglshapedrawer.h" + #define SPRITESTUDIO6SDK_PROGRAMABLE_SHADER_ON (1) -namespace spritestudio6 +namespace SpriteStudio { @@ -811,14 +814,17 @@ void SsRenderGL::renderPart( SsPartState* state ) SsCell * cell = state->cellValue.cell; - if ( cell == 0 ) return ; + //if ( cell == 0 ) return ; ISSTexture* texture = state->cellValue.texture; - if ( texture == 0 ) return ; + //if ( texture == 0 ) return ; SsPoint2 texturePixelSize; - texturePixelSize.x = state->cellValue.texture->getWidth(); - texturePixelSize.y = state->cellValue.texture->getHeight(); + if (texture) + { + texturePixelSize.x = state->cellValue.texture->getWidth(); + texturePixelSize.y = state->cellValue.texture->getHeight(); + } execMask(state); @@ -839,7 +845,7 @@ void SsRenderGL::renderPart( SsPartState* state ) if (cell) { // テクスチャのサイズが2のべき乗かチェック - if ( texture->isPow2() ) + if (texture && texture->isPow2() ) { // 2のべき乗 texture_is_pow2 = true; @@ -881,7 +887,12 @@ void SsRenderGL::renderPart( SsPartState* state ) #endif SSTextureGL* tex_gl = (SSTextureGL*)texture; - glBindTexture(gl_target, tex_gl->tex); + if (tex_gl) { + glBindTexture(gl_target, tex_gl->tex); + } + else { + glBindTexture(gl_target, 0); + } // フィルタ GLint filterMode; @@ -1165,10 +1176,11 @@ void SsRenderGL::renderPart( SsPartState* state ) glLoadMatrixf(state->matrixLocal); //Ver6 ローカルスケール対応 GLint VertexLocation = -1; - if (state->noCells) - { - //セルが無いので描画を行わない - }else{ + +// if (state->noCells) +// { +// //セルが無いので描画を行わない +// } #if SPRITESTUDIO6SDK_PROGRAMABLE_SHADER_ON @@ -1260,39 +1272,75 @@ void SsRenderGL::renderPart( SsPartState* state ) } #endif -#if SPRITESTUDIO6SDK_USE_TRIANGLE_FIN - if ( state->is_vertex_transform || state->is_parts_color) - { - static const GLubyte indices[] = { 4 , 3, 1, 0, 2 , 3}; - glDrawElements(GL_TRIANGLE_FAN, 6, GL_UNSIGNED_BYTE, indices); - }else{ - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + if (state && state->part && state->part->type == SsPartType::shape) + { + SsOpenGLShapeDrawer drawer; + SsPartValueShape* pValue = static_cast(state->part->m_pPartValueInfo.get()); + const SsShape* pShape = pValue->getShape(); + + float fTX = -state->pivotOffset.x * state->size.x; + float fTY = -state->pivotOffset.y * state->size.y; + + if (pShape) { + glPushMatrix(); + glTranslatef(fTX, fTY, 0); + drawer.execute(*pShape, state->vertices, state->colors); + glPopMatrix(); } + } + else if (state && state->part && state->part->type == SsPartType::nines) { + SsOpenGLNinesDrawer drawer; + SsPartValueNines* pValue = static_cast(state->part->m_pPartValueInfo.get()); + const SsNines* pNines = pValue->getNines(); + float fTX = -state->pivotOffset.x * state->size.x; + float fTY = -state->pivotOffset.y * state->size.y; + + if (pNines) { + glPushMatrix(); + glTranslatef(fTX, fTY, 0); + drawer.execute(*pNines, state->vertices, state->colors); + glPopMatrix(); + } + } + else { + if (!state->noCells) + { +#if SPRITESTUDIO6SDK_USE_TRIANGLE_FIN + if (state->is_vertex_transform || state->is_parts_color) + { + static const GLubyte indices[] = { 4 , 3, 1, 0, 2 , 3 }; + glDrawElements(GL_TRIANGLE_FAN, 6, GL_UNSIGNED_BYTE, indices); + } + else { + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + } #else - // 頂点配列を描画 - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + // 頂点配列を描画 + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); #endif + } } +// } #if SPRITESTUDIO6SDK_PROGRAMABLE_SHADER_ON -// if ( glpgObject ) + if ( state->is_shader ) { - if ( state->is_shader ) + if ( pPrgObject ) { -// if ( glpgObject ) - if ( pPrgObject ) - { - if ( VertexLocation >= 0 ) { - glDisableVertexAttribArray(VertexLocation);//無効化 - } - pPrgObject->Disable(); + if ( VertexLocation >= 0 ) { + glDisableVertexAttribArray(VertexLocation);//無効化 } + pPrgObject->Disable(); } } #endif + +RENDER_END: glPopMatrix(); if (texture_is_pow2 == false) @@ -1306,4 +1354,4 @@ void SsRenderGL::renderPart( SsPartState* state ) } -} // namespace spritestudio6 +} // namespace SpriteStudio diff --git a/Common/Drawer/ssplayer_render_gl.h b/Common/Drawer/ssplayer_render_gl.h index 5dee1165..a76a690d 100644 --- a/Common/Drawer/ssplayer_render_gl.h +++ b/Common/Drawer/ssplayer_render_gl.h @@ -3,7 +3,7 @@ #include "../Animator/ssplayer_render.h" -namespace spritestudio6 +namespace SpriteStudio { struct SsPartState; @@ -43,6 +43,6 @@ class SsRenderGL : public ISsRenderer }; -} // namespace spritestudio6 +} // namespace SpriteStudio #endif diff --git a/Common/Drawer/ssplayer_shader_gl.cpp b/Common/Drawer/ssplayer_shader_gl.cpp index c410bde9..c426a343 100644 --- a/Common/Drawer/ssplayer_shader_gl.cpp +++ b/Common/Drawer/ssplayer_shader_gl.cpp @@ -9,7 +9,7 @@ #include -namespace spritestudio6 +namespace SpriteStudio { @@ -380,4 +380,4 @@ SSOpenGLProgramObject::Use( void ) -} // namespace spritestudio6 +} // namespace SpriteStudio diff --git a/Common/Drawer/ssplayer_shader_gl.h b/Common/Drawer/ssplayer_shader_gl.h index bb6906c0..5bca81b9 100644 --- a/Common/Drawer/ssplayer_shader_gl.h +++ b/Common/Drawer/ssplayer_shader_gl.h @@ -9,7 +9,7 @@ #define SPRITESTUDIO6SDK_PUT_UNIFORM_WARNING (1) -namespace spritestudio6 +namespace SpriteStudio { class SSOpenGLShader { @@ -149,7 +149,7 @@ class SSOpenGLShaderMan int SsGL_CheckShaderReady( void ); extern SSOpenGLShaderMan* glshaderMan; -} // namespace spritestudio6 +} // namespace SpriteStudio #endif diff --git a/Common/Helper/CMakeLists.txt b/Common/Helper/CMakeLists.txt index 86a3ea07..1fbf6b22 100644 --- a/Common/Helper/CMakeLists.txt +++ b/Common/Helper/CMakeLists.txt @@ -13,23 +13,29 @@ CCACHE() PREPARE() set(ssHelper_SRCS - IsshTexture.cpp +# IsshTexture.cpp + SsTextureFactory.cpp sshTextureBMP.cpp stb_image.c sshScene.cpp sshTask.cpp XPFileOpenDlg.cpp DebugPrint.cpp + SsRawImage.cpp + UnicodeConv.cpp ) set(ssHelper_HEADERS - IsshTexture.h + # IsshTexture.h + SsTextureFactory.h sshTextureBMP.h stb_image.h sshObject.h sshTask.h XPFileOpenDlg.h DebugPrint.h + SsRawImage.h + UnicodeConv.h ) if(MSVC) diff --git a/Common/Helper/DebugPrint.cpp b/Common/Helper/DebugPrint.cpp index cdac8c05..26f8c10c 100644 --- a/Common/Helper/DebugPrint.cpp +++ b/Common/Helper/DebugPrint.cpp @@ -12,7 +12,7 @@ #endif -namespace spritestudio6 +namespace SpriteStudio { @@ -49,4 +49,4 @@ void THROW_ERROR_MESSAGE_MAIN( std::string str , char* fname , size_t line ) } -} // namespace spritestudio6 +} // namespace SpriteStudio diff --git a/Common/Helper/DebugPrint.h b/Common/Helper/DebugPrint.h index 3a287821..62ccee19 100644 --- a/Common/Helper/DebugPrint.h +++ b/Common/Helper/DebugPrint.h @@ -3,7 +3,7 @@ #include -namespace spritestudio6 +namespace SpriteStudio { void DEBUG_PRINTF( const char* strFormat, ... ); @@ -18,12 +18,12 @@ struct ThrowErrorMessage{ // MEMO: 外部名前空間からアクセスされた時の防備で、念のため完全修飾してあります。 #define SPRITESTUDIO6SDK_THROW_ERROR_MESSAGE(str) \ {\ -spritestudio6::THROW_ERROR_MESSAGE_MAIN( str , __FILE__ , __LINE__ );\ +SpriteStudio::THROW_ERROR_MESSAGE_MAIN( str , __FILE__ , __LINE__ );\ }\ void THROW_ERROR_MESSAGE_MAIN( std::string str , char* fname , size_t line ); -} // namespace spritestudio6 +} // namespace SpriteStudio #endif \ No newline at end of file diff --git a/Common/Helper/DirectX/SSTextureDX9.cpp b/Common/Helper/DirectX/SSTextureDX9.cpp index 676b0874..856fb1d1 100644 --- a/Common/Helper/DirectX/SSTextureDX9.cpp +++ b/Common/Helper/DirectX/SSTextureDX9.cpp @@ -6,7 +6,7 @@ #include "ssHelper.h" #include "SSTextureDX9.h" -namespace spritestudio6 +namespace SpriteStudio { #if 0 @@ -67,4 +67,4 @@ bool SSTextureDX9::Load( const char* filename ) return true; } -} // namespace spritestudio6 +} // namespace SpriteStudio diff --git a/Common/Helper/DirectX/SSTextureDX9.h b/Common/Helper/DirectX/SSTextureDX9.h index fe7fc945..db0d9d66 100644 --- a/Common/Helper/DirectX/SSTextureDX9.h +++ b/Common/Helper/DirectX/SSTextureDX9.h @@ -4,7 +4,7 @@ #include "IsshTexture.h" -namespace spritestudio6 +namespace SpriteStudio { //テクスチャクラス ( DirectX9 ) @@ -26,7 +26,7 @@ class SSTextureDX9 : public ISSTexture }; -} // namespace spritestudio6 +} // namespace SpriteStudio #endif diff --git a/Common/Helper/OpenGL/SSTextureGL.cpp b/Common/Helper/OpenGL/SSTextureGL.cpp index e09007a6..27fabc0d 100644 --- a/Common/Helper/OpenGL/SSTextureGL.cpp +++ b/Common/Helper/OpenGL/SSTextureGL.cpp @@ -16,9 +16,9 @@ */ #include "SSTextureGL.h" +#include "../Helper/DebugPrint.h" - -namespace spritestudio6 +namespace SpriteStudio { /* ===================================================================================== @@ -38,58 +38,76 @@ bool SSTextureGL::Load( const char* fname ) SSTextureLoader::DataHandle image = SSTextureLoader::LoadImageFromFile( fname, &tex_width , &tex_height , &bpp ); if ( image == SSTextureLoader::InvalidDataHandle ) return false; + loadFromMemory(image, tex_width, tex_height, bpp); + + SSTextureLoader::DecodeEndImageFile( image ); + + return true; +} + +bool SSTextureGL::loadFromMemory(uint8_t* image, int width, int height, int bpp) +{ + #if USE_GLEW int target = GL_TEXTURE_RECTANGLE_ARB; #else int target = GL_TEXTURE_RECTANGLE; #endif - if ( SSTextureLoader::CheckSizePow2( tex_width, tex_height ) ) + if (SSTextureLoader::CheckSizePow2(tex_width, tex_height)) { target = GL_TEXTURE_2D; } glGenTextures(1, &tex); - if ( tex == 0 ) return false; - glBindTexture( target, tex ); - - glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL ); - glTexParameteri( target, GL_TEXTURE_WRAP_S, GL_REPEAT ); - glTexParameteri( target, GL_TEXTURE_WRAP_T, GL_REPEAT ); - glTexParameterf( target, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); - glTexParameterf( target, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); - if ( bpp == 4 ) + if (tex == 0) return false; + glBindTexture(target, tex); + + tex_width = width; + tex_height = height; + + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); + glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + if (bpp == 4) { -/* - //Ver6 ではストレートアルファで処理を行うのでコメントにする - stbi_uc *ip = image; - for ( int i = 0 ; i < width * height ; i++ ) - { - stbi_uc* r = ip; ip ++; - stbi_uc* g = ip; ip ++; - stbi_uc* b = ip; ip ++; - stbi_uc* a = ip; ip ++; -// if ( *a == 0 ) - { - //*r = *g = *b = 0xff; - int _a = *a; - int _r = *r; - int _g = *g; - int _b = *b; - *r = ( _r * _a) >> 8 ; - *g = ( _g * _a) >> 8 ; - *b = ( _b * _a) >> 8 ; - } - } -*/ - glTexImage2D( target, 0, GL_RGBA, tex_width, tex_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)image ); - }else if ( bpp == 3 ) + /* + //Ver6 ではストレートアルファで処理を行うのでコメントにする + stbi_uc *ip = image; + for ( int i = 0 ; i < width * height ; i++ ) + { + stbi_uc* r = ip; ip ++; + stbi_uc* g = ip; ip ++; + stbi_uc* b = ip; ip ++; + stbi_uc* a = ip; ip ++; + // if ( *a == 0 ) + { + //*r = *g = *b = 0xff; + int _a = *a; + int _r = *r; + int _g = *g; + int _b = *b; + *r = ( _r * _a) >> 8 ; + *g = ( _g * _a) >> 8 ; + *b = ( _b * _a) >> 8 ; + } + } + */ + glTexImage2D(target, 0, GL_RGBA, tex_width, tex_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)image); + + //for (int i = 0; i < tex_width * tex_height ; i++) + //{ + // DEBUG_PRINTF( "%d \n" , image[i] ); + //} + } + else if (bpp == 3) { - glTexImage2D( target, 0, GL_RGBA, tex_width, tex_height, 0, GL_RGB, GL_UNSIGNED_BYTE, (const void*)image ); + glTexImage2D(target, 0, GL_RGBA, tex_width, tex_height, 0, GL_RGB, GL_UNSIGNED_BYTE, (const void*)image); } - SSTextureLoader::DecodeEndImageFile( image ); + return true; } - -} // namespace spritestudio6 +} // namespace SpriteStudio diff --git a/Common/Helper/OpenGL/SSTextureGL.h b/Common/Helper/OpenGL/SSTextureGL.h index 6c01f7fd..e2406de2 100644 --- a/Common/Helper/OpenGL/SSTextureGL.h +++ b/Common/Helper/OpenGL/SSTextureGL.h @@ -1,9 +1,10 @@ #ifndef __TKTEXTURE__ #define __TKTEXTURE__ -#include "../IsshTexture.h" +//#include "../IsshTexture.h" +#include "../SsTextureFactory.h" -namespace spritestudio6 +namespace SpriteStudio { class SSTextureGL : public ISSTexture @@ -22,10 +23,11 @@ class SSTextureGL : public ISSTexture virtual int getHeight() { return tex_height; } virtual ISSTexture* create(){ return new SSTextureGL(); } + virtual bool loadFromMemory(uint8_t* ptr, int width, int height ,int bpp); }; -} // namespace spritestudio6 +} // namespace SpriteStudio #endif diff --git a/Common/Helper/SsRawImage.cpp b/Common/Helper/SsRawImage.cpp new file mode 100644 index 00000000..94a61722 --- /dev/null +++ b/Common/Helper/SsRawImage.cpp @@ -0,0 +1,162 @@ +#include "../Loader/sstypes.h" +#include "SsTextureFactory.h" + +#include "SsRawImage.h" +#include "../Helper/DebugPrint.h" + +#include "stb_image.h" + +#include "../Libs/avir/avir.h" + +namespace SpriteStudio +{ + + + + +SsRawImage::~SsRawImage() +{ + if (is_autorelease) + { + delete rawimage; + rawimage = 0; + } +} + + +void SsRawImage::create(int width, int height , SsColor color) +{ + if (rawimage) + { + delete rawimage; + } + + this->width = width; + this->height = height; + this->bpp = 4; + + int arraysize = width * height * 4; +// rawimage.reset( new uint8_t[arraysize] ); + rawimage = new uint8_t[arraysize]; + + uint8_t* ptr = rawimage; + + + fill(color); +} + + +void SsRawImage::fill(SsColor color) +{ + uint8_t* ptr = rawimage; + for (int i = 0; i < width * height * this->bpp ; i += 4) + { + ptr[i + 0] = color.r; + ptr[i + 1] = color.g; + ptr[i + 2] = color.b; + ptr[i + 3] = color.a; + } +} + +static uint8_t* getImagePtr(uint8_t* ptr, int bpp , int x, int y , int width) +{ + //uint8_t* ptr = img->getRaw(); + //int bpp = img->getBpp(); + + uint8_t* ret = ptr + width * bpp* y + (x * bpp); + + return ret; +} + +bool SsRawImage::loadFromMemory(uint8_t* ptr, int width, int height, int bpp) +{ + create(width, height); + + for (int oy = 0; oy < height; oy++) + { + for (int ox = 0; ox < width; ox++) + { + uint8_t* srcPtr = getImagePtr(ptr, 4 , ox, oy , width); + uint8_t* dstPtr = getImagePtr(this->rawimage, 4 , ox, oy , width); + + dstPtr[0] = srcPtr[0]; + dstPtr[1] = srcPtr[1]; + dstPtr[2] = srcPtr[2]; + dstPtr[3] = srcPtr[3]; + } + } + + return true; +} + + +bool SsRawImage::Bitblt(SsRawImage* src, SsRectI srcRect, SsRectI dstRect) +{ + + int InBufSize = srcRect.width() * srcRect.height() * 4; + int OutBufSize = dstRect.width()* dstRect.height() * 4; + + + uint8_t* InBuf = new uint8_t[InBufSize]; + uint8_t* OutBuf = new uint8_t[OutBufSize]; + + + //一旦バッファにコピー + for (int oy = 0; oy < srcRect.height() ; oy++) + { + for (int ox = 0; ox < srcRect.width() ; ox++) + { + uint8_t* srcPtr = getImagePtr(src->rawimage, 4, srcRect.x() + ox, srcRect.y() + oy, src->width); + uint8_t* dstPtr = getImagePtr(InBuf, 4, ox, oy, srcRect.width() ); + + dstPtr[0] = srcPtr[0]; + dstPtr[1] = srcPtr[1]; + dstPtr[2] = srcPtr[2]; + dstPtr[3] = srcPtr[3]; + } + } + + //Dstサイズにリサイズ + avir::CImageResizer<> ImageResizer(8); + ImageResizer.resizeImage( + InBuf, srcRect.width(), srcRect.height(), 0, + OutBuf, dstRect.width(), dstRect.height(), 4, 0); + + + //リサイズ後バッファからコピー + for (int oy = 0; oy < dstRect.height(); oy++) + { + for (int ox = 0; ox < dstRect.width(); ox++) + { + uint8_t* srcPtr = getImagePtr(OutBuf, 4 , ox, oy , dstRect.width() ); + uint8_t* dstPtr = getImagePtr(this->rawimage, 4, dstRect.x() + ox, dstRect.y() + oy , this->width); + + dstPtr[0] = srcPtr[0]; + dstPtr[1] = srcPtr[1]; + dstPtr[2] = srcPtr[2]; + dstPtr[3] = srcPtr[3]; + } + } + + delete InBuf; + delete OutBuf; + + return true; +} + +bool SsRawImage::Load(const char* filename) +{ + SSTextureLoader::DataHandle ptr = SSTextureLoader::LoadImageFromFile(filename, + &this->width, + &this->height, + &this->bpp + ); + if (ptr == 0) return false; + rawimage = ptr; + + return true; +} + + + +} // namespace SpriteStudio diff --git a/Common/Helper/SsRawImage.h b/Common/Helper/SsRawImage.h new file mode 100644 index 00000000..89df07c5 --- /dev/null +++ b/Common/Helper/SsRawImage.h @@ -0,0 +1,68 @@ +#ifndef __SSRAWIMAGE__ +#define __SSRAWIMAGE__ + +#include "../Loader/sstypes.h" +#include "SsTextureFactory.h" + + +namespace SpriteStudio +{ + //ビットマップイメージのロード、作成、操作を提供する + +#if 1 +class SsRawImage : public ISSTexture +{ +private: + +// std::unique_ptr rawimage; + uint8_t* rawimage; + int width; + int height; + int bpp; + + bool is_autorelease; + +public : + SsRawImage() : ISSTexture() , rawimage(nullptr) , width(0) ,height(0) , is_autorelease(true) + { + + } + + SsRawImage(int _width, int _height) : SsRawImage() + { + + create(_width, _height); + } + + virtual ~SsRawImage(); +// void create(int width, int height, int bitdepth) + + //RGBAで作成する +// void create(int width, int height, SsColor color = SsColor( 255,255,255,255 )); + void create(int width, int height, SsColor color = SsColor(0,0,0,0)); + void create_and_copy(); + + uint8_t* getRaw() { return rawimage; } + + virtual int getWidth() override { return width; } + virtual int getHeight() override { return height; } + virtual int getBpp() { return bpp; } + + virtual bool Load(const char* filename); + virtual ISSTexture* create() { return 0; } + + virtual bool loadFromMemory(uint8_t* ptr, int width, int height, int bpp); + + void fill(SsColor color); + + //ImageからImageへの転送(リサイズあり) + bool Bitblt(SsRawImage* src, SsRectI srcRect, SsRectI dstRect); + + +}; +#endif + +} // namespace SpriteStudio + +#endif //ifdef __ISSGraphTexture__ + diff --git a/Common/Helper/SsTextureFactory.cpp b/Common/Helper/SsTextureFactory.cpp new file mode 100644 index 00000000..971d246a --- /dev/null +++ b/Common/Helper/SsTextureFactory.cpp @@ -0,0 +1,231 @@ +#include "../Loader/sstypes.h" +#include "SsTextureFactory.h" +#include "SsRawImage.h" + +#include "../Helper/DebugPrint.h" + +#include "stb_image.h" + + +namespace SpriteStudio +{ + + +static SSTextureLoader::DataHandle defaultLoadImageFromFile( const char* fileName, int* width, int* height, int* bpp ) +{ + stbi_uc* image = stbi_load( fileName, width , height , bpp , 0 ); + if ( image == nullptr ) + { // エラー時処理 + return SSTextureLoader::InvalidDataHandle; + } + + return (SSTextureLoader::DataHandle)image; +} +static void defaultDecodeEndImageFile( SSTextureLoader::DataHandle handle ) +{ + if ( handle != SSTextureLoader::InvalidDataHandle) + { + stbi_image_free( (void*)handle ); + } +} +static const char* defaultMessageGetFailureLoadFromFile() +{ + return ( stbi_failure_reason() ); +} +static bool defaultCheckSizePow2(int width, int height) +{ + bool rv = true; + + if ( width > 0 ) rv &= SsUtTextureisPow2( width ); + if ( height > 0 ) rv &= SsUtTextureisPow2( height ); + + return rv; +} + +SSTextureLoader::DataHandle SSTextureLoader::InvalidDataHandle = nullptr; +SSTextureLoader::PrototypeLoadImageFromFile SSTextureLoader::FunctionLoadImageFromFile = defaultLoadImageFromFile; +SSTextureLoader::PrototypeDecodeEndImageFile SSTextureLoader::FunctionDecodeEndImageFile = defaultDecodeEndImageFile; +SSTextureLoader::PrototypeMessageGetFailureLoadFromFile SSTextureLoader::FunctionMessageGetFailureLoadFromFile = defaultMessageGetFailureLoadFromFile; +SSTextureLoader::PrototypeCheckSizePow2 SSTextureLoader::FunctionCheckSizePow2 = defaultCheckSizePow2; + +SSTextureLoader::DataHandle SSTextureLoader::LoadImageFromFile( const char* fileName, int* width, int* height, int* bpp ) +{ + if (FunctionLoadImageFromFile == nullptr) + { + FunctionLoadImageFromFile = defaultLoadImageFromFile; + } + return (FunctionLoadImageFromFile( fileName, width, height, bpp )); +} +void SSTextureLoader::DecodeEndImageFile( SSTextureLoader::DataHandle handle ) +{ + if (FunctionDecodeEndImageFile == nullptr) + { + FunctionDecodeEndImageFile = defaultDecodeEndImageFile; + } + FunctionDecodeEndImageFile( handle ); +} +const char* SSTextureLoader::MessageGetFailureLoadFromFile() +{ + if (FunctionMessageGetFailureLoadFromFile == nullptr) + { + FunctionMessageGetFailureLoadFromFile = defaultMessageGetFailureLoadFromFile; + } + return (FunctionMessageGetFailureLoadFromFile()); +} +bool SSTextureLoader::CheckSizePow2(int width, int height) +{ + if (FunctionCheckSizePow2 == nullptr) + { + FunctionCheckSizePow2 = defaultCheckSizePow2; + } + return (FunctionCheckSizePow2( width, height )); +} + +ISSTexture* SSTextureFactory::m_texture_base_class = 0; +SSTextureFactory* SSTextureFactory::m_myInst = 0; + +ISSTexture* SSTextureFactory::loadTexture(SsString filePath) +{ + if (m_myInst) + { + ISSTexture* _tex = 0; + bool cached = false; + if (m_myInst->textureCache.count(filePath) != 0) + { + if (m_myInst->textureCache[filePath] != 0)cached = true; + } + + if (!cached) + { + //新規 + DEBUG_PRINTF("New Load Texture : %s \n", filePath.c_str()); + _tex = m_myInst->create(); + _tex->filenamepath = filePath; + + if (_tex->Load(filePath.c_str()) == false) + { + delete _tex; + return 0; + } + + //SsRawImage* image = new SsRawImage(_tex->getWidth(), _tex->getHeight()); + //image->fill(SsColor(0xff0000ff)); + + //delete _tex; + //_tex = SSTextureFactory::create(image); + //_tex->loadFromMemory(image->getRaw(), image->getWidth() , image->getHeight() , 4 ); + + + m_myInst->textureCache[filePath] = _tex; + return _tex; + } + else { + _tex = m_myInst->textureCache[filePath]; + if (_tex) + { + DEBUG_PRINTF("Texture Cached : %s \n", filePath.c_str()); + _tex->addref(); + return _tex; + } + } + } + return 0; +} + + +ISSTexture* SSTextureFactory::create(SsRawImage* img,SsString Tag) +{ + ISSTexture* _tex = 0; + + _tex = m_myInst->create(); + _tex->filenamepath = Tag; + _tex->loadFromMemory(img->getRaw(),img->getWidth(),img->getHeight() , 4); + + return _tex; + +} + + +void SSTextureFactory::releaseTextureForced(SsString filePath) +{ + if (m_myInst == 0)return; + + if (SSTextureFactory::isExist(filePath)) + { + ISSTexture* tex = m_myInst->textureCache[filePath]; + m_myInst->textureCache[filePath] = 0; + delete tex; + } +} + + +void SSTextureFactory::releaseTextureForced(ISSTexture* tex) +{ + if (m_myInst == 0)return; + + if (SSTextureFactory::isExist(tex)) + { + m_myInst->textureCache[tex->getFilename()] = 0; + DEBUG_PRINTF("Release Texture refCount == 0 Deleted : %s \n", tex->getFilename()); + delete tex; + } +} +void SSTextureFactory::releaseTexture(ISSTexture* tex) +{ + if (m_myInst == 0)return; + + if (SSTextureFactory::isExist(tex)) + { + int ret = tex->release(); + if (ret == 0) + { + m_myInst->textureCache[tex->getFilename()] = 0; + DEBUG_PRINTF("Release Texture refCount == 0 Deleted : %s \n", tex->getFilename()); + delete tex; + } + else { + DEBUG_PRINTF("Release Texture sub refCount : %s \n", tex->getFilename()); + } + }else{ + DEBUG_PRINTF("The specified texture is not under management. \n"); + } +} + + +bool SSTextureFactory::isExist(SsString filePath) +{ + if (m_myInst == 0)return false; + + if (m_myInst->textureCache.count(filePath) != 0) return true; + return false; +} + +bool SSTextureFactory::isExist(ISSTexture* texture) +{ + if (m_myInst == 0)return false; + + for (auto i = m_myInst->textureCache.begin(); i != m_myInst->textureCache.end(); ++i) { + //std::cout << i->first << " " << i->second << "\n"; + if (i->second == texture) { + return true; + } + } + + return false; +} + +void SSTextureFactory::releaseAllTexture() +{ + if (m_myInst == 0)return; + + for (auto i = m_myInst->textureCache.begin(); i != m_myInst->textureCache.end(); ++i) { + delete i->second; + } + m_myInst->textureCache.clear(); +} + + + + + +} // namespace SpriteStudio diff --git a/Common/Helper/SsTextureFactory.h b/Common/Helper/SsTextureFactory.h new file mode 100644 index 00000000..dcfe5417 --- /dev/null +++ b/Common/Helper/SsTextureFactory.h @@ -0,0 +1,140 @@ +#ifndef __ISSGraphTexture__ +#define __ISSGraphTexture__ + +#include "../Loader/sstypes.h" +#include + +#include + +namespace SpriteStudio +{ + + +// nが2のべき乗かどうかチェックする +inline bool SsUtTextureisPow2(int n) +{ + for (int i = 0; i < 16; i++) + { + if (n == (1 << i)) return true; + } + return false; +} + +class SSTextureLoader +{ +public: + typedef uint8_t* DataHandle; + static DataHandle InvalidDataHandle; + + typedef DataHandle (*PrototypeLoadImageFromFile)( const char* fileName, int* width, int* height, int* bpp ); + typedef void (*PrototypeDecodeEndImageFile)( DataHandle handle ); + typedef const char* (*PrototypeMessageGetFailureLoadFromFile)(); + typedef bool (*PrototypeCheckSizePow2)( int width, int height ); + + //MEMO: 下記関数群に関数ポインタを定義することで、テクスチャの標準読込関数を変更することができます(ただし実行時には本関数ポインタ群を直接実行しないでください)。 + // ※関数を変更する際には、FunctionCheckSizePow2以外の関数は全てワンセットで変更する必要があります(機能実装に使用しているライブラリなどが異なるため)。 + // ※これらの関数ポインタをnullptrに設定すると、次回使用時に標準実装関数に強制的に書き戻されます。 + static PrototypeLoadImageFromFile FunctionLoadImageFromFile; // テクスチャファイルのメモリ確保・ロードと初期解析処理(通常ISSTexture::Load関数から呼び出されます) + static PrototypeDecodeEndImageFile FunctionDecodeEndImageFile; // LoadImageFromFileで解析したテクスチャファイルのデコード終了(通常ISSTexture::Load関数から呼び出されます) + static PrototypeMessageGetFailureLoadFromFile FunctionMessageGetFailureLoadFromFile; // LoadImageFromFileでエラーが起こった場合のエラーメッセージの取得(通常ISSTexture::Load関数から呼び出されます) ※エラー取得できない場合nullptrを返してください + static PrototypeCheckSizePow2 FunctionCheckSizePow2; // テクスチャのXY辺長が2のn乗かのチェック + + //実行用関数群 + static DataHandle LoadImageFromFile( const char* fileName, int* width=nullptr, int* height=nullptr, int* bpp=nullptr ); + static void DecodeEndImageFile( DataHandle handle ); + static const char* MessageGetFailureLoadFromFile(); + static bool CheckSizePow2( int width, int height ); +}; + +class SSTextureFactory; +class ISSTexture +{ +private: + friend SSTextureFactory; + + int refCount; + + int addref() { return ++refCount; } + int release(){ + return --refCount; } + + SsString filenamepath; + SSTextureLoader::DataHandle dataHandle; + +public: + ISSTexture() : refCount(0), dataHandle(SSTextureLoader::InvalidDataHandle), filenamepath() + {} + + virtual ~ISSTexture() + { + } + + virtual int getWidth() = 0; + virtual int getHeight() = 0; + virtual const char* getFilename(){ return filenamepath.c_str(); } + + virtual bool Load( const char* filename ) = 0; + virtual ISSTexture* create() = 0; + + virtual bool loadFromMemory(uint8_t* ptr, int width, int height, int bpp) { return false; } + + + bool isPow2() + { + return SsUtTextureisPow2( getWidth() ) && SsUtTextureisPow2( getHeight() ); + } +}; + +class SsRawImage; + + +class SSTextureFactory +{ +private: + static ISSTexture* m_texture_base_class; + static SSTextureFactory* m_myInst; + + std::map textureCache; + + +private: + static ISSTexture* create() { return m_texture_base_class->create(); } + +public: + SSTextureFactory(){} + SSTextureFactory(ISSTexture* texture_base_class) + { + m_myInst = this ; m_texture_base_class = texture_base_class; + } + + virtual ~SSTextureFactory() + { + if ( m_texture_base_class ) + delete m_texture_base_class; + m_myInst = 0; + } + + static bool isExist(){ return m_myInst != 0; } + + static ISSTexture* loadTexture(SsString filePath); + + static ISSTexture* create(SsRawImage* img, SsString Tag = "unkown"); + + static void releaseTexture(ISSTexture* tex); + + //参照ポインタを関係なしに強制的に削除する + static void releaseTextureForced(ISSTexture* tex); + static void releaseTextureForced(SsString filePath); + + static bool isExist(SsString filePath); + static bool isExist(ISSTexture* texture); + + static void releaseAllTexture(); + +}; + + +} // namespace SpriteStudio + +#endif //ifdef __ISSGraphTexture__ + diff --git a/Common/Helper/UnicodeConv.cpp b/Common/Helper/UnicodeConv.cpp new file mode 100644 index 00000000..9a90e177 --- /dev/null +++ b/Common/Helper/UnicodeConv.cpp @@ -0,0 +1,341 @@ +#include "UnicodeConv.h" + +//auto を書き直し +//uint8_tを定義 +//std::arrayを別なものへ + + +namespace { +int GetU8ByteCount(char ch) { + + if (0 <= uint8_t(ch) && uint8_t(ch) < 0x80) { + return 1; + } + if (0xC2 <= uint8_t(ch) && uint8_t(ch) < 0xE0) { + return 2; + } + if (0xE0 <= uint8_t(ch) && uint8_t(ch) < 0xF0) { + return 3; + } + if (0xF0 <= uint8_t(ch) && uint8_t(ch) < 0xF8) { + return 4; + } + return 0; +} + +bool IsU8LaterByte(char ch) { + return 0x80 <= uint8_t(ch) && uint8_t(ch) < 0xC0; +} + +bool IsU16HighSurrogate(char16_t ch) { return 0xD800 <= ch && ch < 0xDC00; } + +bool IsU16LowSurrogate(char16_t ch) { return 0xDC00 <= ch && ch < 0xE000; } +} // namespace + +bool ConvChU8ToU16(const wtarray& u8Ch, wtarray& u16Ch) { + char32_t u32Ch; + if (!ConvChU8ToU32(u8Ch, u32Ch)) { + return false; + } + if (!ConvChU32ToU16(u32Ch, u16Ch)) { + return false; + } + return true; +} + +bool ConvChU8ToU32(const wtarray& u8Ch, char32_t& u32Ch) { + int numBytes = GetU8ByteCount(u8Ch[0]); + if (numBytes == 0) { + return false; + } + switch (numBytes) { + case 1: + u32Ch = char32_t(uint8_t(u8Ch[0])); + break; + case 2: + if (!IsU8LaterByte(u8Ch[1])) { + return false; + } + if ((uint8_t(u8Ch[0]) & 0x1E) == 0) { + return false; + } + + u32Ch = char32_t(u8Ch[0] & 0x1F) << 6; + u32Ch |= char32_t(u8Ch[1] & 0x3F); + break; + case 3: + if (!IsU8LaterByte(u8Ch[1]) || !IsU8LaterByte(u8Ch[2])) { + return false; + } + if ((uint8_t(u8Ch[0]) & 0x0F) == 0 && + (uint8_t(u8Ch[1]) & 0x20) == 0) { + return false; + } + + u32Ch = char32_t(u8Ch[0] & 0x0F) << 12; + u32Ch |= char32_t(u8Ch[1] & 0x3F) << 6; + u32Ch |= char32_t(u8Ch[2] & 0x3F); + break; + case 4: + if (!IsU8LaterByte(u8Ch[1]) || !IsU8LaterByte(u8Ch[2]) || + !IsU8LaterByte(u8Ch[3])) { + return false; + } + if ((uint8_t(u8Ch[0]) & 0x07) == 0 && + (uint8_t(u8Ch[1]) & 0x30) == 0) { + return false; + } + + u32Ch = char32_t(u8Ch[0] & 0x07) << 18; + u32Ch |= char32_t(u8Ch[1] & 0x3F) << 12; + u32Ch |= char32_t(u8Ch[2] & 0x3F) << 6; + u32Ch |= char32_t(u8Ch[3] & 0x3F); + break; + default: + return false; + } + + return true; +} + +bool ConvChU16ToU8(const wtarray& u16Ch, wtarray& u8Ch) { + char32_t u32Ch; + if (!ConvChU16ToU32(u16Ch, u32Ch)) { + return false; + } + if (!ConvChU32ToU8(u32Ch, u8Ch)) { + return false; + } + return true; +} + +bool ConvChU16ToU32(const wtarray& u16Ch, char32_t& u32Ch) { + if (IsU16HighSurrogate(u16Ch[0])) { + if (IsU16LowSurrogate(u16Ch[1])) { + u32Ch = 0x10000 + (char32_t(u16Ch[0]) - 0xD800) * 0x400 + + (char32_t(u16Ch[1]) - 0xDC00); + } else if (u16Ch[1] == 0) { + u32Ch = u16Ch[0]; + } else { + return false; + } + } else if (IsU16LowSurrogate(u16Ch[0])) { + if (u16Ch[1] == 0) { + u32Ch = u16Ch[0]; + } else { + return false; + } + } else { + u32Ch = u16Ch[0]; + } + + return true; +} + +bool ConvChU32ToU8(const char32_t u32Ch, wtarray& u8Ch) { + if (u32Ch > 0x10FFFF) { + return false; + } + + if (u32Ch < 128) { + u8Ch[0] = char(u32Ch); + u8Ch[1] = 0; + u8Ch[2] = 0; + u8Ch[3] = 0; + } else if (u32Ch < 2048) { + u8Ch[0] = 0xC0 | char(u32Ch >> 6); + u8Ch[1] = 0x80 | (char(u32Ch) & 0x3F); + u8Ch[2] = 0; + u8Ch[3] = 0; + } else if (u32Ch < 65536) { + u8Ch[0] = 0xE0 | char(u32Ch >> 12); + u8Ch[1] = 0x80 | (char(u32Ch >> 6) & 0x3F); + u8Ch[2] = 0x80 | (char(u32Ch) & 0x3F); + u8Ch[3] = 0; + } else { + u8Ch[0] = 0xF0 | char(u32Ch >> 18); + u8Ch[1] = 0x80 | (char(u32Ch >> 12) & 0x3F); + u8Ch[2] = 0x80 | (char(u32Ch >> 6) & 0x3F); + u8Ch[3] = 0x80 | (char(u32Ch) & 0x3F); + } + + return true; +} + +bool ConvChU32ToU16(const char32_t u32Ch, wtarray& u16Ch) { + if (u32Ch > 0x10FFFF) { + return false; + } + + if (u32Ch < 0x10000) { + u16Ch[0] = char16_t(u32Ch); + u16Ch[1] = 0; + } else { + u16Ch[0] = char16_t((u32Ch - 0x10000) / 0x400 + 0xD800); + u16Ch[1] = char16_t((u32Ch - 0x10000) % 0x400 + 0xDC00); + } + + return true; +} + +bool ConvU8ToU16(const std::string& u8Str, std::u16string& u16Str) { + + size_t len = u8Str.size(); + + for (std::string::const_iterator u8It = u8Str.begin(); u8It != u8Str.end(); ++u8It) { + int numBytes = GetU8ByteCount((*u8It)); + + if (numBytes == 0) { + return false; + } + + wtarray u8Ch; + u8Ch[0] = (*u8It); + for (int i = 1; i < numBytes; i++) { + ++u8It; + if (u8It == u8Str.end()) { + return false; + } + u8Ch[i] = (*u8It); + } + + wtarray u16Ch; + if (!ConvChU8ToU16(u8Ch, u16Ch)) { + return false; + } + + u16Str.push_back(u16Ch[0]); + if (u16Ch[1] != 0) { + u16Str.push_back(u16Ch[1]); + } + } + return true; +} + +bool ConvU8ToU32(const std::string& u8Str, std::u32string& u32Str) { + + for (std::string::const_iterator u8It = u8Str.begin(); u8It != u8Str.end(); ++u8It) { + int numBytes = GetU8ByteCount((*u8It)); + if (numBytes == 0) { + return false; + } + + wtarray u8Ch; + u8Ch[0] = (*u8It); + for (int i = 1; i < numBytes; i++) { + ++u8It; + if (u8It == u8Str.end()) { + return false; + } + u8Ch[i] = (*u8It); + } + + char32_t u32Ch; + if (!ConvChU8ToU32(u8Ch, u32Ch)) { + return false; + } + + u32Str.push_back(u32Ch); + } + return true; +} + +bool ConvU16ToU8(const std::u16string& u16Str, std::string& u8Str) { + for (std::u16string::const_iterator u16It = u16Str.begin(); u16It != u16Str.end(); ++u16It) { + wtarray u16Ch; + if (IsU16HighSurrogate((*u16It))) { + u16Ch[0] = (*u16It); + ++u16It; + if (u16It == u16Str.end()) { + return false; + } + u16Ch[1] = (*u16It); + } else { + u16Ch[0] = (*u16It); + u16Ch[1] = 0; + } + + wtarray u8Ch; + if (!ConvChU16ToU8(u16Ch, u8Ch)) { + return false; + } + if (u8Ch[0] != 0) { + u8Str.push_back(u8Ch[0]); + } + if (u8Ch[1] != 0) { + u8Str.push_back(u8Ch[1]); + } + if (u8Ch[2] != 0) { + u8Str.push_back(u8Ch[2]); + } + if (u8Ch[3] != 0) { + u8Str.push_back(u8Ch[3]); + } + } + return true; +} + +bool ConvU16ToU32(const std::u16string& u16Str, std::u32string& u32Str) { + for (std::u16string::const_iterator u16It = u16Str.begin(); u16It != u16Str.end(); ++u16It) { + wtarray u16Ch; + if (IsU16HighSurrogate((*u16It))) { + u16Ch[0] = (*u16It); + ++u16It; + if (u16It == u16Str.end()) { + return false; + } + u16Ch[1] = (*u16It); + } else { + u16Ch[0] = (*u16It); + u16Ch[1] = 0; + } + + char32_t u32Ch; + if (!ConvChU16ToU32(u16Ch, u32Ch)) { + return false; + } + u32Str.push_back(u32Ch); + } + return true; +} + +bool ConvU32ToU8(const std::u32string& u32Str, std::string& u8Str) { + for (std::u32string::const_iterator u32It = u32Str.begin(); u32It != u32Str.end(); ++u32It) { + wtarray u8Ch; + if (!ConvChU32ToU8((*u32It), u8Ch)) { + return false; + } + + if (u8Ch[0] != 0) { + u8Str.push_back(u8Ch[0]); + } + if (u8Ch[1] != 0) { + u8Str.push_back(u8Ch[1]); + } + + if (u8Ch[2] != 0) { + u8Str.push_back(u8Ch[2]); + } + if (u8Ch[3] != 0) { + u8Str.push_back(u8Ch[3]); + } + } + return true; +} + +bool ConvU32ToU16(const std::u32string& u32Str, std::u16string& u16Str) { + for (std::u32string::const_iterator u32It = u32Str.begin(); u32It != u32Str.end(); ++u32It) { + wtarray u16Ch; + if (!ConvChU32ToU16((*u32It), u16Ch)) { + return false; + } + + if (u16Ch[0] != 0) { + u16Str.push_back(u16Ch[0]); + } + if (u16Ch[1] != 0) { + u16Str.push_back(u16Ch[1]); + } + } + return true; +} diff --git a/Common/Helper/UnicodeConv.h b/Common/Helper/UnicodeConv.h new file mode 100644 index 00000000..731e2c7c --- /dev/null +++ b/Common/Helper/UnicodeConv.h @@ -0,0 +1,81 @@ +#ifndef UNICODE_CONV_H_ +#define UNICODE_CONV_H_ + +#include +#include + +#ifndef uint8_t +typedef unsigned char uint8_t; +#endif + + + +template +class wtarray +{ + type _array[num]; + size_t _arraySize; + type _overrun; + +public: + + wtarray(wtarray &src) : _arraySize(num) + { + for (size_t i = 0; i < _arraySize; i++) + this->_array[i] = src._array[i]; + } + + wtarray() : _arraySize(num) {} + virtual ~wtarray() {} + + type operator[](size_t index) const + { + if (index >= _arraySize) + { + return _overrun; //添え字オーバーの場合 + } + return _array[index]; + } + + + type& operator[](size_t index) + { + if (index >= _arraySize) + { + return _overrun; //添え字オーバーの場合 + } + return _array[index]; + } + + size_t byteOf() { return sizeof(type)*_arraySize; } + size_t sizeOf() { return _arraySize; } + + +}; + + + + +bool ConvChU8ToU16(const wtarray& u8Ch, wtarray& u16Ch); +bool ConvChU8ToU32(const wtarray& u8Ch, char32_t& u32Ch); + +bool ConvChU16ToU8(const wtarray& u16Ch, wtarray& u8Ch); +bool ConvChU16ToU32(const wtarray& u16Ch, char32_t& u32Ch); + +bool ConvChU32ToU8(const char32_t u32Ch, wtarray& u8Ch); +bool ConvChU32ToU16(const char32_t u32Ch, wtarray& u16Ch); + +bool ConvU8ToU16(const std::string& u8Str, std::u16string& u16Str); +bool ConvU8ToU32(const std::string& u8Str, std::u32string& u32Str); + +bool ConvU16ToU8(const std::u16string& u16Str, std::string& u8Str); +bool ConvU16ToU32(const std::u16string& u16Str, std::u32string& u32Str); + +bool ConvU32ToU8(const std::u32string& u32Str, std::string& u8Str); +bool ConvU32ToU16(const std::u32string& u32Str, std::u16string& u16Str); + + + + + +#endif // UNICODE_CONV_H_ diff --git a/Common/Helper/XPFileOpenDlg.cpp b/Common/Helper/XPFileOpenDlg.cpp index 9b42e923..daed166f 100644 --- a/Common/Helper/XPFileOpenDlg.cpp +++ b/Common/Helper/XPFileOpenDlg.cpp @@ -25,7 +25,7 @@ #include "string" #endif -namespace spritestudio6 +namespace SpriteStudio { @@ -79,4 +79,4 @@ bool XPFileOpenDlg::Show() } -} // namespace spritestudio6 +} // namespace SpriteStudio diff --git a/Common/Helper/XPFileOpenDlg.h b/Common/Helper/XPFileOpenDlg.h index bfd2df65..7836d5a5 100644 --- a/Common/Helper/XPFileOpenDlg.h +++ b/Common/Helper/XPFileOpenDlg.h @@ -11,7 +11,7 @@ #ifndef __XP_FILEOPENDLG__ #define __XP_FILEOPENDLG__ -namespace spritestudio6 +namespace SpriteStudio { class XPFileOpenDlg { @@ -31,6 +31,6 @@ class XPFileOpenDlg { }; -} // namespace spritestudio6 +} // namespace SpriteStudio #endif diff --git a/Common/Helper/ssHelper.h b/Common/Helper/ssHelper.h index 4b5d77ee..561ab9fd 100644 --- a/Common/Helper/ssHelper.h +++ b/Common/Helper/ssHelper.h @@ -7,7 +7,7 @@ #include "sshObject.h" #include "sshTask.h" #include "sshScene.h" -#include "IsshTexture.h" +#include "SsTextureFactory.h" #include "XPFileOpenDlg.h" #include "DebugPrint.h" diff --git a/Common/Helper/sshObject.cpp b/Common/Helper/sshObject.cpp index 19aae2f6..daf575f4 100644 --- a/Common/Helper/sshObject.cpp +++ b/Common/Helper/sshObject.cpp @@ -1,9 +1,9 @@ #include "sshObject.h" -namespace spritestudio6 +namespace SpriteStudio { -} // namespace spritestudio6 +} // namespace SpriteStudio diff --git a/Common/Helper/sshObject.h b/Common/Helper/sshObject.h index 0e24da02..a244c25b 100644 --- a/Common/Helper/sshObject.h +++ b/Common/Helper/sshObject.h @@ -3,7 +3,7 @@ #include "sshTask.h" -namespace spritestudio6 +namespace SpriteStudio { @@ -14,6 +14,6 @@ class tkObject : public task_base{ }; -} // namespace spritestudio6 +} // namespace SpriteStudio #endif diff --git a/Common/Helper/sshScene.cpp b/Common/Helper/sshScene.cpp index 9cf5e653..54852325 100644 --- a/Common/Helper/sshScene.cpp +++ b/Common/Helper/sshScene.cpp @@ -1,7 +1,7 @@ #include "sshScene.h" -namespace spritestudio6 +namespace SpriteStudio { -} // namespace spritestudio6 +} // namespace SpriteStudio diff --git a/Common/Helper/sshScene.h b/Common/Helper/sshScene.h index 88b9961a..2029a1ef 100644 --- a/Common/Helper/sshScene.h +++ b/Common/Helper/sshScene.h @@ -4,7 +4,7 @@ #include "sshObject.h" -namespace spritestudio6 +namespace SpriteStudio { @@ -23,6 +23,6 @@ class tkScene : public tkObject -} // namespace spritestudio6 +} // namespace SpriteStudio #endif diff --git a/Common/Helper/sshTask.cpp b/Common/Helper/sshTask.cpp index 911b2106..e63de0a3 100644 --- a/Common/Helper/sshTask.cpp +++ b/Common/Helper/sshTask.cpp @@ -2,7 +2,7 @@ #include "sshTask.h" //#include "Debug.h" -namespace spritestudio6 +namespace SpriteStudio { @@ -132,4 +132,4 @@ void task_manager::debug_print_tasks() */ -} // namespace spritestudio6 +} // namespace SpriteStudio diff --git a/Common/Helper/sshTask.h b/Common/Helper/sshTask.h index c7a6ab7f..424740b2 100644 --- a/Common/Helper/sshTask.h +++ b/Common/Helper/sshTask.h @@ -15,7 +15,7 @@ #define SPRITESTUDIO6SDK_NOUSE_ARGUMENT(_name_) ( void )( &_name_ ); #endif -namespace spritestudio6 +namespace SpriteStudio { class treeitem_uid @@ -335,6 +335,6 @@ inline void task_manager_destroy() } -} // namespace spritestudio6 +} // namespace SpriteStudio #endif diff --git a/Common/Helper/sshTextureBMP.cpp b/Common/Helper/sshTextureBMP.cpp index 1dcd8f67..03630047 100644 --- a/Common/Helper/sshTextureBMP.cpp +++ b/Common/Helper/sshTextureBMP.cpp @@ -6,7 +6,7 @@ #include "ssHelper.h" #include "sshTextureBMP.h" -namespace spritestudio6 +namespace SpriteStudio { bool SSTextureBMP::Load( const char* fname ) @@ -34,4 +34,4 @@ bool SSTextureBMP::Load( const char* fname ) -} // namespace spritestudio6 +} // namespace SpriteStudio diff --git a/Common/Helper/sshTextureBMP.h b/Common/Helper/sshTextureBMP.h index b73646f5..b3e1ffab 100644 --- a/Common/Helper/sshTextureBMP.h +++ b/Common/Helper/sshTextureBMP.h @@ -1,9 +1,10 @@ #ifndef __TKTEXTURE__ #define __TKTEXTURE__ -#include "IsshTexture.h" +#include "SsTextureFactory.h" -namespace spritestudio6 + +namespace SpriteStudio { @@ -35,6 +36,6 @@ class SSTextureBMP : public ISSTexture -} // namespace spritestudio6 +} // namespace SpriteStudio #endif diff --git a/Common/Libs/avir/LICENSE b/Common/Libs/avir/LICENSE new file mode 100644 index 00000000..61309b52 --- /dev/null +++ b/Common/Libs/avir/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2015-2021 Aleksey Vaneev + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Common/Libs/avir/README.md b/Common/Libs/avir/README.md new file mode 100644 index 00000000..41a63ba3 --- /dev/null +++ b/Common/Libs/avir/README.md @@ -0,0 +1,490 @@ +# AVIR - Image Resizing Algorithm # + +## Introduction ## + +Me, Aleksey Vaneev, is happy to offer you an open source image resizing / +scaling library which has reached a production level of quality, and is +ready to be incorporated into any project. This library features routines +for both down- and upsizing of 8- and 16-bit, 1 to 4-channel images. Image +resizing routines were implemented in multi-platform C++ code, and have a +high level of optimality. Beside resizing, this library offers a sub-pixel +shift operation. Built-in sRGB gamma correction is available. + +The resizing algorithm at first produces 2X upsized image (relative to the +source image size, or relative to the destination image size if downsizing is +performed) and then performs interpolation using a bank of sinc function-based +fractional delay filters. At the last stage a correction filter is applied +which fixes smoothing introduced at previous steps. + +The resizing algorithm was designed to provide the best visual quality. The +author even believes this algorithm provides the "ultimate" level of +quality (for an orthogonal, non neural-network, resizing) which cannot be +increased further: no math exists to provide a better frequency response, +better anti-aliasing quality and at the same time having less ringing +artifacts: these are 3 elements that define any resizing algorithm's quality; +in AVIR practice these elements have a high correlation to each other, so they +can be represented by a single parameter (AVIR offers several parameter sets +with varying quality). Algorithm's time performance turned out to be very good +as well (for the "ultimate" image quality). + +An important element utilized by this algorithm is the so called Peaked Cosine +window function, which is applied over sinc function in all filters. Please +consult the documentation for more details. + +Note that since AVIR implements orthogonal resizing, it may exhibit diagonal +aliasing artifacts. These artifacts are usually suppressed by EWA or radial +filtering techniques. EWA-like technique is not implemented in AVIR, because +it requires considerably more computing resources and may produce a blurred +image. + +As a bonus, a much faster `LANCIR` image resizing algorithm is also offered as +a part of this library. But the main focus of this documentation is the +original AVIR image resizing algorithm. + +*AVIR is dedicated to women. Your digital photos can look good at any size!* + +P.S. Please credit the author of this library in your documentation in the +following way: "AVIR image resizing algorithm designed by Aleksey Vaneev". + +## Affine and Non-Linear Transformations ## + +AVIR does not offer affine and non-linear image transformations "out of the +box". Since upsizing is a relatively fast operation in AVIR (required time +scales linearly with the output image area), affine and non-linear +transformations can be implemented in steps: 4- to 8-times upsizing, +transformation via bilinear interpolation, downsizing (linear proportional +affine transformations can probably skip the downsizing step). This should not +compromise the transformation quality much as bilinear interpolation's +problems will mostly reside in spectral area without useful signal, with a +maximum of 0.7 dB high-frequency attenuation for 4-times upsizing, and 0.17 dB +attenuation for 8-times upsizing. This approach is probably as time efficient +as performing a high-quality transform over the input image directly (the only +serious drawback is the increased memory requirement). Note that affine +transformations that change image proportions should first apply proportion +change during upsizing. + +## Requirements ## + +C++ compiler and system with efficient "float" floating-point (24-bit +mantissa) type support. This library can also internally use the "double" and +SIMD floating-point types during resizing if needed. This library does not +have dependencies beside the standard C library. + +## Links ## + +* [Documentation](https://www.voxengo.com/public/avir/Documentation/) + +## Usage Information ## + +The image resizer is represented by the `avir::CImageResizer<>` class, which +is a single front-end class for the whole library. Basically, you do not need +to use nor understand any other classes beside this class. + +The code of the library resides in the "avir" C++ namespace, effectively +isolating it from all other code. The code is thread-safe. You need just +a single resizer object per running application, at any time, even when +resizing images concurrently. + +To resize images in your application, simply add 3 lines of code (note that +you may need to change `ImageResizer( 8 )` here, to specify your image's true +bit resolution, which may be 10 or even 16): + + #include "avir.h" + avir :: CImageResizer<> ImageResizer( 8 ); + ImageResizer.resizeImage( InBuf, 640, 480, 0, OutBuf, 1024, 768, 3, 0 ); + (multi-threaded operation requires additional coding, see the documentation) + +AVIR works with header-less "raw" image buffers. If you are not too familiar +with the low-level "packed interleaved" image storage format, the `InBuf` is +expected to be `w*h*c` elements in size, where `w` and `h` is the width and +the height of the image in pixels, respectively, and `c` is the number of +color channels in the image. In the example above, the size of the `InBuf` is +`640*480*3=921600` elements. If you are working with 8-bit images, the buffer +and the elements should have the `uint8_t*` type; if you are working with +16-bit images, they should have the `uint16_t*` type. Note that when +processing 16-bit images, the value of `16` should be used in resizer's +constructor. AVIR's algorithm does not discern between channel packing order +(`RGBA`, `ARGB`, `BGRA`, etc.), so if the `BGRA` ordered elements were passed +to it, the result will be also `BGRA`. + +If the graphics library you are using returns a `uint32_t*` pointer to a raw +4-channel packed pixel data, you will need to cast both the input and output +pointers to the `uint8_t*` type when supplying them to the resizing function, +and set the ElCount to 4. + +For low-ringing performance: + + avir :: CImageResizer<> ImageResizer( 8, 0, avir :: CImageResizerParamsLR() ); + +To use the built-in gamma correction, which is disabled by default, an object +of the `avir::CImageResizerVars` class with its variable `UseSRGBGamma` set to +`true` should be supplied to the `resizeImage()` function. Note that, when +enabled, the gamma correction is applied to all channels (e.g. alpha-channel) +in the current implementation. + + avir :: CImageResizerVars Vars; + Vars.UseSRGBGamma = true; + +Dithering (error-diffusion dither which is perceptually good) can be enabled +this way: + + typedef avir :: fpclass_def< float, float, + avir :: CImageResizerDithererErrdINL< float > > fpclass_dith; + avir :: CImageResizer< fpclass_dith > ImageResizer( 8 ); + +The library is able to process images of any bit depth: this includes 8-bit, +16-bit, float and double types. Larger integer and signed integer types are +not supported. Supported source and destination image sizes are only limited +by the available system memory. Note that the resizing function applies +clipping to integer output only; floating-point output will not be clipped to +[0; 1] range. + +The code of this library was commented in the [Doxygen](http://www.doxygen.org/) +style. To generate the documentation locally you may run the +`doxygen ./other/avirdoxy.txt` command from the library's directory. Note that +the code was suitably documented allowing you to make modifications, and to +gain full understanding of the algorithm. + +Preliminary tests show that this library (compiled with Intel C++ Compiler +18.2 with AVX2 instructions enabled, without explicit SIMD resizing code) can +resize 8-bit RGB 5184x3456 (17.9 Mpixel) 3-channel image down to 1920x1280 +(2.5 Mpixel) image in 245 milliseconds, utilizing a single thread, on Intel +Core i7-7700K processor-based system without overclocking. This scales down to +74 milliseconds if 8 threads are utilized. + +Multi-threaded operation is not provided by this library "out of the box". +The multi-threaded (horizontally-threaded) infrastructure is available, but +requires additional system-specific interfacing code for engagement. + +## SIMD Usage Information ## + +This library is capable of using SIMD floating-point types for internal +variables. This means that up to 4 color channels can be processed in +parallel. Since the default interleaved processing algorithm itself remains +non-SIMD, the use of SIMD internal types is not practical for 1- and 2-channel +image resizing (due to overhead). SIMD internal type can be used this way: + + #include "avir_float4_sse.h" + avir :: CImageResizer< avir :: fpclass_float4 > ImageResizer( 8 ); + +For 1-channel and 2-channel image resizing when AVX instructions are allowed +it may be reasonable to utilize de-interleaved SIMD processing algorithm. +While it gives no performance benefit if the "float4" SSE processing type is +used, it offers some performance boost if the "float8" AVX processing type is +used (given dithering is not performed, or otherwise performance is reduced at +the dithering stage since recursive dithering cannot be parallelized). The +internal type remains non-SIMD "float". De-interleaved algorithm can be used +this way: + + #include "avir_float8_avx.h" + avir :: CImageResizer< avir :: fpclass_float8_dil > ImageResizer( 8 ); + +It's important to note that on the latest Intel processors (i7-7700K and +probably later) the use of the aforementioned SIMD-specific resizing code may +not be justifiable, or may be even counter-productive due to many factors: +memory bandwidth bottleneck, increased efficiency of processor's circuitry +utilization and out-of-order execution, automatic SIMD optimizations performed +by the compiler. This is at least true when compiling 64-bit code with Intel +C++ Compiler 18.2 with /QxSSE4.2, or especially with the /QxCORE-AVX2 option. +SSE-specific resizing code may still be a little bit more efficient for +4-channel image resizing. + +## Notes ## + +This library was tested for compatibility with [GNU C++](http://gcc.gnu.org/), +[Microsoft Visual C++](http://www.microsoft.com/visualstudio/eng/products/visual-studio-express-products), +[LLVM](https://llvm.org/), and [Intel C++](http://software.intel.com/en-us/c-compilers) +compilers, on 32- and 64-bit Windows, macOS, and CentOS Linux. The code was +also tested with Dr.Memory/Win32 for the absence of uninitialized or +unaddressable memory accesses. + +All code is fully "inline", without the need to compile any source files. The +memory footprint of the library itself is very modest, except that the size of +the temporary image buffers depends on the input and output image sizes, and +is proportionally large. + +The "heart" of resizing algorithm's quality resides in the parameters defined +via the `avir::CImageResizerParams` structure. While the default set of +parameters that offers a good quality was already provided, there is +(probably) still a place for improvement exists, and the default parameters +may change in a future update. If you need to recall an exact set of +parameters, simply save them locally for a later use. + +When the algorithm is run with no resizing applied (k=1), the result of +resizing will not be an exact, but a very close copy of the source image. The +reason for such inexactness is that the image is always low-pass filtered at +first to reduce aliasing during subsequent resizing, and at last filtered by a +correction filter. Such approach allows algorithm to maintain a stable level +of quality regardless of the resizing "k" factor used. + +This library includes a binary command line tool "imageresize" for some +desktop platforms. This tool was designed to be used as a demonstration of +library's performance, and as a reference, it is multi-threaded (the `-t` +switch can be used to control the number of threads utilized). This tool uses +plain "float" processing (no explicit SIMD) and relies on automatic compiler +optimizations. This tool uses the following libraries: + +* turbojpeg Copyright (c) 2009-2013 D. R. Commander +* libpng Copyright (c) 1998-2013 Glenn Randers-Pehrson +* zlib Copyright (c) 1995-2013 Jean-loup Gailly and Mark Adler + +Note that you can enable gamma-correction with the `-g` switch. However, +sometimes gamma-correction produces "greenish/reddish/bluish haze" since +low-amplitude oscillations produced by resizing at object boundaries are +amplified by gamma correction. This can also have an effect of reduced +contrast. + +## Interpolation Discussion ## + +The use of certain low-pass filters and 2X upsampling in this library is +hardly debatable, because they are needed to attain a certain anti-aliasing +effect and keep ringing artifacts low. But the use of sinc function-based +interpolation filter that is 18 taps-long (may be higher, up to 36 taps in +practice) can be questioned, because such interpolation filter requires 18 +multiply-add operations. Comparatively, an optimal Hermite or cubic +interpolation spline requires 8 multiply and 11 add operations. + +One of the reasons 18-tap filter is preferred, is because due to memory +bandwidth limitations using a lower-order filter does not provide any +significant performance increase (e.g. 14-tap filter is less than 5% more +efficient overall). At the same time, in comparison to cubic spline, 18-tap +filter embeds a low-pass filter that rejects signal above 0.5\*pi (provides +additional anti-aliasing filtering), and this filter has a consistent shape at +all fractional offsets. Splines have a varying low-pass filter shape at +different fractional offsets (e.g. no low-pass filtering at 0.0 offset, +and maximal low-pass filtering at 0.5 offset). 18-tap filter also offers a +superior stop-band attenuation which almost guarantees absence of artifacts if +the image is considerably sharpened afterwards. + +## Why 2X upsizing in AVIR? ## + +Classic approaches to image resizing do not perform an additional 2X upsizing. +So, why such upsizing is needed at all in AVIR? Indeed, image resizing can be +implemented using a single interpolation filter which is applied to the source +image directly. However, such approach has limitations: + +First of all, speaking about non-2X-upsized resizing, during upsizing the +interpolation filter has to be tuned to a frequency close to pi (Nyquist) in +order to reduce high-frequency smoothing: this reduces the space left for +filter optimization. Beside that, during downsizing, a filter that performs +well and predictable when tuned to frequencies close to the Nyquist frequency, +may become distorted in its spectral shape when it is tuned to lower +frequencies. That is why it is usually a good idea to have filter's stop-band +begin below Nyquist so that the transition band's shape remains stable at any +lower-frequency setting. At the same time, this requirement complicates a +further corrective filtering, because correction filter may become too steep +at the point where the stop-band begins. + +Secondly, speaking about non-2X-upsized resizing, filter has to be very short +(with a base length of 5-7 taps, further multiplied by the resizing factor) or +otherwise the ringing artifacts will be very strong: it is a general rule that +the steeper the filter is around signal frequencies being removed the higher +the ringing artifacts are. That is why it is preferred to move steep +transitions into the spectral area with a quieter signal. A short filter also +means it cannot provide a strong "beyond-Nyquist" stop-band attenuation, so an +interpolated image will look a bit edgy or not very clean due to stop-band +artifacts. + +To sum up, only additional controlled 2X upsizing provides enough spectral +space to design interpolation filter without visible ringing artifacts yet +providing a strong stop-band attenuation and stable spectral characteristics +(good at any resizing "k" factor). Moreover, 2X upsizing becomes very +important in maintaining a good resizing quality when downsizing and upsizing +by small "k" factors, in the range 0.5 to 2: resizing approaches that do not +perform 2X upsizing usually cannot design a good interpolation filter for such +factors just because there is not enough spectral space available. + +## Why Peaked Cosine in AVIR? ## + +First of all, AVIR is a general solution to image resizing problem. That is +why it should not be directly compared to "spline interpolation" or "Lanczos +resampling", because the latter two are only means to design interpolation +filters, and they can be implemented in a variety of ways, even in sub-optimal +ways. Secondly, with only a minimal effort AVIR can be changed to use any +existing interpolation formula and any window function, but this is just not +needed. + +An effort was made to compare Peaked Cosine to Lanczos window function, and +here is the author's opinion. Peaked Cosine has two degrees of freedom whereas +Lanczos has one degree of freedom. While both functions can be used with +acceptable results, Peaked Cosine window function used in automatic parameter +optimization really pushes the limits of frequency response linearity, +anti-aliasing strength (stop-band attenuation) and low-ringing performance +which Lanczos cannot usually achieve. This is true at least when using a +general-purpose downhill simplex optimization method. Lanczos window has good +(but not better) characteristics in several special cases (certain "k" +factors) which makes it of limited use in a general solution such as AVIR. + +Among other window functions (Kaiser, Gaussian, Cauchy, Poisson, generalized +cosine windows) there are no better candidates as well. It looks like Peaked +Cosine function's scalability (it retains stable, almost continously-variable +spectral characteristics at any window parameter values), and its ability to +create "desirable" pass-band ripple in the frequency response near the cutoff +point contribute to its better overall quality. Somehow Peaked Cosine window +function optimization manages to converge to reasonable states in most cases +(that is why AVIR library comes with a set of equally robust, but distinctive +parameter sets) whereas all other window functions tend to produce +unpredictable optimization results. + +The only disadvantage of Peaked Cosine window function is that usable filters +windowed by this function tend to be longer than "usual" (with Kaiser window +being the "golden standard" for filter length per decibel of stop-band +attenuation). This is a price that should be paid for stable spectral +characteristics. + +This waterfall graph depicts the windowing function, at varying Alpha values. + + + +## LANCIR ## + +As a part of AVIR library, the `CLancIR` class is also offered which is an +optimal implementation of [Lanczos](https://en.wikipedia.org/wiki/Lanczos_resampling) +image resizing filter. This class has a similar programmatic interface to +AVIR, but it is not thread-safe: each executing thread should have its own +`CLancIR` object. This class was designed for cases of batch processing of +same-sized frames like in video encoding, or for just-in-time resizing of +an application's assets. This Lanczos implementation is likely one of the +fastest available for CPUs; it features a radical AVX, SSE2, and NEON +optimizations. + +LANCIR offers up to three times faster image resizing in comparison to AVIR. +The quality difference is, however, debatable. Note that while LANCIR can +take 8- and 16-bit and float image buffers, its precision is limited to +8-bit resizing. + +LANCIR should be seen as a bonus and as an "industrial standard" reference +for comparison. LANCIR uses Lanczos filter "a" parameter equal to 3 which is +similar to AVIR's default setting. + +## Comparison ## + +This graph displays a comparison of AVIR 2.9 (default parameters) and +Lanczos-3 image resizing algorithm in the area of frequency response. +The methodology can be seen in the `other/frtest.cpp` file. This graph +displays an average frequency response over a set of resizing factors. +It is similar but not equal to Fourier analysis as any errors and aliasing +artifacts are integrated into the response. As you can see, AVIR offers a +visibly better frequency response linearity. The horizontal scale displays a +normalized frequency scale, where 0 is DC frequency and 1 is Nyquist +frequency. In common terms, 1 corresponds to 1-pixel image features, 0.5 +corresponds to 2-pixel features while 0.25 corresponds to 4-pixel features, +etc. The vertical scale is in decibel. + +![FR plot](https://github.com/avaneev/avir/blob/master/other/_fr_up.png) + +The following graph displays a comparison of an average dynamic range over a +set of resizing factors. The dynamic range is estimated by performing +two-way resizing, followed by deviation/error estimation relative to the +original image. As you can see here, aliasing artifacts visibly reduce dynamic +range above 0.5\*Nyquist. An interesting aspect of this measurement method is +that it reflects modes of visual ringing very well: they correspond to the +points on frequency response where differential approaches zero. + +![DR plot](https://github.com/avaneev/avir/blob/master/other/_dr_up.png) + +Note that on downsizing the response graphs look similar to these. + +## Users ## + +This library is used by: + + * [Contaware.com](http://www.contaware.com/) + * [Pretext contact maps](https://github.com/wtsi-hpag/PretextSnapshot) + * [LVC Audio](https://lvcaudio.com) + * [Trainz](https://www.trainzportal.com/files/TRS19/credits.html) + * [MLV App](https://mlv.app/) + +[This video](https://www.youtube.com/watch?v=oNF-c6YX7-8) was "unsqueezed" +with AVIR by a factor of 3 from ML RAW video, and at a final stage downsampled +to 4K resolution. + +Please drop me a note at aleksey.vaneev@gmail.com and I will include a link to +your software product to the list of users. This list is important at +maintaining confidence in this library among the interested parties. + +## Change Log ## + +Version 3.0: + +* Improved speed by 10-25% on upsizing by utilizing a special resizing +function together with filter-less 2X upsizing. Does not apply to the +de-interleaved (AVX) resizing. +* Minor LANCIR optimization. + +Version 2.9: + +* Removed a rarely-used half-band resizing step completely since it offers no +practical performance nor quality benefits. +* Optimized filter generation function (removed divisions by a constant) as +filters are always post-normalized anyway. This may reduce overhead when +creating thumbnail-sized images. + +Version 2.8: + +* Fixed regression with the copy-constructor of CImageResizeVars class +(previously it caused uninitialized accesses). +* Removed filter length optimization as it did not reduce overhead measurably. +* Optimized "peaked cosine" window function generator (removed division). +* Added "unbiasing" to resizer - an unconventional approach which reduces peak +error significantly, at the expense of 5% increased overhead. +* Reoptimized filter parameters, now yielding an unprecedented quality. + +Version 2.7: + +* Added normalization of individual fractional delay filters. This reduced +peak error by 3 dB, which is substantial for image resizing. +* Reoptimized all filter parameters resulting in better frequency response +linearity. +* Added AVIR_NOCTOR macro to avoid copy-constructing and copying objects of +some classes via a default copy function. +* Added copy-constructor and assignment operator to the CImageResizerVars +class, to avoid uninitialized memory copying. +* Corrected automatic image offseting and "k" factor on image upsizing. + +Version 2.6: + +* A minor fix to sRGB gamma approximation functions. +* LANCIR: fixed a rare access violation crash. + +Version 2.5: + +* Surrounded `memcpy` calls with length checks to conform to `memcpy` +specification which does not allow NULL pointers even with zero copy length. + +Version 2.4: + +* Removed outdated `_mm_reset()` function calls from the SIMD code. +* Changed `float4 round()` to use SSE2 rounding features, avoiding use of +64-bit registers. + +Version 2.3: + +* Implemented CLancIR image resizing algorithm. +* Fixed a minor image offset on image upsizing. + +Version 2.2: + +* Released AVIR under a permissive MIT license agreement. + +Version 2.1: + +* Fixed error-diffusion dither problems introduced in the previous version. +* Added the `-1` switch to the `imageresize` to enable 1-bit output for +dither's quality evaluation (use together with the `-d` switch). +* Added the `--algparams=` switch to the `imageresize` to control resizing +quality (replaces the `--low-ring` switch). +* Added `avir :: CImageResizerParamsULR` parameter set for lowest-ringing +performance possible (not considerably different to +`avir :: CImageResizerParamsLR`, but a bit lower ringing). + +Version 2.0: + +* Minor inner loop optimizations. +* Lifted the supported image size constraint by switching buffer addressing to +`size_t` from `int`, now image size is limited by the available system memory. +* Added several useful switches to the `imageresize` utility. +* Now `imageresize` does not apply gamma-correction by default. +* Fixed scaling of bit depth-reduction operation. +* Improved error-diffusion dither's signal-to-noise ratio. +* Compiled binaries with AVX2 instruction set (SSE4 for macOS). diff --git a/Common/Libs/avir/avir.h b/Common/Libs/avir/avir.h new file mode 100644 index 00000000..c5e82d10 --- /dev/null +++ b/Common/Libs/avir/avir.h @@ -0,0 +1,6644 @@ +//$ nobt +//$ nocpp + +/** + * @file avir.h + * + * @brief The "main" inclusion file with all required classes and functions. + * + * This is the "main" inclusion file for the "AVIR" image resizer. This + * inclusion file contains implementation of the AVIR image resizing algorithm + * in its entirety. Also includes several classes and functions that can be + * useful elsewhere. + * + * AVIR Copyright (c) 2015-2021 Aleksey Vaneev + * + * @mainpage + * + * @section intro_sec Introduction + * + * Description is available at https://github.com/avaneev/avir + * + * AVIR is devoted to women. Your digital photos can look good at any size! + * + * Please credit the author of this library in your documentation in the + * following way: "AVIR image resizing algorithm designed by Aleksey Vaneev". + * + * @section license License + * + * MIT License + * + * Copyright (c) 2015-2021 Aleksey Vaneev + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * @version 3.0 + */ + +#ifndef AVIR_CIMAGERESIZER_INCLUDED +#define AVIR_CIMAGERESIZER_INCLUDED + +#include +#include +#include +#include + +namespace avir { + +/** + * The macro defines AVIR version string. + */ + +#define AVIR_VERSION "3.0" + +/** + * The macro equals to "pi" constant, fills 53-bit floating point mantissa. + * Undefined at the end of file. + */ + +#define AVIR_PI 3.1415926535897932 + +/** + * The macro equals to "pi divided by 2" constant, fills 53-bit floating + * point mantissa. Undefined at the end of file. + */ + +#define AVIR_PId2 1.5707963267948966 + +/** + * A special macro that defines empty copy-constructor and copy operator with + * the "private:" prefix. This macro should be used in classes that cannot be + * copied in a standard C++ way. + */ + +#define AVIR_NOCTOR( ClassName ) \ + private: \ + ClassName( const ClassName& ) { } \ + ClassName& operator = ( const ClassName& ) { return( *this ); } + +/** + * Rounding function, based on the (int) typecast. Biased result. Not suitable + * for numbers >= 2^31. + * + * @param d Value to round. + * @return Rounded value. Some bias may be introduced. + */ + +template< class T > +inline T round( const T d ) +{ + return( d < (T) 0 ? -(T) (int) ( (T) 0.5 - d ) : + (T) (int) ( d + (T) 0.5 )); +} + +/** + * Template function "clamps" (clips) the specified value so that it is not + * lesser than "minv", and not greater than "maxv". + * + * @param Value Value to clamp. + * @param minv Minimal allowed value. + * @param maxv Maximal allowed value. + * @return The clamped value. + */ + +template< class T > +inline T clamp( const T& Value, const T minv, const T maxv ) +{ + if( Value < minv ) + { + return( minv ); + } + else + if( Value > maxv ) + { + return( maxv ); + } + else + { + return( Value ); + } +} + +/** + * Power 2.4 approximation function, designed for sRGB gamma correction. + * + * @param x Argument, in the range 0.09 to 1. + * @return Value raised into power 2.4, approximate. + */ + +template< class T > +inline T pow24_sRGB( const T x ) +{ + const double x2 = (double) x * x; + const double x3 = x2 * x; + const double x4 = x2 * x2; + + return( (T) ( 0.0985766365536824 + 0.839474952656502 * x2 + + 0.363287814061725 * x3 - 0.0125559718896615 / + ( 0.12758338921578 + 0.290283465468235 * x ) - + 0.231757513261358 * x - 0.0395365717969074 * x4 )); +} + +/** + * Power 1/2.4 approximation function, designed for sRGB gamma correction. + * + * @param x Argument, in the range 0.003 to 1. + * @return Value raised into power 1/2.4, approximate. + */ + +template< class T > +inline T pow24i_sRGB( const T x ) +{ + const double sx = sqrt( (double) x ); + const double ssx = sqrt( sx ); + const double sssx = sqrt( ssx ); + + return( (T) ( 0.000213364515060263 + 0.0149409239419218 * x + + 0.433973412731747 * sx + ssx * ( 0.659628181609715 * sssx - + 0.0380957908841466 - 0.0706476137208521 * sx ))); +} + +/** + * Function approximately linearizes the sRGB gamma value. + * + * @param s sRGB gamma value, in the range 0 to 1. + * @return Linearized sRGB gamma value, approximated. + */ + +template< class T > +inline T convertSRGB2Lin( const T s ) +{ + const T a = (T) 0.055; + + if( s <= (T) 0.04045 ) + { + return( s / (T) 12.92 ); + } + + return( pow24_sRGB(( s + a ) / ( (T) 1 + a ))); +} + +/** + * Function approximately de-linearizes the linear gamma value. + * + * @param s Linear gamma value, in the range 0 to 1. + * @return sRGB gamma value, approximated. + */ + +template< class T > +inline T convertLin2SRGB( const T s ) +{ + const T a = (T) 0.055; + + if( s <= (T) 0.0031308 ) + { + return( (T) 12.92 * s ); + } + + return(( (T) 1 + a ) * pow24i_sRGB( s ) - a ); +} + +/** + * Function converts (via typecast) specified array of type T1 values of + * length l into array of type T2 values. If T1 is the same as T2, copy + * operation is performed. When copying data at overlapping address spaces, + * "op" should be lower than "ip". + * + * @param ip Input buffer. + * @param[out] op Output buffer. + * @param l The number of elements to copy. + * @param ip Input buffer pointer increment. + * @param op Output buffer pointer increment. + */ + +template< class T1, class T2 > +inline void copyArray( const T1* ip, T2* op, int l, + const int ipinc = 1, const int opinc = 1 ) +{ + while( l > 0 ) + { + *op = (T2) *ip; + op += opinc; + ip += ipinc; + l--; + } +} + +/** + * Function adds values located in array "ip" to array "op". + * + * @param ip Input buffer. + * @param[out] op Output buffer. + * @param l The number of elements to add. + * @param ip Input buffer pointer increment. + * @param op Output buffer pointer increment. + */ + +template< class T1, class T2 > +inline void addArray( const T1* ip, T2* op, int l, + const int ipinc = 1, const int opinc = 1 ) +{ + while( l > 0 ) + { + *op += *ip; + op += opinc; + ip += ipinc; + l--; + } +} + +/** + * Function that replicates a set of adjacent elements several times in a row. + * This operation is usually used to replicate pixels at the start or end of + * image's scanline. + * + * @param ip Source array. + * @param ipl Source array length (usually 1..4, but can be any number). + * @param[out] op Destination buffer. + * @param l Number of times the source array should be replicated (the + * destination buffer should be able to hold ipl * l number of elements). + * @param opinc Destination buffer position increment after replicating the + * source array. This value should be equal to at least ipl. + */ + +template< class T1, class T2 > +inline void replicateArray( const T1* const ip, const int ipl, T2* op, int l, + const int opinc ) +{ + if( ipl == 1 ) + { + while( l > 0 ) + { + op[ 0 ] = (T2) ip[ 0 ]; + op += opinc; + l--; + } + } + else + if( ipl == 4 ) + { + while( l > 0 ) + { + op[ 0 ] = (T2) ip[ 0 ]; + op[ 1 ] = (T2) ip[ 1 ]; + op[ 2 ] = (T2) ip[ 2 ]; + op[ 3 ] = (T2) ip[ 3 ]; + op += opinc; + l--; + } + } + else + if( ipl == 3 ) + { + while( l > 0 ) + { + op[ 0 ] = (T2) ip[ 0 ]; + op[ 1 ] = (T2) ip[ 1 ]; + op[ 2 ] = (T2) ip[ 2 ]; + op += opinc; + l--; + } + } + else + if( ipl == 2 ) + { + while( l > 0 ) + { + op[ 0 ] = (T2) ip[ 0 ]; + op[ 1 ] = (T2) ip[ 1 ]; + op += opinc; + l--; + } + } + else + { + while( l > 0 ) + { + int i; + + for( i = 0; i < ipl; i++ ) + { + op[ i ] = (T2) ip[ i ]; + } + + op += opinc; + l--; + } + } +} + +/** + * Function calculates frequency response of the specified FIR filter at the + * specified circular frequency. Phase can be calculated as atan2( im, re ). + * Function uses computationally-efficient oscillators instead of "cos" and + * "sin" functions. + * + * @param flt FIR filter's coefficients. + * @param fltlen Number of coefficients (taps) in the filter. + * @param th Circular frequency [0; pi]. + * @param[out] re0 Resulting real part of the complex frequency response. + * @param[out] im0 Resulting imaginary part of the complex frequency response. + * @param fltlat Filter's latency in samples (taps). + */ + +template< class T > +inline void calcFIRFilterResponse( const T* flt, int fltlen, + const double th, double& re0, double& im0, const int fltlat = 0 ) +{ + const double sincr = 2.0 * cos( th ); + double cvalue1; + double svalue1; + + if( fltlat == 0 ) + { + cvalue1 = 1.0; + svalue1 = 0.0; + } + else + { + cvalue1 = cos( -fltlat * th ); + svalue1 = sin( -fltlat * th ); + } + + double cvalue2 = cos( -( fltlat + 1 ) * th ); + double svalue2 = sin( -( fltlat + 1 ) * th ); + + double re = 0.0; + double im = 0.0; + + while( fltlen > 0 ) + { + re += cvalue1 * flt[ 0 ]; + im += svalue1 * flt[ 0 ]; + flt++; + fltlen--; + + double tmp = cvalue1; + cvalue1 = sincr * cvalue1 - cvalue2; + cvalue2 = tmp; + + tmp = svalue1; + svalue1 = sincr * svalue1 - svalue2; + svalue2 = tmp; + } + + re0 = re; + im0 = im; +} + +/** + * Function normalizes FIR filter so that its frequency response at DC is + * equal to DCGain. + * + * @param[in,out] p Filter coefficients. + * @param l Filter length. + * @param DCGain Filter's gain at DC. + * @param pstep "p" array step. + */ + +template< class T > +inline void normalizeFIRFilter( T* const p, const int l, const double DCGain, + const int pstep = 1 ) +{ + double s = 0.0; + T* pp = p; + int i = l; + + while( i > 0 ) + { + s += *pp; + pp += pstep; + i--; + } + + s = DCGain / s; + pp = p; + i = l; + + while( i > 0 ) + { + *pp = (T) ( *pp * s ); + pp += pstep; + i--; + } +} + +/** + * @brief Memory buffer class for element array storage, with capacity + * tracking. + * + * Allows easier handling of memory blocks allocation and automatic + * deallocation for arrays (buffers) consisting of elements of specified + * class. Tracks buffer's capacity in "int" variable; unsuitable for + * allocation of very large memory blocks (with more than 2 billion elements). + * + * This class manages memory space only - it does not perform element class + * construction (initialization) operations. Buffer's required memory address + * alignment specification is supported. + * + * Uses standard library to allocate and deallocate memory. + * + * @tparam T Buffer element's type. + * @tparam capint Buffer capacity's type to use. Use size_t for large buffers. + */ + +template< class T, typename capint = int > +class CBuffer +{ +public: + CBuffer() + : Data( NULL ) + , DataAligned( NULL ) + , Capacity( 0 ) + , Alignment( 0 ) + { + } + + /** + * Constructor creates the buffer with the specified capacity. + * + * @param aCapacity Buffer's capacity. + * @param aAlignment Buffer's required memory address alignment. 0 - use + * stdlib's default alignment. + */ + + CBuffer( const capint aCapacity, const int aAlignment = 0 ) + { + allocinit( aCapacity, aAlignment ); + } + + CBuffer( const CBuffer& Source ) + { + allocinit( Source.Capacity, Source.Alignment ); + + if( Capacity > 0 ) + { + memcpy( DataAligned, Source.DataAligned, Capacity * sizeof( T )); + } + } + + ~CBuffer() + { + freeData(); + } + + CBuffer& operator = ( const CBuffer& Source ) + { + alloc( Source.Capacity, Source.Alignment ); + + if( Capacity > 0 ) + { + memcpy( DataAligned, Source.DataAligned, Capacity * sizeof( T )); + } + + return( *this ); + } + + /** + * Function allocates memory so that the specified number of elements + * can be stored in *this buffer object. + * + * @param aCapacity Storage for this number of elements to allocate. + * @param aAlignment Buffer's required memory address alignment, + * power-of-2 values only. 0 - use stdlib's default alignment. + */ + + void alloc( const capint aCapacity, const int aAlignment = 0 ) + { + freeData(); + allocinit( aCapacity, aAlignment ); + } + + /** + * Function deallocates any previously allocated buffer. + */ + + void free() + { + freeData(); + Data = NULL; + DataAligned = NULL; + Capacity = 0; + Alignment = 0; + } + + /** + * @return The capacity of the element buffer. + */ + + capint getCapacity() const + { + return( Capacity ); + } + + /** + * Function "forces" *this buffer to have an arbitary capacity. Calling + * this function invalidates all further operations except deleting *this + * object. This function should not be usually used at all. Function can + * be used to "model" certain buffer capacity without calling a costly + * memory allocation function. + * + * @param NewCapacity A new "forced" capacity. + */ + + void forceCapacity( const capint NewCapacity ) + { + Capacity = NewCapacity; + } + + /** + * Function reallocates *this buffer to a larger size so that it will be + * able to hold the specified number of elements. Downsizing is not + * performed. Alignment is not changed. + * + * @param NewCapacity New (increased) capacity. + * @param DoDataCopy "True" if data in the buffer should be retained. + */ + + void increaseCapacity( const capint NewCapacity, + const bool DoDataCopy = true ) + { + if( NewCapacity < Capacity ) + { + return; + } + + if( DoDataCopy ) + { + const capint PrevCapacity = Capacity; + T* const PrevData = Data; + T* const PrevDataAligned = DataAligned; + + allocinit( NewCapacity, Alignment ); + + if( PrevCapacity > 0 ) + { + memcpy( DataAligned, PrevDataAligned, + PrevCapacity * sizeof( T )); + } + + :: free( PrevData ); + } + else + { + :: free( Data ); + allocinit( NewCapacity, Alignment ); + } + } + + /** + * Function "truncates" (reduces) capacity of the buffer without + * reallocating it. Alignment is not changed. + * + * @param NewCapacity New required capacity. + */ + + void truncateCapacity( const capint NewCapacity ) + { + if( NewCapacity >= Capacity ) + { + return; + } + + Capacity = NewCapacity; + } + + /** + * Function increases capacity so that the specified number of + * elements can be stored. This function increases the previous capacity + * value by third the current capacity value until space for the required + * number of elements is available. Alignment is not changed. + * + * @param ReqCapacity Required capacity. + */ + + void updateCapacity( const capint ReqCapacity ) + { + if( ReqCapacity <= Capacity ) + { + return; + } + + capint NewCapacity = Capacity; + + while( NewCapacity < ReqCapacity ) + { + NewCapacity += NewCapacity / 3 + 1; + } + + increaseCapacity( NewCapacity ); + } + + operator T* () const + { + return( DataAligned ); + } + +private: + T* Data; ///< Element buffer pointer. + ///< + T* DataAligned; ///< Memory address-aligned element buffer pointer. + ///< + capint Capacity; ///< Element buffer capacity. + ///< + int Alignment; ///< Memory address alignment in use. 0 - use stdlib's + ///< default alignment. + ///< + + /** + * Internal element buffer allocation function used during object + * construction. + * + * @param aCapacity Storage for this number of elements to allocate. + * @param aAlignment Buffer's required memory address alignment. 0 - use + * stdlib's default alignment. + */ + + void allocinit( const capint aCapacity, const int aAlignment ) + { + if( aAlignment == 0 ) + { + Data = (T*) :: malloc( aCapacity * sizeof( T )); + DataAligned = Data; + Alignment = 0; + } + else + { + Data = (T*) :: malloc( aCapacity * sizeof( T ) + aAlignment ); + DataAligned = alignptr( Data, aAlignment ); + Alignment = aAlignment; + } + + Capacity = aCapacity; + } + + /** + * Function frees a previously allocated Data buffer. + */ + + void freeData() + { + :: free( Data ); + } + + /** + * Function modifies the specified pointer so that it becomes memory + * address-aligned. + * + * @param ptr Pointer to align. + * @param align Alignment in bytes to apply. + * @return Pointer aligned to align bytes. Works with power-of-2 + * alignments only. If no alignment is necessary, "align" bytes will be + * added to the pointer value. + */ + + template< class Tp > + inline Tp alignptr( const Tp ptr, const uintptr_t align ) + { + return( (Tp) ( (uintptr_t) ptr + align - + ( (uintptr_t) ptr & ( align - 1 ))) ); + } +}; + +/** + * @brief Array of structured objects. + * + * Implements allocation of a linear array of objects of class T (which are + * initialized), addressable via operator[]. Each object is created via the + * "operator new". New object insertions are quick since implementation uses + * prior space allocation (capacity), thus not requiring frequent memory block + * reallocations. + * + * @tparam T Array element's type. + */ + +template< class T > +class CStructArray +{ +public: + CStructArray() + : ItemCount( 0 ) + { + } + + CStructArray( const CStructArray& Source ) + : ItemCount( 0 ) + , Items( Source.getItemCount() ) + { + while( ItemCount < Source.getItemCount() ) + { + Items[ ItemCount ] = new T( Source[ ItemCount ]); + ItemCount++; + } + } + + ~CStructArray() + { + clear(); + } + + CStructArray& operator = ( const CStructArray& Source ) + { + clear(); + + const int NewCount = Source.ItemCount; + Items.updateCapacity( NewCount ); + + while( ItemCount < NewCount ) + { + Items[ ItemCount ] = new T( Source[ ItemCount ]); + ItemCount++; + } + + return( *this ); + } + + T& operator []( const int Index ) + { + return( *Items[ Index ]); + } + + const T& operator []( const int Index ) const + { + return( *Items[ Index ]); + } + + /** + * Function creates a new object of type T with the default constructor + * and adds this object to the array. + * + * @return Reference to a newly added object. + */ + + T& add() + { + if( ItemCount == Items.getCapacity() ) + { + Items.increaseCapacity( ItemCount * 3 / 2 + 1 ); + } + + Items[ ItemCount ] = new T(); + ItemCount++; + + return( (*this)[ ItemCount - 1 ]); + } + + /** + * Function changes number of allocated items. New items are created with + * the default constructor. If NewCount is below the current item count, + * items that are above NewCount range will be destructed. + * + * @param NewCount New requested item count. + */ + + void setItemCount( const int NewCount ) + { + if( NewCount > ItemCount ) + { + Items.increaseCapacity( NewCount ); + + while( ItemCount < NewCount ) + { + Items[ ItemCount ] = new T(); + ItemCount++; + } + } + else + { + while( ItemCount > NewCount ) + { + ItemCount--; + delete Items[ ItemCount ]; + } + } + } + + /** + * Function erases all items of *this array. + */ + + void clear() + { + while( ItemCount > 0 ) + { + ItemCount--; + delete Items[ ItemCount ]; + } + } + + /** + * @return The number of allocated items. + */ + + int getItemCount() const + { + return( ItemCount ); + } + +private: + int ItemCount; ///< The number of items available in the array. + ///< + CBuffer< T* > Items; ///< Element buffer. + ///< +}; + +/** + * @brief Sine signal generator class. + * + * Class implements sine signal generator without biasing, with + * constructor-based initalization only. This generator uses oscillator + * instead of "sin" function. + */ + +class CSineGen +{ +public: + /** + * Constructor initializes *this sine signal generator. + * + * @param si Sine function increment, in radians. + * @param ph Starting phase, in radians. Add 0.5 * AVIR_PI for cosine + * function. + */ + + CSineGen( const double si, const double ph ) + : svalue1( sin( ph )) + , svalue2( sin( ph - si )) + , sincr( 2.0 * cos( si )) + { + } + + /** + * @return The next value of the sine function, without biasing. + */ + + double generate() + { + const double res = svalue1; + + svalue1 = sincr * res - svalue2; + svalue2 = res; + + return( res ); + } + +private: + double svalue1; ///< Current sine value. + ///< + double svalue2; ///< Previous sine value. + ///< + double sincr; ///< Sine value increment. + ///< +}; + +/** + * @brief Peaked Cosine window function generator class. + * + * Class implements Peaked Cosine window function generator. Generates the + * right-handed half of the window function. The Alpha parameter of this + * window function offers the control of the balance between the early and + * later taps of the filter. E.g. at Alpha=1 both early and later taps are + * attenuated, but at Alpha=4 mostly later taps are attenuated. This offers a + * great control over ringing artifacts produced by a low-pass filter in image + * processing, without compromising achieved image sharpness. + */ + +class CDSPWindowGenPeakedCosine +{ +public: + /** + * Constructor initializes *this window function generator. + * + * @param aAlpha Alpha parameter, affects the peak shape (peak + * augmentation) of the window function. Any positive value can be used. + * @param aLen2 Half filter's length (non-truncated). + */ + + CDSPWindowGenPeakedCosine( const double aAlpha, const double aLen2 ) + : Alpha( aAlpha ) + , Len2( aLen2 ) + , Len2i( 1.0 / aLen2 ) + , wn( 0.0 ) + , w1( AVIR_PId2 / Len2, AVIR_PI * 0.5 ) + { + } + + /** + * @return The next Peaked Cosine window function coefficient. + */ + + double generate() + { + const double h = pow( wn * Len2i, Alpha ); + wn += 1.0; + + return( w1.generate() * ( 1.0 - h )); + } + +private: + double Alpha; ///< Alpha parameter, affects the peak shape of window. + ///< + double Len2; ///< Half length of the window function. + ///< + double Len2i; ///< = 1 / Len2. + ///< + double wn; ///< Window function integer position. 0 - center of the + ///< window function. + ///< + CSineGen w1; ///< Sine-wave generator. + ///< +}; + +/** + * @brief FIR filter-based equalizer generator. + * + * Class implements an object used to generate symmetric-odd FIR filters with + * the specified frequency response (aka paragraphic equalizer). The + * calculated filter is windowed by the Peaked Cosine window function. + * + * In image processing, due to short length of filters being used (6-8 taps) + * the resulting frequency response of the filter is approximate and may be + * mathematically imperfect, but still adequate to the visual requirements. + * + * On a side note, this equalizer generator can be successfully used for audio + * signal equalization as well: for example, it is used in almost the same + * form in Voxengo Marvel GEQ equalizer plug-in. + * + * Filter generation is based on decomposition of frequency range into + * spectral bands, with each band represented by linear and ramp "kernels". + * When the filter is built, these kernels are combined together with + * different weights that approximate the required frequency response. + */ + +class CDSPFIREQ +{ +public: + /** + * Function initializes *this object with the required parameters. The + * gain of frequencies beyond the MinFreq..MaxFreq range are controlled by + * the first and the last band's gain. + * + * @param SampleRate Processing sample rate (use 2 for image processing). + * @param aFilterLength Required filter length in samples (taps). The + * actual filter length is truncated to an integer value. + * @param aBandCount Number of band crossover points required to control, + * including bands at MinFreq and MaxFreq. + * @param MinFreq Minimal frequency that should be controlled. + * @param MaxFreq Maximal frequency that should be controlled. + * @param IsLogBands "True" if the bands should be spaced logarithmically. + * @param WFAlpha Peaked Cosine window function's Alpha parameter. + */ + + void init( const double SampleRate, const double aFilterLength, + const int aBandCount, const double MinFreq, const double MaxFreq, + const bool IsLogBands, const double WFAlpha ) + { + FilterLength = aFilterLength; + BandCount = aBandCount; + + CenterFreqs.alloc( BandCount ); + + z = (int) ceil( FilterLength * 0.5 ); + zi = z + ( z & 1 ); + z2 = z * 2; + + CBuffer< double > oscbuf( z2 ); + initOscBuf( oscbuf ); + + CBuffer< double > winbuf( z ); + initWinBuf( winbuf, WFAlpha ); + + UseFirstVirtBand = ( MinFreq > 0.0 ); + const int k = zi * ( BandCount + ( UseFirstVirtBand ? 1 : 0 )); + Kernels1.alloc( k ); + Kernels2.alloc( k ); + + double m; // Frequency step multiplier. + double mo; // Frequency step offset (addition). + + if( IsLogBands ) + { + m = exp( log( MaxFreq / MinFreq ) / ( BandCount - 1 )); + mo = 0.0; + } + else + { + m = 1.0; + mo = ( MaxFreq - MinFreq ) / ( BandCount - 1 ); + } + + double f = MinFreq; + double x1 = 0.0; + double x2; + int si; + + if( UseFirstVirtBand ) + { + si = 0; + } + else + { + si = 1; + CenterFreqs[ 0 ] = 0.0; + f = f * m + mo; + } + + double* kernbuf1 = &Kernels1[ 0 ]; + double* kernbuf2 = &Kernels2[ 0 ]; + int i; + + for( i = si; i < BandCount; i++ ) + { + x2 = f * 2.0 / SampleRate; + CenterFreqs[ i ] = x2; + + fillBandKernel( x1, x2, kernbuf1, kernbuf2, oscbuf, winbuf ); + + kernbuf1 += zi; + kernbuf2 += zi; + x1 = x2; + f = f * m + mo; + } + + if( x1 < 1.0 ) + { + UseLastVirtBand = true; + fillBandKernel( x1, 1.0, kernbuf1, kernbuf2, oscbuf, winbuf ); + } + else + { + UseLastVirtBand = false; + } + } + + /** + * @return Filter's length, in samples (taps). + */ + + int getFilterLength() const + { + return( z2 - 1 ); + } + + /** + * @return Filter's latency (group delay), in samples (taps). + */ + + int getFilterLatency() const + { + return( z - 1 ); + } + + /** + * Function creates symmetric-odd FIR filter with the specified gain + * levels at band crossover points. + * + * @param BandGains Array of linear gain levels, count=BandCount specified + * in the init() function. + * @param[out] Filter Output filter buffer, length = getFilterLength(). + */ + + void buildFilter( const double* const BandGains, double* const Filter ) + { + const double* kernbuf1 = &Kernels1[ 0 ]; + const double* kernbuf2 = &Kernels2[ 0 ]; + double x1 = 0.0; + double y1 = BandGains[ 0 ]; + double x2; + double y2; + + int i; + int si; + + if( UseFirstVirtBand ) + { + si = 1; + x2 = CenterFreqs[ 0 ]; + y2 = y1; + } + else + { + si = 2; + x2 = CenterFreqs[ 1 ]; + y2 = BandGains[ 1 ]; + } + + copyBandKernel( Filter, kernbuf1, kernbuf2, y1 - y2, + x1 * y2 - x2 * y1 ); + + kernbuf1 += zi; + kernbuf2 += zi; + x1 = x2; + y1 = y2; + + for( i = si; i < BandCount; i++ ) + { + x2 = CenterFreqs[ i ]; + y2 = BandGains[ i ]; + + addBandKernel( Filter, kernbuf1, kernbuf2, y1 - y2, + x1 * y2 - x2 * y1 ); + + kernbuf1 += zi; + kernbuf2 += zi; + x1 = x2; + y1 = y2; + } + + if( UseLastVirtBand ) + { + addBandKernel( Filter, kernbuf1, kernbuf2, y1 - y2, + x1 * y2 - y1 ); + } + + for( i = 0; i < z - 1; i++ ) + { + Filter[ z + i ] = Filter[ z - 2 - i ]; + } + } + + /** + * Function calculates filter's length (in samples) and latency depending + * on the required non-truncated filter length. + * + * @param aFilterLength Required filter length in samples (non-truncated). + * @param[out] Latency Resulting latency (group delay) of the filter, + * in samples (taps). + * @return Filter length in samples (taps). + */ + + static int calcFilterLength( const double aFilterLength, int& Latency ) + { + const int l = (int) ceil( aFilterLength * 0.5 ); + Latency = l - 1; + + return( l * 2 - 1 ); + } + +private: + double FilterLength; ///< Length of filter. + ///< + int z; ///< Equals (int) ceil( FilterLength * 0.5 ). + ///< + int zi; ///< Equals "z" if z is even, or z + 1 if z is odd. Used as a + ///< Kernels1 and Kernels2 size multiplier and kernel buffer increment + ///< to make sure each kernel buffer is 16-byte aligned. + ///< + int z2; ///< Equals z * 2. + ///< + int BandCount; ///< Number of controllable bands. + ///< + CBuffer< double > CenterFreqs; ///< Center frequencies for all bands, + ///< normalized to 0.0-1.0 range. + ///< + CBuffer< double > Kernels1; ///< Half-length kernel buffers for each + ///< spectral band (linear part). + ///< + CBuffer< double > Kernels2; ///< Half-length kernel buffers for each + ///< spectral band (ramp part). + ///< + bool UseFirstVirtBand; ///< "True" if the first virtual band + ///< (between 0.0 and MinFreq) should be used. The first virtual band + ///< won't be used if MinFreq equals 0.0. + ///< + bool UseLastVirtBand; ///< "True" if the last virtual band (between + ///< MaxFreq and SampleRate * 0.5) should be used. The last virtual + ///< band won't be used if MaxFreq * 2.0 equals SampleRate. + ///< + + /** + * Function initializes the "oscbuf" used in the fillBandKernel() + * function. + * + * @param oscbuf Oscillator buffer, length = z * 2. + */ + + void initOscBuf( double* oscbuf ) const + { + int i = z; + + while( i > 0 ) + { + oscbuf[ 0 ] = 0.0; + oscbuf[ 1 ] = 1.0; + oscbuf += 2; + i--; + } + } + + /** + * Function initializes window function buffer. This function generates + * Peaked Cosine window function. + * + * @param winbuf Windowing buffer. + * @param Alpha Peaked Cosine alpha parameter. + */ + + void initWinBuf( double* winbuf, const double Alpha ) const + { + CDSPWindowGenPeakedCosine wf( Alpha, FilterLength * 0.5 ); + int i; + + for( i = 1; i <= z; i++ ) + { + winbuf[ z - i ] = wf.generate(); + } + } + + /** + * Function fills first half of symmetric-odd FIR kernel for the band. + * This function should be called successively for adjacent bands. + * Previous band's x2 should be equal to current band's x1. A band kernel + * consists of 2 elements: linear kernel and ramp kernel. + * + * @param x1 Band's left corner frequency (0..1). + * @param x2 Band's right corner frequency (0..1). + * @param kernbuf1 Band kernel buffer 1 (linear part), length = z. + * @param kernbuf2 Band kernel buffer 2 (ramp part), length = z. + * @param oscbuf Oscillation buffer. Before the first call of the + * fillBandKernel() should be initialized with the call of the + * initOscBuf() function. + * @param winbuf Buffer that contains windowing function. + */ + + void fillBandKernel( const double x1, const double x2, double* kernbuf1, + double* kernbuf2, double* oscbuf, const double* const winbuf ) + { + const double s2_incr = AVIR_PI * x2; + const double s2_coeff = 2.0 * cos( s2_incr ); + + double s2_value1 = sin( s2_incr * ( -z + 1 )); + double c2_value1 = sin( s2_incr * ( -z + 1 ) + AVIR_PI * 0.5 ); + oscbuf[ 0 ] = sin( s2_incr * -z ); + oscbuf[ 1 ] = sin( s2_incr * -z + AVIR_PI * 0.5 ); + + int ks; + + for( ks = 1; ks < z; ks++ ) + { + const int ks2 = ks * 2; + const double s1_value1 = oscbuf[ ks2 ]; + const double c1_value1 = oscbuf[ ks2 + 1 ]; + oscbuf[ ks2 ] = s2_value1; + oscbuf[ ks2 + 1 ] = c2_value1; + + const double x = AVIR_PI * ( ks - z ); + const double v0 = winbuf[ ks - 1 ] / (( x1 - x2 ) * x ); + + kernbuf1[ ks - 1 ] = ( x2 * s2_value1 - x1 * s1_value1 + + ( c2_value1 - c1_value1 ) / x ) * v0; + + kernbuf2[ ks - 1 ] = ( s2_value1 - s1_value1 ) * v0; + + s2_value1 = s2_coeff * s2_value1 - oscbuf[ ks2 - 2 ]; + c2_value1 = s2_coeff * c2_value1 - oscbuf[ ks2 - 1 ]; + } + + kernbuf1[ z - 1 ] = ( x2 * x2 - x1 * x1 ) / ( x1 - x2 ) * 0.5; + kernbuf2[ z - 1 ] = -1.0; + } + + /** + * Function copies band kernel's elements to the output buffer. + * + * @param outbuf Output buffer. + * @param kernbuf1 Kernel buffer 1 (linear part). + * @param kernbuf2 Kernel buffer 2 (ramp part). + * @param c Multiplier for linear kernel element. + * @param d Multiplier for ramp kernel element. + */ + + void copyBandKernel( double* outbuf, const double* const kernbuf1, + const double* const kernbuf2, const double c, const double d ) const + { + int ks; + + for( ks = 0; ks < z; ks++ ) + { + outbuf[ ks ] = c * kernbuf1[ ks ] + d * kernbuf2[ ks ]; + } + } + + /** + * Function adds band kernel's elements to the output buffer. + * + * @param outbuf Output buffer. + * @param kernbuf1 Kernel buffer 1 (linear part). + * @param kernbuf2 Kernel buffer 2 (ramp part). + * @param c Multiplier for linear kernel element. + * @param d Multiplier for ramp kernel element. + */ + + void addBandKernel( double* outbuf, const double* const kernbuf1, + const double* const kernbuf2, const double c, const double d ) const + { + int ks; + + for( ks = 0; ks < z; ks++ ) + { + outbuf[ ks ] += c * kernbuf1[ ks ] + d * kernbuf2[ ks ]; + } + } +}; + +/** + * @brief Low-pass filter windowed by Peaked Cosine window function. + * + * This class implements calculation of linear-phase symmetric-odd FIR + * low-pass filter windowed by the Peaked Cosine window function, for image + * processing applications. + */ + +class CDSPPeakedCosineLPF +{ +public: + int fl2; ///< Half filter's length, excluding the peak value. This value + ///< can be also used as filter's latency in samples (taps). + ///< + int FilterLen; ///< Filter's length in samples (taps). + ///< + + /** + * Constructor initalizes *this object. + * + * @param aLen2 Half-length (non-truncated) of low-pass filter, in samples + * (taps). + * @param aFreq2 Low-pass filter's corner frequency [0; pi]. + * @param aAlpha Peaked Cosine window function Alpha parameter. + */ + + CDSPPeakedCosineLPF( const double aLen2, const double aFreq2, + const double aAlpha ) + : fl2( (int) ceil( aLen2 ) - 1 ) + , FilterLen( fl2 + fl2 + 1 ) + , Len2( aLen2 ) + , Freq2( aFreq2 ) + , Alpha( aAlpha ) + { + } + + /** + * Function generates a linear-phase low-pass filter windowed by Peaked + * Cosine window function. + * + * @param[out] op Output buffer, length = FilterLen (fl2 * 2 + 1). + * @param DCGain Required gain at DC. The resulting filter will be + * normalized to achieve this DC gain. If non-positive, no automatic + * normalization will be performed. + */ + + template< class T > + void generateLPF( T* op, const double DCGain ) + { + CDSPWindowGenPeakedCosine wf( Alpha, Len2 ); + CSineGen f2( Freq2, 0.0 ); + + op += fl2; + T* op2 = op; + f2.generate(); + + if( DCGain > 0.0 ) + { + int t = 1; + + *op = (T) ( Freq2 * wf.generate() ); + double s = *op; + + while( t <= fl2 ) + { + const T v = (T) ( f2.generate() * wf.generate() / t ); + op++; + op2--; + *op = v; + *op2 = v; + s += v + v; + t++; + } + + t = FilterLen; + s = DCGain / s; + + while( t > 0 ) + { + *op2 = (T) ( *op2 * s ); + op2++; + t--; + } + } + else + { + int t = 1; + + *op = (T) ( Freq2 * wf.generate() ); + + while( t <= fl2 ) + { + const T v = (T) ( f2.generate() * wf.generate() / t ); + op++; + op2--; + *op = v; + *op2 = v; + t++; + } + } + } + +private: + double Len2; ///< Half-length (non-truncated) of low-pass filter, in + ///< samples (taps). + ///< + double Freq2; ///< Low-pass filter's corner frequency. + ///< + double Alpha; ///< Peaked Cosine window function Alpha parameter. + ///< +}; + +/** + * @brief Buffer class for parametrized low-pass filter. + * + * This class extends the CBuffer< double > class by adding several variables + * that define a symmetric-odd FIR low-pass filter windowed by Peaked Cosine + * window function. This class can be used to compare filters without + * comparing their buffer contents. + */ + +class CFltBuffer : public CBuffer< double > +{ +public: + double Len2; ///< Half-length (non-truncated) of low-pass filters, in + ///< samples (taps). + ///< + double Freq; ///< Low-pass filter's corner frequency. + ///< + double Alpha; ///< Peaked Cosine window function Alpha parameter. + ///< + double DCGain; ///< DC gain applied to the filter. + ///< + + CFltBuffer() + : CBuffer< double >() + , Len2( 0.0 ) + , Freq( 0.0 ) + , Alpha( 0.0 ) + , DCGain( 0.0 ) + { + } + + /** + * @param b2 Filter buffer to compare *this object to. + * @return Operator returns "true" if both filters have same parameters. + */ + + bool operator == ( const CFltBuffer& b2 ) const + { + return( Len2 == b2.Len2 && Freq == b2.Freq && Alpha == b2.Alpha && + DCGain == b2.DCGain ); + } +}; + +/** + * @brief Sinc function-based fractional delay filter bank. + * + * Class implements storage and initialization of a bank of sinc + * function-based fractional delay filters, expressed as 1st order polynomial + * interpolation coefficients. The filters are produced from a single "long" + * windowed low-pass filter. Also supports 0th-order ("nearest neighbor") + * interpolation. + * + * This class also supports multiplication of each fractional delay filter by + * an external filter (usually a low-pass filter). + * + * @tparam fptype Specifies storage type of the filter coefficients bank. The + * filters are initially calculated using the "double" precision. + */ + +template< class fptype > +class CDSPFracFilterBankLin +{ + AVIR_NOCTOR( CDSPFracFilterBankLin ); + +public: + CDSPFracFilterBankLin() + : Order( -1 ) + { + } + + /** + * Copy constructor copies a limited set of parameters of the source + * filter bank. The actual filters are not copied. Such copying is used + * during filtering steps "modeling" stage. A further init() function + * call is required. + * + * @param s Source filter bank. + */ + + void copyInitParams( const CDSPFracFilterBankLin& s ) + { + WFLen2 = s.WFLen2; + WFFreq = s.WFFreq; + WFAlpha = s.WFAlpha; + FracCount = s.FracCount; + Order = s.Order; + Alignment = s.Alignment; + SrcFilterLen = s.SrcFilterLen; + FilterLen = s.FilterLen; + FilterSize = s.FilterSize; + IsSrcTableBuilt = false; + ExtFilter = s.ExtFilter; + TableFillFlags.alloc( s.TableFillFlags.getCapacity() ); + int i; + + // Copy table fill flags, but shifted so that further initialization + // is still possible (such feature should not be used, though). + + for( i = 0; i < TableFillFlags.getCapacity(); i++ ) + { + TableFillFlags[ i ] = (uint8_t) ( s.TableFillFlags[ i ] << 2 ); + } + } + + /** + * Operator compares *this filter bank and another filter bank and returns + * "true" if their parameters are equal. Alignment is not taken into + * account. + * + * @param s Filter bank to compare to. + * @return "True" if compared banks have equal parameters. + */ + + bool operator == ( const CDSPFracFilterBankLin& s ) const + { + return( Order == s.Order && WFLen2 == s.WFLen2 && + WFFreq == s.WFFreq && WFAlpha == s.WFAlpha && + FracCount == s.FracCount && ExtFilter == s.ExtFilter ); + } + + /** + * Function initializes (builds) the filter bank based on the supplied + * parameters. If the supplied parameters are equal to previously defined + * parameters, function does nothing (alignment is assumed to be never + * changing between the init() function calls). + * + * @param ReqFracCount Required number of fractional delays in the filter + * bank. The minimal value is 2. + * @param ReqOrder Required order of the interpolation polynomial + * (0 or 1). + * @param BaseLen Low-pass filter's base length, in samples (taps). + * Affects the actual length of the filter and its overall steepness. + * @param Cutoff Low-pass filter's normalized cutoff frequency [0; 1]. + * @param aWFAlpha Peaked Cosine window function's Alpha parameter. + * @param aExtFilter External filter to apply to each fractional delay + * filter. + * @param aAlignment Memory alignment of the filter bank, power-of-2 + * value. 0 - use default stdlib alignment. + * @param FltLenAlign Filter's length alignment, power-of-2 value. + */ + + void init( const int ReqFracCount, const int ReqOrder, + const double BaseLen, const double Cutoff, const double aWFAlpha, + const CFltBuffer& aExtFilter, const int aAlignment = 0, + const int FltLenAlign = 1 ) + { + double NewWFLen2 = 0.5 * BaseLen * ReqFracCount; + double NewWFFreq = AVIR_PI * Cutoff / ReqFracCount; + double NewWFAlpha = aWFAlpha; + + if( ReqOrder == Order && NewWFLen2 == WFLen2 && NewWFFreq == WFFreq && + NewWFAlpha == WFAlpha && ReqFracCount == FracCount && + aExtFilter == ExtFilter ) + { + IsInitRequired = false; + return; + } + + WFLen2 = NewWFLen2; + WFFreq = NewWFFreq; + WFAlpha = NewWFAlpha; + FracCount = ReqFracCount; + Order = ReqOrder; + Alignment = aAlignment; + ExtFilter = aExtFilter; + + CDSPPeakedCosineLPF p( WFLen2, WFFreq, WFAlpha ); + SrcFilterLen = ( p.fl2 / ReqFracCount + 1 ) * 2; + + const int ElementSize = ReqOrder + 1; + FilterLen = SrcFilterLen; + + if( ExtFilter.getCapacity() > 0 ) + { + FilterLen += ExtFilter.getCapacity() - 1; + } + + FilterLen = ( FilterLen + FltLenAlign - 1 ) & ~( FltLenAlign - 1 ); + FilterSize = FilterLen * ElementSize; + IsSrcTableBuilt = false; + IsInitRequired = true; + } + + /** + * @return The length of each fractional delay filter, in samples (taps). + * Always an even value. + */ + + int getFilterLen() const + { + return( FilterLen ); + } + + /** + * @return The number of fractional filters in use by *this bank. + */ + + int getFracCount() const + { + return( FracCount ); + } + + /** + * @return The order of the interpolation polynomial. + */ + + int getOrder() const + { + return( Order ); + } + + /** + * Function returns the pointer to the specified interpolation table + * filter. + * + * @param i Filter (fractional delay) index, in the range 0 to + * ReqFracCount - 1, inclusive. + * @return Pointer to filter. Higher order polynomial coefficients are + * stored after after previous order coefficients, separated by FilterLen + * elements. + */ + + const fptype* getFilter( const int i ) + { + if( !IsSrcTableBuilt ) + { + buildSrcTable(); + } + + fptype* const Res = &Table[ i * FilterSize ]; + + if(( TableFillFlags[ i ] & 2 ) == 0 ) + { + createFilter( i ); + TableFillFlags[ i ] |= 2; + + if( Order > 0 ) + { + createFilter( i + 1 ); + const fptype* const Res2 = Res + FilterSize; + fptype* const op = Res + FilterLen; + int j; + + // Create higher-order interpolation coefficients (linear + // interpolation). + + for( j = 0; j < FilterLen; j++ ) + { + op[ j ] = Res2[ j ] - Res[ j ]; + } + } + } + + return( Res ); + } + + /** + * Function makes sure all fractional delay filters were created. + */ + + void createAllFilters() + { + int i; + + for( i = 0; i < FracCount; i++ ) + { + getFilter( i ); + } + } + + /** + * Function returns an approximate initialization complexity, expressed in + * the number of multiply-add operations. This includes fractional delay + * filters calculation and multiplication by an external filter. This + * function can only be called after the init() function. + * + * @param FracUseMap Fractional delays use map, each element corresponds + * to a single fractional delay, will be compared to the internal table + * fill flags. This map should include 0 and 1 values only. + * @return The complexity of the initialization, expressed in the number + * of multiply-add operations. + */ + + int calcInitComplexity( const CBuffer< uint8_t >& FracUseMap ) const + { + const int FltInitCost = 65; // Cost to initialize a single sample + // of the fractional delay filter. + const int FltUseCost = FilterLen * Order + + SrcFilterLen * ExtFilter.getCapacity(); // Cost to use a single + // fractional delay filter. + const int ucb[ 2 ] = { 0, FltUseCost }; + int ic; + int i; + + if( IsInitRequired ) + { + ic = FracCount * SrcFilterLen * FltInitCost; + + for( i = 0; i < FracCount; i++ ) + { + ic += ucb[ FracUseMap[ i ]]; + } + } + else + { + ic = 0; + + for( i = 0; i < FracCount; i++ ) + { + if( FracUseMap[ i ] != 0 ) + { + ic += ucb[ TableFillFlags[ i ] == 0 ? 1 : 0 ]; + } + } + } + + return( ic ); + } + +private: + static const int InterpPoints = 2; ///< The maximal number of points the + ///< interpolation is based on. + ///< + double WFLen2; ///< Window function's Len2 parameter. + ///< + double WFFreq; ///< Window function's Freq parameter. + ///< + double WFAlpha; ///< Window function's Alpha parameter. + ///< + int FracCount; ///< The required number of fractional delay filters. + ///< + int Order; ///< The order of the interpolation polynomial. + ///< + int Alignment; ///< The required filter table alignment. + ///< + int SrcFilterLen; ///< Length of the "source" filters. This is always an + ///< even value. + ///< + int FilterLen; ///< Specifies the number of samples (taps) each fractional + ///< delay filter has. This is always an even value, adjusted by the + ///< FltLenAlign. + ///< + int FilterSize; ///< The size of a single filter element, equals + ///< FilterLen * ElementSize. + ///< + bool IsInitRequired; ///< "True" if SrcTable filter table initialization + ///< is required. This value is available only after the call to the + ///< init() function. + ///< + CBuffer< fptype > Table; ///< Interpolation table, size equals to + ///< ReqFracCount * FilterLen * ElementSize. + ///< + CBuffer< uint8_t > TableFillFlags; ///< Contains ReqFracCount + 1 + ///< elements. Bit 0 of every element is 1 if Table already contains + ///< the filter from SrcTable filtered by ExtFilter. Bit 1 of every + ///< element means higher order coefficients were filled for the + ///< filter. + ///< + CFltBuffer ExtFilter; ///< External filter that should be applied to every + ///< fractional delay filter. Can be empty. Half of this filter's + ///< capacity is used as latency (group delay) value of the filter. + ///< + CBuffer< double > SrcTable; ///< Source table of delay filters, contains + ///< ReqFracCount + 1 elements. This table is used to fill the Table + ///< with the actual filters, filtered by an external filter. + ///< + bool IsSrcTableBuilt; ///< "True" if the SrcTable was built already. This + ///< variable is set to "false" in the init() function. + ///< + + /** + * Function builds source table used in the createFilter() function. + */ + + void buildSrcTable() + { + IsSrcTableBuilt = true; + IsInitRequired = false; + + CDSPPeakedCosineLPF p( WFLen2, WFFreq, WFAlpha ); + + const int BufLen = SrcFilterLen * FracCount + InterpPoints - 1; + const int BufOffs = InterpPoints / 2 - 1; + const int BufCenter = SrcFilterLen * FracCount / 2 + BufOffs; + + CBuffer< double > Buf( BufLen ); + memset( Buf, 0, ( BufCenter - p.fl2 ) * sizeof( double )); + int i = BufLen - BufCenter - p.fl2 - 1; + memset( &Buf[ BufLen - i ], 0, i * sizeof( double )); + + p.generateLPF( &Buf[ BufCenter - p.fl2 ], 0.0 ); + + SrcTable.alloc(( FracCount + 1 ) * SrcFilterLen ); + TableFillFlags.alloc( FracCount + 1 ); + int j; + double* op0 = SrcTable; + + for( i = FracCount; i >= 0; i-- ) + { + TableFillFlags[ i ] = 0; + double* p = Buf + BufOffs + i; + + for( j = 0; j < SrcFilterLen; j++ ) + { + op0[ 0 ] = p[ 0 ]; + op0++; + p += FracCount; + } + + normalizeFIRFilter( op0 - SrcFilterLen, SrcFilterLen, 1.0 ); + } + + Table.alloc(( FracCount + 1 ) * FilterSize, Alignment ); + } + + /** + * Function creates the specified filter in the Table by copying it from + * the SrcTable and filtering by ExtFilter. Function does nothing if + * filter was already created. + * + * @param k Filter index to create, in the range 0 to FracCount, + * inclusive. + */ + + void createFilter( const int k ) + { + if( TableFillFlags[ k ] != 0 ) + { + return; + } + + TableFillFlags[ k ] |= 1; + const int ExtFilterLatency = ExtFilter.getCapacity() / 2; + const int ResLatency = ExtFilterLatency + SrcFilterLen / 2; + int ResLen = SrcFilterLen; + + if( ExtFilter.getCapacity() > 0 ) + { + ResLen += ExtFilter.getCapacity() - 1; + } + + const int ResOffs = FilterLen / 2 - ResLatency; + fptype* op = &Table[ k * FilterSize ]; + int i; + + for( i = 0; i < ResOffs; i++ ) + { + op[ i ] = (fptype) 0; + } + + for( i = ResOffs + ResLen; i < FilterLen; i++ ) + { + op[ i ] = (fptype) 0; + } + + op += ResOffs; + const double* const srcflt = &SrcTable[ k * SrcFilterLen ]; + + if( ExtFilter.getCapacity() == 0 ) + { + for( i = 0; i < ResLen; i++ ) + { + op[ i ] = (fptype) srcflt[ i ]; + } + + return; + } + + // Perform convolution of extflt and srcflt. + + const double* const extflt = &ExtFilter[ 0 ]; + int j; + + for( j = 0; j < ResLen; j++ ) + { + int k = 0; + int l = j - ExtFilter.getCapacity() + 1; + int r = l + ExtFilter.getCapacity(); + + if( l < 0 ) + { + k -= l; + l = 0; + } + + if( r > SrcFilterLen ) + { + r = SrcFilterLen; + } + + const double* const extfltb = extflt + k; + const double* const srcfltb = srcflt + l; + double s = 0.0; + l = r - l; + + for( i = 0; i < l; i++ ) + { + s += extfltb[ i ] * srcfltb[ i ]; + } + + op[ j ] = (fptype) s; + } + } +}; + +/** + * @brief Thread pool for multi-threaded image resizing operation. + * + * This base class is used to organize a multi-threaded image resizing + * operation. The thread pool should consist of threads that initially wait + * for a signal. Upon receiving a signal (via the startAllWorkloads() + * function) each previously added thread should execute its workload's + * process() function once, and return to the wait signal state again. The + * thread pool should be also able to efficiently wait for all workloads to + * finish via the waitAllWorkloadsToFinish() function. + * + * The image resizing algorithm makes calls to functions of this class. + */ + +class CImageResizerThreadPool +{ +public: + CImageResizerThreadPool() + { + } + + virtual ~CImageResizerThreadPool() + { + } + + /** + * @brief Thread pool's workload object class. + * + * This class should be used as a base class for objects that perform the + * actual work spread over several threads. + */ + + class CWorkload + { + public: + virtual ~CWorkload() + { + } + + /** + * Function that gets called from the thread when thread pool's + * startAllWorkloads() function is called. + */ + + virtual void process() = 0; + }; + + /** + * @return The suggested number of workloads (and their associated + * threads) to add. The minimal value this function can return is 1. The + * usual value may depend on the number of physical and virtual cores + * present in the system, and on other considerations. + */ + + virtual int getSuggestedWorkloadCount() const + { + return( 1 ); + } + + /** + * Function adds a new workload (and possibly thread) to the thread pool. + * The caller decides how many parallel workloads (and threads) it + * requires, but this number will not exceed the value returned by the + * getSuggestedWorkloadCount() function. It is implementation-specific how + * many workloads to associate with a single thread. But for efficiency + * reasons each workload should be associated with its own thread. + * + * Note that the same set of workload objects will be processed each time + * the startAllWorkloads() function is called. This means that workload + * objects are added only once. The caller changes the state of the + * workload objects and then calls the startAllWorkloads() function to + * process them. + * + * @param Workload Workload object whose process() function will be called + * from within the thread when the startAllWorkloads() function is called. + */ + + virtual void addWorkload( CWorkload* const Workload ) + { + } + + /** + * Function starts all workloads associated with threads previously added + * via the addWorkload() function. It is assumed that this function + * performs the necessary "memory barrier" (or "cache sync") kind of + * operation so that all threads catch up the prior changes made to the + * workload objects during their wait state. + */ + + virtual void startAllWorkloads() + { + } + + /** + * Function waits for all workloads to finish. + */ + + virtual void waitAllWorkloadsToFinish() + { + } + + /** + * Function removes all workloads previously added via the addWorkload() + * function. This function gets called only after the + * waitAllWorkloadsToFinish() function call. + */ + + virtual void removeAllWorkloads() + { + } +}; + +/** + * @brief Resizing algorithm parameters structure. + * + * This structure holds all selectable parameters used by the resizing + * algorithm at various stages, for both downsizing and upsizing. There are no + * other parameters exist that can optimize the performance of the resizing + * algorithm. Filter length parameters can take fractional values. + * + * Beside quality, these parameters (except Alpha parameters) directly affect + * the computative cost of the resizing algorithm. It is possible to trade + * the visual quality for computative cost. + * + * Anti-alias filtering during downsizing can be defined as a considerable + * reduction of contrast of smallest features of an image. Unfortunately, such + * de-contrasting partially affects features of all sizes thus producing a + * non-linearity of frequency response. All pre-defined parameter sets are + * described by 3 values separated by slashes. The first value is the + * de-contrasting factor of small features (which are being removed) while + * the second value is the de-contrasting factor of large features (which + * should remain intact), with value of 1 equating to "no contrast change". + * The third value is the optimization score (see below), with value of 0 + * equating to the "perfect" linearity of frequency response. + * + * The pre-defined parameter sets offered by this library were auto-optimized + * for the given LPFltBaseLen, IntFltLen and CorrFltAlpha values. The + * optimization goal was to minimize the score: the sum of squares of the + * difference between original and processed images (which was not actually + * resized, k=1). The original image was a 0.5 megapixel uniformly-distributed + * white-noise image with pixel intensities in the 0-1 range. Such goal + * converges very well and produces filtering system with the flattest + * frequency response possible for the given constraints. With this goal, + * increasing the LPFltBaseLen value reduces the general amount of aliasing + * artifacts. + */ + +struct CImageResizerParams +{ + double CorrFltAlpha; ///< Alpha parameter of the Peaked Cosine window + ///< function used on the correction filter. The "usable" values are + ///< in the narrow range 1.0 to 1.5. + ///< + double CorrFltLen; ///< Correction filter's length in samples (taps). The + ///< "usable" range is narrow, 5.5 to 8, as to minimize the + ///< "overcorrection" which is mathematically precise, but visually + ///< unacceptable. + ///< + double IntFltAlpha; ///< Alpha parameter of the Peaked Cosine window + ///< function used on the interpolation low-pass filter. The "usable" + ///< values are in the range 1.5 to 2.5. + ///< + double IntFltCutoff; ///< Interpolation low-pass filter's cutoff frequency + ///< (normalized, [0; 1]). The "usable" range is 0.6 to 0.8. + ///< + double IntFltLen; ///< Interpolation low-pass filter's length in samples + ///< (taps). The length value should be at least 18 or otherwise a + ///< "dark grid" artifact will be introduced if a further sharpening + ///< is applied. IntFltLen together with other IntFlt parameters + ///< should be tuned in a way that produces the flattest frequency + ///< response in 0-0.5 normalized frequency range (this range is due + ///< to 2X upsampling). + ///< + double LPFltAlpha; ///< Alpha parameter of the Peaked Cosine window + ///< function used on the low-pass filter. The "usable" values are + ///< in the range 1.5 to 6.5. + ///< + double LPFltBaseLen; ///< Base length of the low-pass (aka anti-aliasing + ///< or reconstruction) filter, in samples (taps), further adjusted by + ///< the actual cutoff frequency, upsampling and downsampling factors. + ///< The "usable" range is between 6 and 9. + ///< + double LPFltCutoffMult; ///< Low-pass filter's cutoff frequency + ///< multiplier. This value can be both below and above 1.0 as + ///< low-pass filters are inserted on downsampling and upsampling + ///< steps and always have corner frequency equal to or below 0.5pi. + ///< This multiplier shifts low-pass filter's corner frequency towards + ///< lower (if below 1.0) or higher (if above 1.0) frequencies. This + ///< multiplier can be way below 1.0 since any additional + ///< high-frequency damping will be partially corrected by the + ///< correction filter. The "usable" range is 0.3 to 1.0. + ///< + + CImageResizerParams() + : HBFltAlpha( 1.94609 ) + , HBFltCutoff( 0.46437 ) + , HBFltLen( 24 ) + { + } + + double HBFltAlpha; ///< Half-band filter's Alpha. Assigned internally. + ///< + double HBFltCutoff; ///< Half-band filter's cutoff point [0; 1]. Assigned + ///< internally. + ///< + double HBFltLen; ///< Length of the half-band low-pass filter. Assigned + ///< internally. Internally used to perform 2X or higher downsampling. + ///< These filter parameters should be treated as "technical" and do + ///< not require adjustment as they were tuned to suit all + ///< combinations of other parameters. This half-band filter provides + ///< a wide transition band (for minimal ringing artifacts) and a high + ///< stop-band attenuation (for minimal aliasing). + ///< +}; + +/** + * @brief The default set of resizing algorithm parameters + * (10.06/1.88/1.029(256064.90)/0.000039). + * + * This is the default set of resizing parameters that was designed to deliver + * a sharp image while still providing a low amount of ringing artifacts, and + * having a reasonable computational cost. + */ + +struct CImageResizerParamsDef : public CImageResizerParams +{ + CImageResizerParamsDef() + { + CorrFltAlpha = 0.97946;//10.06/1.88/1.029(256064.90)/0.000039:258649,447179 + CorrFltLen = 6.4262; + IntFltAlpha = 6.41341; + IntFltCutoff = 0.7372; + IntFltLen = 18; + LPFltAlpha = 4.76449; + LPFltBaseLen = 7.55999999999998; + LPFltCutoffMult = 0.79285; + } +}; + +/** + * @brief Set of resizing algorithm parameters for ultra-low-ringing + * performance (7.50/2.01/1.083(11568559.86)/0.000001). + * + * This set of resizing algorithm parameters offers the lowest amount of + * ringing this library is capable of providing while still offering a decent + * quality. Low ringing is attained at the expense of higher aliasing + * artifacts and a slightly reduced contrast. + */ + +struct CImageResizerParamsULR : public CImageResizerParams +{ + CImageResizerParamsULR() + { + CorrFltAlpha = 0.95521;//7.50/2.01/1.083(11568559.86)/0.000001:258649,434609 + CorrFltLen = 5.70774; + IntFltAlpha = 1.00766; + IntFltCutoff = 0.74202; + IntFltLen = 18; + LPFltAlpha = 1.6801; + LPFltBaseLen = 6.62; + LPFltCutoffMult = 0.67821; + } +}; + +/** + * @brief Set of resizing algorithm parameters for low-ringing performance + * (7.91/1.96/1.065(1980857.66)/0.000004). + * + * This set of resizing algorithm parameters offers a very low-ringing + * performance at the expense of higher aliasing artifacts and a slightly + * reduced contrast. + */ + +struct CImageResizerParamsLR : public CImageResizerParams +{ + CImageResizerParamsLR() + { + CorrFltAlpha = 1;//7.91/1.96/1.065(1980857.66)/0.000004:258649,437578 + CorrFltLen = 5.865; + IntFltAlpha = 1.79529; + IntFltCutoff = 0.74325; + IntFltLen = 18; + LPFltAlpha = 1.87597; + LPFltBaseLen = 6.89999999999999; + LPFltCutoffMult = 0.69326; + } +}; + +/** + * @brief Set of resizing algorithm parameters for lower-ringing performance + * (9.21/1.91/1.040(391960.71)/0.000023). + * + * This set of resizing algorithm parameters offers a lower-ringing + * performance in comparison to the default setting, at the expense of higher + * aliasing artifacts and a slightly reduced contrast. + */ + +struct CImageResizerParamsLow : public CImageResizerParams +{ + CImageResizerParamsLow() + { + CorrFltAlpha = 0.99739;//9.21/1.91/1.040(391960.71)/0.000023:258649,444105 + CorrFltLen = 6.20326; + IntFltAlpha = 4.6836; + IntFltCutoff = 0.73879; + IntFltLen = 18; + LPFltAlpha = 7.86565; + LPFltBaseLen = 6.91999999999999; + LPFltCutoffMult = 0.78379; + } +}; + +/** + * @brief Set of resizing algorithm parameters for low-aliasing + * resizing (11.59/1.84/1.015(73054.59)/0.000159). + * + * This set of resizing algorithm parameters offers a considerable + * anti-aliasing performance with a good frequency response linearity (and + * contrast). This is an intermediate setting between the default and Ultra + * parameters. + */ + +struct CImageResizerParamsHigh : public CImageResizerParams +{ + CImageResizerParamsHigh() + { + CorrFltAlpha = 0.97433;//11.59/1.84/1.015(73054.59)/0.000159:258649,451830 + CorrFltLen = 6.87893; + IntFltAlpha = 7.74731; + IntFltCutoff = 0.73844; + IntFltLen = 18; + LPFltAlpha = 4.8149; + LPFltBaseLen = 8.07999999999996; + LPFltCutoffMult = 0.79335; + } +}; + +/** + * @brief Set of resizing algorithm parameters for ultra low-aliasing + * resizing (13.68/1.79/1.000(521792.07)/0.000026). + * + * This set of resizing algorithm parameters offers a very considerable + * anti-aliasing performance with a good frequency response linearity (and + * contrast). This set of parameters is computationally expensive and may + * produce ringing artifacts on sharp features. + */ + +struct CImageResizerParamsUltra : public CImageResizerParams +{ + CImageResizerParamsUltra() + { + CorrFltAlpha = 0.99705;//13.68/1.79/1.000(521792.07)/0.000026:258649,457973 + CorrFltLen = 7.42695; + IntFltAlpha = 1.71985; + IntFltCutoff = 0.7571; + IntFltLen = 18; + LPFltAlpha = 6.71313; + LPFltBaseLen = 8.27999999999996; + LPFltCutoffMult = 0.78413; + } +}; + +/** + * @brief Image resizing variables class. + * + * This is an utility "catch all" class that defines various variables used + * during image resizing. Several variables that are explicitly initialized in + * this class' constructor are also used as additional "input" variables to + * the image resizing function. These variables will not be changed by the + * avir::CImageResizer<>::resizeImage() function. + */ + +class CImageResizerVars +{ +public: + int ElCount; ///< The number of "fptype" elements used to store 1 pixel. + ///< + int ElCountIO; ///< The number of source and destination image's elements + ///< used to store 1 pixel. + ///< + int fppack; ///< The number of atomic types stored in a single "fptype" + ///< element. + ///< + int fpalign; ///< Suggested alignment size in bytes. This is not a + ///< required alignment, because image resizing algorithm cannot be + ///< made to have a strictly aligned data access in all cases (e.g. + ///< de-interleaved interpolation cannot perform aligned accesses). + ///< + int elalign; ///< Length alignment of arrays of elements. This applies to + ///< filters and intermediate buffers: this constant forces filters + ///< and scanlines to have a length which is a multiple of this value, + ///< for more efficient SIMD implementation. + ///< + int packmode; ///< 0 if interleaved packing, 1 if de-interleaved. + ///< + int BufLen[ 2 ]; ///< Intermediate buffers' lengths in "fptype" elements. + int BufOffs[ 2 ]; ///< Offsets into the intermediate buffers, used to + ///< provide prefix elements required during processing so that no + ///< "out of range" access happens. This offset is a multiple of + ///< ElCount if pixels are stored in interleaved form. + ///< + double k; ///< Resizing step coefficient, updated to reflect the actually + ///< used coefficient during resizing. + ///< + double o; ///< Starting pixel offset inside the source image, updated to + ///< reflect the actually used offset during resizing. + ///< + int ResizeStep; ///< Index of the resizing step in the latest filtering + ///< steps array. + ///< + bool IsResize2; ///< Use optimized "doResize2" function. + ///< + double InGammaMult; ///< Input gamma multiplier, used to convert input + ///< data to 0 to 1 range. 0.0 if no gamma is in use. + ///< + double OutGammaMult; ///< Output gamma multiplier, used to convert data to + ///< 0 to 255/65535 range. 0.0 if no gamma is in use. + ///< + + double ox; ///< Start X pixel offset within source image (can be + ///< negative). Positive offset moves image to the left. + ///< + double oy; ///< Start Y pixel offset within source image (can be + ///< negative). Positive offset moves image to the top. + ///< + CImageResizerThreadPool* ThreadPool; ///< Thread pool to be used by the + ///< image resizing function. Set to NULL to use single-threaded + ///< processing. + ///< + bool UseSRGBGamma; ///< Perform sRGB gamma linearization (correction). + ///< + int BuildMode; ///< The build mode to use, for debugging purposes. Set to + ///< -1 to select a minimal-complexity mode automatically. All build + ///< modes deliver similar results with minor deviations. + ///< + int RndSeed; ///< Random seed parameter. This parameter may be incremented + ///< after each random generator initialization. The use of this + ///< variable depends on the ditherer implementation. + ///< + + CImageResizerVars() + : ox( 0.0 ) + , oy( 0.0 ) + , ThreadPool( NULL ) + , UseSRGBGamma( false ) + , BuildMode( -1 ) + , RndSeed( 0 ) + { + } +}; + +/** + * @brief Image resizer's filtering step class. + * + * Class defines data to perform a single filtering step over a whole + * horizontal or vertical scanline. Resizing consists of 1 or more steps that + * may be performed before the actual resizing takes place. Filtering may also + * follow a resizing step. Each step must ensure that scanline data contains + * enough pixels to perform the next step (which may be resizing) without + * exceeding scanline's bounds. + * + * A derived class must implement several "const" and "static" functions that + * are used to perform the actual filtering in interleaved or de-interleaved + * mode. + * + * @tparam fptype Floating point type to use for storing pixel elements. SIMD + * types can be used: in this case each element may hold a whole pixel. + * @tparam fptypeatom The atomic type the "fptype" consists of. + */ + +template< class fptype, class fptypeatom > +class CImageResizerFilterStep +{ + AVIR_NOCTOR( CImageResizerFilterStep ); + +public: + bool IsUpsample; ///< "True" if this step is an upsampling step, "false" + ///< if downsampling step. Should be set to "false" if ResampleFactor + ///< equals 0. + ///< + int ResampleFactor; ///< Resample factor (>=1). If 0, this is a resizing + ///< step. This value should be >1 if IsUpsample equals "true". + ///< + CBuffer< fptype > Flt; ///< Filter to use at this step. + ///< + CFltBuffer FltOrig; ///< Originally-designed filter. This buffer may not + ///< be assigned. Assigned by filters that precede the resizing step + ///< if such filter is planned to be embedded into the interpolation + ///< filter as "external" filter. If IsUpsample=true and this filter + ///< buffer is not empty, the upsampling step will not itself apply + ///< any filtering over upsampled input scanline. + ///< + double DCGain; ///< DC gain which was applied to the filter. Not defined + ///< if ResampleFactor = 0. + ///< + int FltLatency; ///< Filter's latency (group delay, shift) in pixels. + ///< + const CImageResizerVars* Vars; ///< Image resizing-related variables. + ///< + int InLen; ///< Input scanline's length in pixels. + ///< + int InBuf; ///< Input buffer index, 0 or 1. + ///< + int InPrefix; ///< Required input prefix pixels. These prefix pixels will + ///< be filled with source scanline's first pixel value. If IsUpsample + ///< is "true", this is the additional number of times the first pixel + ///< will be filtered before processing scanline, this number is also + ///< reflected in the OutPrefix. + ///< + int InSuffix; ///< Required input suffix pixels. These suffix pixels will + ///< be filled with source scanline's last pixel value. If IsUpsample + ///< is "true", this is the additional number of times the last pixel + ///< will be filtered before processing scanline, this number is also + ///< reflected in the OutSuffix. + ///< + int InElIncr; ///< Pixel element increment within the input buffer, used + ///< during de-interleaved processing: in this case each image's + ///< channel is stored independently, InElIncr elements apart. + ///< + int OutLen; ///< Length of the resulting scanline. + ///< + int OutBuf; ///< Output buffer index. 0 or 1; 2 for the last step. + ///< + int OutPrefix; ///< Required output prefix pixels. These prefix pixels + ///< will not be pre-filled with any values. Value is valid only if + ///< IsUpsample equals "true". + ///< + int OutSuffix; ///< Required input suffix pixels. These suffix pixels will + ///< not be pre-filled with any values. Value is valid only if + ///< IsUpsample equals "true". + ///< + int OutElIncr; ///< Pixel element increment within the output buffer, used + ///< during de-interleaved processing. Equals to the InBufElIncr of + ///< the next step. + ///< + CBuffer< fptype > PrefixDC; ///< DC component fluctuations added at the + ///< start of the resulting scanline, used when IsUpsample equals + ///< "true". + ///< + CBuffer< fptype > SuffixDC; ///< DC component fluctuations added at the + ///< end of the resulting scanline, used when IsUpsample equals + ///< "true". + ///< + int EdgePixelCount; ///< The number of edge pixels added. Affects the + ///< initial position within the input scanline, used to produce edge + ///< pixels. This variable is used and should be defined when + ///< IsUpsample=false and ResampleFactor>0. When assigning this + ///< variable it is also necessary to update InPrefix, OutLen and + ///< Vars.o variables. + ///< + static const int EdgePixelCountDef = 3; ///< The default number of pixels + ///< additionally produced at scanline edges during filtering. This is + ///< required to reduce edge artifacts. + ///< + + /** + * @brief Resizing position structure. + * + * Structure holds resizing position and pointer to fractional delay + * filter. + */ + + struct CResizePos + { + int SrcPosInt; ///< Source scanline position. + ///< + int fti; ///< Fractional delay filter index. + ///< + const fptype* ftp; ///< Fractional delay filter pointer. + ///< + fptypeatom x; ///< Interpolation coefficient between delay filters. + ///< + int SrcOffs; ///< Source scanline offset. + ///< + int fl; ///< Filter length to use, applies to doResize2() only. + ///< + }; + + /** + * @brief Resizing positions buffer class. + * + * This class combines buffer together with variables that define resizing + * stepping. + */ + + class CRPosBuf : public CBuffer< CResizePos > + { + public: + double k; ///< Resizing step. + ///< + double o; ///< Resizing offset. + ///< + int FracCount; ///< The number of fractional delay filters in a filter + ///< bank used together with this buffer. + ///< + }; + + /** + * @brief Resizing positions buffer array class. + * + * This class combines structure array of the CRPosBuf class objects with + * the function that locates or creates buffer with the required resizing + * stepping. + */ + + class CRPosBufArray : public CStructArray< CRPosBuf > + { + public: + using CStructArray< CRPosBuf > :: add; + using CStructArray< CRPosBuf > :: getItemCount; + + /** + * Function returns the resizing positions buffer with the required + * stepping. If no such buffer exists, it is created. + * + * @param k Resizing step. + * @param o Resizing offset. + * @param FracCount The number of fractional delay filters in a filter + * bank used together with this buffer. + * @return Reference to the CRPosBuf object. + */ + + CRPosBuf& getRPosBuf( const double k, const double o, + const int FracCount ) + { + int i; + + for( i = 0; i < getItemCount(); i++ ) + { + CRPosBuf& Buf = (*this)[ i ]; + + if( Buf.k == k && Buf.o == o && Buf.FracCount == FracCount ) + { + return( Buf ); + } + } + + CRPosBuf& NewBuf = add(); + NewBuf.k = k; + NewBuf.o = o; + NewBuf.FracCount = FracCount; + + return( NewBuf ); + } + }; + + CRPosBuf* RPosBuf; ///< Resizing positions buffer. Used when + ///< ResampleFactor equals 0 (resizing step). + ///< + CDSPFracFilterBankLin< fptype >* FltBank; ///< Filter bank in use by *this + ///< resizing step. + ///< + + CImageResizerFilterStep() + { + } +}; + +/** + * @brief Interleaved filtering steps implementation class. + * + * This class implements scanline filtering functions in interleaved mode. + * This means that each pixel is processed independently, not in groups. + * + * @tparam fptype Floating point type to use for storing pixel elements. SIMD + * types can be used: in this case each element may hold a whole pixel. + * @tparam fptypeatom The atomic type the "fptype" consists of. + */ + +template< class fptype, class fptypeatom > +class CImageResizerFilterStepINL : + public CImageResizerFilterStep< fptype, fptypeatom > +{ +public: + using CImageResizerFilterStep< fptype, fptypeatom > :: IsUpsample; + using CImageResizerFilterStep< fptype, fptypeatom > :: ResampleFactor; + using CImageResizerFilterStep< fptype, fptypeatom > :: Flt; + using CImageResizerFilterStep< fptype, fptypeatom > :: FltOrig; + using CImageResizerFilterStep< fptype, fptypeatom > :: FltLatency; + using CImageResizerFilterStep< fptype, fptypeatom > :: Vars; + using CImageResizerFilterStep< fptype, fptypeatom > :: InLen; + using CImageResizerFilterStep< fptype, fptypeatom > :: InPrefix; + using CImageResizerFilterStep< fptype, fptypeatom > :: InSuffix; + using CImageResizerFilterStep< fptype, fptypeatom > :: OutLen; + using CImageResizerFilterStep< fptype, fptypeatom > :: OutPrefix; + using CImageResizerFilterStep< fptype, fptypeatom > :: OutSuffix; + using CImageResizerFilterStep< fptype, fptypeatom > :: PrefixDC; + using CImageResizerFilterStep< fptype, fptypeatom > :: SuffixDC; + using CImageResizerFilterStep< fptype, fptypeatom > :: RPosBuf; + using CImageResizerFilterStep< fptype, fptypeatom > :: FltBank; + using CImageResizerFilterStep< fptype, fptypeatom > :: EdgePixelCount; + + /** + * Function performs "packing" of a scanline, and type conversion. + * Scanline, depending on the "fptype" can be potentially stored as a + * packed SIMD values having a certain atomic type. If required, the sRGB + * gamma correction is applied. + * + * @param ip Input scanline. + * @param op0 Output scanline. + * @param l0 The number of pixels to "pack". + */ + + template< class Tin > + void packScanline( const Tin* ip, fptype* const op0, const int l0 ) const + { + const int ElCount = Vars -> ElCount; + const int ElCountIO = Vars -> ElCountIO; + fptype* op = op0; + int l = l0; + + if( !Vars -> UseSRGBGamma ) + { + if( ElCountIO == 1 ) + { + while( l > 0 ) + { + fptypeatom* v = (fptypeatom*) op; + v[ 0 ] = (fptypeatom) ip[ 0 ]; + op += ElCount; + ip++; + l--; + } + } + else + if( ElCountIO == 4 ) + { + while( l > 0 ) + { + fptypeatom* v = (fptypeatom*) op; + v[ 0 ] = (fptypeatom) ip[ 0 ]; + v[ 1 ] = (fptypeatom) ip[ 1 ]; + v[ 2 ] = (fptypeatom) ip[ 2 ]; + v[ 3 ] = (fptypeatom) ip[ 3 ]; + op += ElCount; + ip += 4; + l--; + } + } + else + if( ElCountIO == 3 ) + { + while( l > 0 ) + { + fptypeatom* v = (fptypeatom*) op; + v[ 0 ] = (fptypeatom) ip[ 0 ]; + v[ 1 ] = (fptypeatom) ip[ 1 ]; + v[ 2 ] = (fptypeatom) ip[ 2 ]; + op += ElCount; + ip += 3; + l--; + } + } + else + if( ElCountIO == 2 ) + { + while( l > 0 ) + { + fptypeatom* v = (fptypeatom*) op; + v[ 0 ] = (fptypeatom) ip[ 0 ]; + v[ 1 ] = (fptypeatom) ip[ 1 ]; + op += ElCount; + ip += 2; + l--; + } + } + } + else + { + const fptypeatom gm = (fptypeatom) Vars -> InGammaMult; + + if( ElCountIO == 1 ) + { + while( l > 0 ) + { + fptypeatom* v = (fptypeatom*) op; + v[ 0 ] = convertSRGB2Lin( (fptypeatom) ip[ 0 ] * gm ); + op += ElCount; + ip++; + l--; + } + } + else + if( ElCountIO == 4 ) + { + while( l > 0 ) + { + fptypeatom* v = (fptypeatom*) op; + v[ 0 ] = convertSRGB2Lin( (fptypeatom) ip[ 0 ] * gm ); + v[ 1 ] = convertSRGB2Lin( (fptypeatom) ip[ 1 ] * gm ); + v[ 2 ] = convertSRGB2Lin( (fptypeatom) ip[ 2 ] * gm ); + v[ 3 ] = convertSRGB2Lin( (fptypeatom) ip[ 3 ] * gm ); + op += ElCount; + ip += 4; + l--; + } + } + else + if( ElCountIO == 3 ) + { + while( l > 0 ) + { + fptypeatom* v = (fptypeatom*) op; + v[ 0 ] = convertSRGB2Lin( (fptypeatom) ip[ 0 ] * gm ); + v[ 1 ] = convertSRGB2Lin( (fptypeatom) ip[ 1 ] * gm ); + v[ 2 ] = convertSRGB2Lin( (fptypeatom) ip[ 2 ] * gm ); + op += ElCount; + ip += 3; + l--; + } + } + else + if( ElCountIO == 2 ) + { + while( l > 0 ) + { + fptypeatom* v = (fptypeatom*) op; + v[ 0 ] = convertSRGB2Lin( (fptypeatom) ip[ 0 ] * gm ); + v[ 1 ] = convertSRGB2Lin( (fptypeatom) ip[ 1 ] * gm ); + op += ElCount; + ip += 2; + l--; + } + } + } + + const int ZeroCount = ElCount * Vars -> fppack - ElCountIO; + op = (fptype*) ( (fptypeatom*) op0 + ElCountIO ); + l = l0; + + if( ZeroCount == 1 ) + { + while( l > 0 ) + { + fptypeatom* v = (fptypeatom*) op; + v[ 0 ] = (fptypeatom) 0; + op += ElCount; + l--; + } + } + else + if( ZeroCount == 2 ) + { + while( l > 0 ) + { + fptypeatom* v = (fptypeatom*) op; + v[ 0 ] = (fptypeatom) 0; + v[ 1 ] = (fptypeatom) 0; + op += ElCount; + l--; + } + } + else + if( ZeroCount == 3 ) + { + while( l > 0 ) + { + fptypeatom* v = (fptypeatom*) op; + v[ 0 ] = (fptypeatom) 0; + v[ 1 ] = (fptypeatom) 0; + v[ 2 ] = (fptypeatom) 0; + op += ElCount; + l--; + } + } + } + + /** + * Function applies Linear to sRGB gamma correction to the specified + * scanline. + * + * @param p Scanline. + * @param l The number of pixels to de-linearize. + * @param Vars0 Image resizing-related variables. + */ + + static void applySRGBGamma( fptype* p, int l, + const CImageResizerVars& Vars0 ) + { + const int ElCount = Vars0.ElCount; + const int ElCountIO = Vars0.ElCountIO; + const fptypeatom gm = (fptypeatom) Vars0.OutGammaMult; + + if( ElCountIO == 1 ) + { + while( l > 0 ) + { + fptypeatom* v = (fptypeatom*) p; + v[ 0 ] = convertLin2SRGB( v[ 0 ]) * gm; + p += ElCount; + l--; + } + } + else + if( ElCountIO == 4 ) + { + while( l > 0 ) + { + fptypeatom* v = (fptypeatom*) p; + v[ 0 ] = convertLin2SRGB( v[ 0 ]) * gm; + v[ 1 ] = convertLin2SRGB( v[ 1 ]) * gm; + v[ 2 ] = convertLin2SRGB( v[ 2 ]) * gm; + v[ 3 ] = convertLin2SRGB( v[ 3 ]) * gm; + p += ElCount; + l--; + } + } + else + if( ElCountIO == 3 ) + { + while( l > 0 ) + { + fptypeatom* v = (fptypeatom*) p; + v[ 0 ] = convertLin2SRGB( v[ 0 ]) * gm; + v[ 1 ] = convertLin2SRGB( v[ 1 ]) * gm; + v[ 2 ] = convertLin2SRGB( v[ 2 ]) * gm; + p += ElCount; + l--; + } + } + else + if( ElCountIO == 2 ) + { + while( l > 0 ) + { + fptypeatom* v = (fptypeatom*) p; + v[ 0 ] = convertLin2SRGB( v[ 0 ]) * gm; + v[ 1 ] = convertLin2SRGB( v[ 1 ]) * gm; + p += ElCount; + l--; + } + } + } + + /** + * Function converts vertical scanline to horizontal scanline. This + * function is called by the image resizer when image is resized + * vertically. This means that the vertical scanline is stored in the + * same format produced by the packScanline() and maintained by other + * filtering functions. + * + * @param ip Input vertical scanline. + * @param op Output buffer (temporary buffer used during resizing). + * @param SrcLen The number of pixels in the input scanline, also used to + * calculate input buffer increment. + * @param SrcIncr Input buffer increment to the next vertical pixel. + */ + + void convertVtoH( const fptype* ip, fptype* op, const int SrcLen, + const int SrcIncr ) const + { + const int ElCount = Vars -> ElCount; + int j; + + if( ElCount == 1 ) + { + for( j = 0; j < SrcLen; j++ ) + { + op[ 0 ] = ip[ 0 ]; + ip += SrcIncr; + op++; + } + } + else + if( ElCount == 4 ) + { + for( j = 0; j < SrcLen; j++ ) + { + op[ 0 ] = ip[ 0 ]; + op[ 1 ] = ip[ 1 ]; + op[ 2 ] = ip[ 2 ]; + op[ 3 ] = ip[ 3 ]; + ip += SrcIncr; + op += 4; + } + } + else + if( ElCount == 3 ) + { + for( j = 0; j < SrcLen; j++ ) + { + op[ 0 ] = ip[ 0 ]; + op[ 1 ] = ip[ 1 ]; + op[ 2 ] = ip[ 2 ]; + ip += SrcIncr; + op += 3; + } + } + else + if( ElCount == 2 ) + { + for( j = 0; j < SrcLen; j++ ) + { + op[ 0 ] = ip[ 0 ]; + op[ 1 ] = ip[ 1 ]; + ip += SrcIncr; + op += 2; + } + } + } + + /** + * Function performs "unpacking" of a scanline and type conversion + * (truncation is used when floating point is converted to integer). + * Scanline, depending on the "fptype" can be potentially stored as a + * packed SIMD values having a certain atomic type. The unpacking function + * assumes that scanline is stored in the style produced by the + * packScanline() function. + * + * @param ip Input scanline. + * @param op Output scanline. + * @param l The number of pixels to "unpack". + * @param Vars0 Image resizing-related variables. + */ + + template< class Tout > + static void unpackScanline( const fptype* ip, Tout* op, int l, + const CImageResizerVars& Vars0 ) + { + const int ElCount = Vars0.ElCount; + const int ElCountIO = Vars0.ElCountIO; + + if( ElCountIO == 1 ) + { + while( l > 0 ) + { + const fptypeatom* v = (const fptypeatom*) ip; + op[ 0 ] = (Tout) v[ 0 ]; + ip += ElCount; + op++; + l--; + } + } + else + if( ElCountIO == 4 ) + { + while( l > 0 ) + { + const fptypeatom* v = (const fptypeatom*) ip; + op[ 0 ] = (Tout) v[ 0 ]; + op[ 1 ] = (Tout) v[ 1 ]; + op[ 2 ] = (Tout) v[ 2 ]; + op[ 3 ] = (Tout) v[ 3 ]; + ip += ElCount; + op += 4; + l--; + } + } + else + if( ElCountIO == 3 ) + { + while( l > 0 ) + { + const fptypeatom* v = (const fptypeatom*) ip; + op[ 0 ] = (Tout) v[ 0 ]; + op[ 1 ] = (Tout) v[ 1 ]; + op[ 2 ] = (Tout) v[ 2 ]; + ip += ElCount; + op += 3; + l--; + } + } + else + if( ElCountIO == 2 ) + { + while( l > 0 ) + { + const fptypeatom* v = (const fptypeatom*) ip; + op[ 0 ] = (Tout) v[ 0 ]; + op[ 1 ] = (Tout) v[ 1 ]; + ip += ElCount; + op += 2; + l--; + } + } + } + + /** + * Function calculates scanline's DC gain for each channel, further used + * to "unbias" the scanline. + * + * @param p Source scanline. + * @param SrcLen Source scanline's length. + * @param[out] ElBiases Resuling biases. + */ + + void calcScanlineBias( const fptype* p, const int SrcLen, + fptype* const ElBiases ) const + { + const int ElCount = Vars -> ElCount; + int l = SrcLen; + + if( ElCount == 1 ) + { + fptype b0 = (fptype) 0; + + while( l > 0 ) + { + b0 += p[ 0 ]; + p++; + l--; + } + + ElBiases[ 0 ] = b0 / (fptype) SrcLen; + } + else + if( ElCount == 4 ) + { + fptype b0 = (fptype) 0; + fptype b1 = (fptype) 0; + fptype b2 = (fptype) 0; + fptype b3 = (fptype) 0; + + while( l > 0 ) + { + b0 += p[ 0 ]; + b1 += p[ 1 ]; + b2 += p[ 2 ]; + b3 += p[ 3 ]; + p += 4; + l--; + } + + ElBiases[ 0 ] = b0 / (fptype) SrcLen; + ElBiases[ 1 ] = b1 / (fptype) SrcLen; + ElBiases[ 2 ] = b2 / (fptype) SrcLen; + ElBiases[ 3 ] = b3 / (fptype) SrcLen; + } + else + if( ElCount == 3 ) + { + fptype b0 = (fptype) 0; + fptype b1 = (fptype) 0; + fptype b2 = (fptype) 0; + + while( l > 0 ) + { + b0 += p[ 0 ]; + b1 += p[ 1 ]; + b2 += p[ 2 ]; + p += 3; + l--; + } + + ElBiases[ 0 ] = b0 / (fptype) SrcLen; + ElBiases[ 1 ] = b1 / (fptype) SrcLen; + ElBiases[ 2 ] = b2 / (fptype) SrcLen; + } + else + if( ElCount == 2 ) + { + fptype b0 = (fptype) 0; + fptype b1 = (fptype) 0; + + while( l > 0 ) + { + b0 += p[ 0 ]; + b1 += p[ 1 ]; + p += 2; + l--; + } + + ElBiases[ 0 ] = b0 / (fptype) SrcLen; + ElBiases[ 1 ] = b1 / (fptype) SrcLen; + } + } + + /** + * Function applies "unbiasing" to the scanline, by subtracting the + * previously calculated bias (DC gain) values. + * + * @param p Scanline. + * @param l Scanline's length. + * @param ElBiases Biases to subtract, for each channel. + */ + + void unbiasScanline( fptype* p, int l, + const fptype* const ElBiases ) const + { + const int ElCount = Vars -> ElCount; + + if( ElCount == 1 ) + { + const fptype b0 = ElBiases[ 0 ]; + + while( l > 0 ) + { + p[ 0 ] -= b0; + p++; + l--; + } + } + else + if( ElCount == 4 ) + { + const fptype b0 = ElBiases[ 0 ]; + const fptype b1 = ElBiases[ 1 ]; + const fptype b2 = ElBiases[ 2 ]; + const fptype b3 = ElBiases[ 3 ]; + + while( l > 0 ) + { + p[ 0 ] -= b0; + p[ 1 ] -= b1; + p[ 2 ] -= b2; + p[ 3 ] -= b3; + p += 4; + l--; + } + } + else + if( ElCount == 3 ) + { + const fptype b0 = ElBiases[ 0 ]; + const fptype b1 = ElBiases[ 1 ]; + const fptype b2 = ElBiases[ 2 ]; + + while( l > 0 ) + { + p[ 0 ] -= b0; + p[ 1 ] -= b1; + p[ 2 ] -= b2; + p += 3; + l--; + } + } + else + if( ElCount == 2 ) + { + const fptype b0 = ElBiases[ 0 ]; + const fptype b1 = ElBiases[ 1 ]; + + while( l > 0 ) + { + p[ 0 ] -= b0; + p[ 1 ] -= b1; + p += 2; + l--; + } + } + } + + /** + * Function prepares input scanline buffer for *this filtering step. + * Left- and right-most pixels are replicated to make sure no buffer + * overrun happens. Such approach also allows to bypass any pointer + * range checks. + * + * @param Src Source buffer. + */ + + void prepareInBuf( fptype* Src ) const + { + if( IsUpsample || InPrefix + InSuffix == 0 ) + { + return; + } + + const int ElCount = Vars -> ElCount; + replicateArray( Src, ElCount, Src - ElCount, InPrefix, -ElCount ); + + Src += ( InLen - 1 ) * ElCount; + replicateArray( Src, ElCount, Src + ElCount, InSuffix, ElCount ); + } + + /** + * Function peforms scanline upsampling with filtering. + * + * @param Src Source scanline buffer (length = this -> InLen). Source + * scanline increment will be equal to ElCount. + * @param Dst Destination scanline buffer. + */ + + void doUpsample( const fptype* const Src, fptype* const Dst ) const + { + const int ElCount = Vars -> ElCount; + fptype* op0 = &Dst[ -OutPrefix * ElCount ]; + memset( op0, 0, ( OutPrefix + OutLen + OutSuffix ) * ElCount * + sizeof( fptype )); + + const fptype* ip = Src; + const int opstep = ElCount * ResampleFactor; + int l; + + if( FltOrig.getCapacity() > 0 ) + { + // Do not perform filtering, only upsample. + + op0 += ( OutPrefix % ResampleFactor ) * ElCount; + l = OutPrefix / ResampleFactor; + + if( ElCount == 1 ) + { + while( l > 0 ) + { + op0[ 0 ] = ip[ 0 ]; + op0 += opstep; + l--; + } + + l = InLen - 1; + + while( l > 0 ) + { + op0[ 0 ] = ip[ 0 ]; + op0 += opstep; + ip += ElCount; + l--; + } + + l = OutSuffix / ResampleFactor; + + while( l >= 0 ) + { + op0[ 0 ] = ip[ 0 ]; + op0 += opstep; + l--; + } + } + else + if( ElCount == 4 ) + { + while( l > 0 ) + { + op0[ 0 ] = ip[ 0 ]; + op0[ 1 ] = ip[ 1 ]; + op0[ 2 ] = ip[ 2 ]; + op0[ 3 ] = ip[ 3 ]; + op0 += opstep; + l--; + } + + l = InLen - 1; + + while( l > 0 ) + { + op0[ 0 ] = ip[ 0 ]; + op0[ 1 ] = ip[ 1 ]; + op0[ 2 ] = ip[ 2 ]; + op0[ 3 ] = ip[ 3 ]; + op0 += opstep; + ip += ElCount; + l--; + } + + l = OutSuffix / ResampleFactor; + + while( l >= 0 ) + { + op0[ 0 ] = ip[ 0 ]; + op0[ 1 ] = ip[ 1 ]; + op0[ 2 ] = ip[ 2 ]; + op0[ 3 ] = ip[ 3 ]; + op0 += opstep; + l--; + } + } + else + if( ElCount == 3 ) + { + while( l > 0 ) + { + op0[ 0 ] = ip[ 0 ]; + op0[ 1 ] = ip[ 1 ]; + op0[ 2 ] = ip[ 2 ]; + op0 += opstep; + l--; + } + + l = InLen - 1; + + while( l > 0 ) + { + op0[ 0 ] = ip[ 0 ]; + op0[ 1 ] = ip[ 1 ]; + op0[ 2 ] = ip[ 2 ]; + op0 += opstep; + ip += ElCount; + l--; + } + + l = OutSuffix / ResampleFactor; + + while( l >= 0 ) + { + op0[ 0 ] = ip[ 0 ]; + op0[ 1 ] = ip[ 1 ]; + op0[ 2 ] = ip[ 2 ]; + op0 += opstep; + l--; + } + } + else + if( ElCount == 2 ) + { + while( l > 0 ) + { + op0[ 0 ] = ip[ 0 ]; + op0[ 1 ] = ip[ 1 ]; + op0 += opstep; + l--; + } + + l = InLen - 1; + + while( l > 0 ) + { + op0[ 0 ] = ip[ 0 ]; + op0[ 1 ] = ip[ 1 ]; + op0 += opstep; + ip += ElCount; + l--; + } + + l = OutSuffix / ResampleFactor; + + while( l >= 0 ) + { + op0[ 0 ] = ip[ 0 ]; + op0[ 1 ] = ip[ 1 ]; + op0 += opstep; + l--; + } + } + + return; + } + + const fptype* const f = Flt; + const int flen = Flt.getCapacity(); + fptype* op; + int i; + + if( ElCount == 1 ) + { + l = InPrefix; + + while( l > 0 ) + { + op = op0; + + for( i = 0; i < flen; i++ ) + { + op[ i ] += f[ i ] * ip[ 0 ]; + } + + op0 += opstep; + l--; + } + + l = InLen - 1; + + while( l > 0 ) + { + op = op0; + + for( i = 0; i < flen; i++ ) + { + op[ i ] += f[ i ] * ip[ 0 ]; + } + + ip += ElCount; + op0 += opstep; + l--; + } + + l = InSuffix; + + while( l >= 0 ) + { + op = op0; + + for( i = 0; i < flen; i++ ) + { + op[ i ] += f[ i ] * ip[ 0 ]; + } + + op0 += opstep; + l--; + } + } + else + if( ElCount == 4 ) + { + l = InPrefix; + + while( l > 0 ) + { + op = op0; + + for( i = 0; i < flen; i++ ) + { + op[ 0 ] += f[ i ] * ip[ 0 ]; + op[ 1 ] += f[ i ] * ip[ 1 ]; + op[ 2 ] += f[ i ] * ip[ 2 ]; + op[ 3 ] += f[ i ] * ip[ 3 ]; + op += 4; + } + + op0 += opstep; + l--; + } + + l = InLen - 1; + + while( l > 0 ) + { + op = op0; + + for( i = 0; i < flen; i++ ) + { + op[ 0 ] += f[ i ] * ip[ 0 ]; + op[ 1 ] += f[ i ] * ip[ 1 ]; + op[ 2 ] += f[ i ] * ip[ 2 ]; + op[ 3 ] += f[ i ] * ip[ 3 ]; + op += 4; + } + + ip += ElCount; + op0 += opstep; + l--; + } + + l = InSuffix; + + while( l >= 0 ) + { + op = op0; + + for( i = 0; i < flen; i++ ) + { + op[ 0 ] += f[ i ] * ip[ 0 ]; + op[ 1 ] += f[ i ] * ip[ 1 ]; + op[ 2 ] += f[ i ] * ip[ 2 ]; + op[ 3 ] += f[ i ] * ip[ 3 ]; + op += 4; + } + + op0 += opstep; + l--; + } + } + else + if( ElCount == 3 ) + { + l = InPrefix; + + while( l > 0 ) + { + op = op0; + + for( i = 0; i < flen; i++ ) + { + op[ 0 ] += f[ i ] * ip[ 0 ]; + op[ 1 ] += f[ i ] * ip[ 1 ]; + op[ 2 ] += f[ i ] * ip[ 2 ]; + op += 3; + } + + op0 += opstep; + l--; + } + + l = InLen - 1; + + while( l > 0 ) + { + op = op0; + + for( i = 0; i < flen; i++ ) + { + op[ 0 ] += f[ i ] * ip[ 0 ]; + op[ 1 ] += f[ i ] * ip[ 1 ]; + op[ 2 ] += f[ i ] * ip[ 2 ]; + op += 3; + } + + ip += ElCount; + op0 += opstep; + l--; + } + + l = InSuffix; + + while( l >= 0 ) + { + op = op0; + + for( i = 0; i < flen; i++ ) + { + op[ 0 ] += f[ i ] * ip[ 0 ]; + op[ 1 ] += f[ i ] * ip[ 1 ]; + op[ 2 ] += f[ i ] * ip[ 2 ]; + op += 3; + } + + op0 += opstep; + l--; + } + } + else + if( ElCount == 2 ) + { + l = InPrefix; + + while( l > 0 ) + { + op = op0; + + for( i = 0; i < flen; i++ ) + { + op[ 0 ] += f[ i ] * ip[ 0 ]; + op[ 1 ] += f[ i ] * ip[ 1 ]; + op += 2; + } + + op0 += opstep; + l--; + } + + l = InLen - 1; + + while( l > 0 ) + { + op = op0; + + for( i = 0; i < flen; i++ ) + { + op[ 0 ] += f[ i ] * ip[ 0 ]; + op[ 1 ] += f[ i ] * ip[ 1 ]; + op += 2; + } + + ip += ElCount; + op0 += opstep; + l--; + } + + l = InSuffix; + + while( l >= 0 ) + { + op = op0; + + for( i = 0; i < flen; i++ ) + { + op[ 0 ] += f[ i ] * ip[ 0 ]; + op[ 1 ] += f[ i ] * ip[ 1 ]; + op += 2; + } + + op0 += opstep; + l--; + } + } + + op = op0; + const fptype* dc = SuffixDC; + l = SuffixDC.getCapacity(); + + if( ElCount == 1 ) + { + for( i = 0; i < l; i++ ) + { + op[ i ] += ip[ 0 ] * dc[ i ]; + } + } + else + if( ElCount == 4 ) + { + while( l > 0 ) + { + op[ 0 ] += ip[ 0 ] * dc[ 0 ]; + op[ 1 ] += ip[ 1 ] * dc[ 0 ]; + op[ 2 ] += ip[ 2 ] * dc[ 0 ]; + op[ 3 ] += ip[ 3 ] * dc[ 0 ]; + dc++; + op += 4; + l--; + } + } + else + if( ElCount == 3 ) + { + while( l > 0 ) + { + op[ 0 ] += ip[ 0 ] * dc[ 0 ]; + op[ 1 ] += ip[ 1 ] * dc[ 0 ]; + op[ 2 ] += ip[ 2 ] * dc[ 0 ]; + dc++; + op += 3; + l--; + } + } + else + if( ElCount == 2 ) + { + while( l > 0 ) + { + op[ 0 ] += ip[ 0 ] * dc[ 0 ]; + op[ 1 ] += ip[ 1 ] * dc[ 0 ]; + dc++; + op += 2; + l--; + } + } + + ip = Src; + op = Dst - InPrefix * opstep; + dc = PrefixDC; + l = PrefixDC.getCapacity(); + + if( ElCount == 1 ) + { + for( i = 0; i < l; i++ ) + { + op[ i ] += ip[ 0 ] * dc[ i ]; + } + } + else + if( ElCount == 4 ) + { + while( l > 0 ) + { + op[ 0 ] += ip[ 0 ] * dc[ 0 ]; + op[ 1 ] += ip[ 1 ] * dc[ 0 ]; + op[ 2 ] += ip[ 2 ] * dc[ 0 ]; + op[ 3 ] += ip[ 3 ] * dc[ 0 ]; + dc++; + op += 4; + l--; + } + } + else + if( ElCount == 3 ) + { + while( l > 0 ) + { + op[ 0 ] += ip[ 0 ] * dc[ 0 ]; + op[ 1 ] += ip[ 1 ] * dc[ 0 ]; + op[ 2 ] += ip[ 2 ] * dc[ 0 ]; + dc++; + op += 3; + l--; + } + } + else + if( ElCount == 2 ) + { + while( l > 0 ) + { + op[ 0 ] += ip[ 0 ] * dc[ 0 ]; + op[ 1 ] += ip[ 1 ] * dc[ 0 ]; + dc++; + op += 2; + l--; + } + } + } + + /** + * Function peforms scanline filtering with optional downsampling. + * Function makes use of the symmetry of the filter. + * + * @param Src Source scanline buffer (length = this -> InLen). Source + * scanline increment will be equal to ElCount. + * @param Dst Destination scanline buffer. + * @param DstIncr Destination scanline buffer increment, used for + * horizontal or vertical scanline stepping. + */ + + void doFilter( const fptype* const Src, fptype* Dst, + const int DstIncr ) const + { + const int ElCount = Vars -> ElCount; + const fptype* const f = &Flt[ FltLatency ]; + const int flen = FltLatency + 1; + const int ipstep = ElCount * ResampleFactor; + const fptype* ip = Src - EdgePixelCount * ipstep; + const fptype* ip1; + const fptype* ip2; + int l = OutLen; + int i; + + if( ElCount == 1 ) + { + while( l > 0 ) + { + fptype s = f[ 0 ] * ip[ 0 ]; + ip1 = ip; + ip2 = ip; + + for( i = 1; i < flen; i++ ) + { + ip1++; + ip2--; + s += f[ i ] * ( ip1[ 0 ] + ip2[ 0 ]); + } + + Dst[ 0 ] = s; + Dst += DstIncr; + ip += ipstep; + l--; + } + } + else + if( ElCount == 4 ) + { + while( l > 0 ) + { + fptype s1 = f[ 0 ] * ip[ 0 ]; + fptype s2 = f[ 0 ] * ip[ 1 ]; + fptype s3 = f[ 0 ] * ip[ 2 ]; + fptype s4 = f[ 0 ] * ip[ 3 ]; + ip1 = ip; + ip2 = ip; + + for( i = 1; i < flen; i++ ) + { + ip1 += 4; + ip2 -= 4; + s1 += f[ i ] * ( ip1[ 0 ] + ip2[ 0 ]); + s2 += f[ i ] * ( ip1[ 1 ] + ip2[ 1 ]); + s3 += f[ i ] * ( ip1[ 2 ] + ip2[ 2 ]); + s4 += f[ i ] * ( ip1[ 3 ] + ip2[ 3 ]); + } + + Dst[ 0 ] = s1; + Dst[ 1 ] = s2; + Dst[ 2 ] = s3; + Dst[ 3 ] = s4; + Dst += DstIncr; + ip += ipstep; + l--; + } + } + else + if( ElCount == 3 ) + { + while( l > 0 ) + { + fptype s1 = f[ 0 ] * ip[ 0 ]; + fptype s2 = f[ 0 ] * ip[ 1 ]; + fptype s3 = f[ 0 ] * ip[ 2 ]; + ip1 = ip; + ip2 = ip; + + for( i = 1; i < flen; i++ ) + { + ip1 += 3; + ip2 -= 3; + s1 += f[ i ] * ( ip1[ 0 ] + ip2[ 0 ]); + s2 += f[ i ] * ( ip1[ 1 ] + ip2[ 1 ]); + s3 += f[ i ] * ( ip1[ 2 ] + ip2[ 2 ]); + } + + Dst[ 0 ] = s1; + Dst[ 1 ] = s2; + Dst[ 2 ] = s3; + Dst += DstIncr; + ip += ipstep; + l--; + } + } + else + if( ElCount == 2 ) + { + while( l > 0 ) + { + fptype s1 = f[ 0 ] * ip[ 0 ]; + fptype s2 = f[ 0 ] * ip[ 1 ]; + ip1 = ip; + ip2 = ip; + + for( i = 1; i < flen; i++ ) + { + ip1 += 2; + ip2 -= 2; + s1 += f[ i ] * ( ip1[ 0 ] + ip2[ 0 ]); + s2 += f[ i ] * ( ip1[ 1 ] + ip2[ 1 ]); + } + + Dst[ 0 ] = s1; + Dst[ 1 ] = s2; + Dst += DstIncr; + ip += ipstep; + l--; + } + } + } + + /** + * Function performs resizing of a single scanline. This function does + * not "know" about the length of the source scanline buffer. This buffer + * should be padded with enough pixels so that ( SrcPos - FilterLenD2 ) is + * always >= 0 and ( SrcPos + ( DstLineLen - 1 ) * k + FilterLenD2 + 1 ) + * does not exceed source scanline's buffer length. SrcLine's increment is + * assumed to be equal to ElCount. + * + * @param SrcLine Source scanline buffer. + * @param DstLine Destination (resized) scanline buffer. + * @param DstLineIncr Destination scanline position increment, used for + * horizontal or vertical scanline stepping. + * @param ElBiases Bias values to add to the resulting scanline. + * @param xx Temporary buffer, of size FltBank -> getFilterLen(), must be + * aligned by fpclass :: fpalign. + */ + + void doResize( const fptype* SrcLine, fptype* DstLine, + const int DstLineIncr, const fptype* const ElBiases, + fptype* const ) const + { + const int IntFltLen = FltBank -> getFilterLen(); + const int ElCount = Vars -> ElCount; + const typename CImageResizerFilterStep< fptype, fptypeatom > :: + CResizePos* rpos = &(*RPosBuf)[ 0 ]; + + const typename CImageResizerFilterStep< fptype, fptypeatom > :: + CResizePos* const rpose = rpos + OutLen; + +#define AVIR_RESIZE_PART1 \ + while( rpos < rpose ) \ + { \ + const fptype x = (fptype) rpos -> x; \ + const fptype* const ftp = rpos -> ftp; \ + const fptype* const ftp2 = ftp + IntFltLen; \ + const fptype* Src = SrcLine + rpos -> SrcOffs; \ + int i; + +#define AVIR_RESIZE_PART1nx \ + while( rpos < rpose ) \ + { \ + const fptype* const ftp = rpos -> ftp; \ + const fptype* Src = SrcLine + rpos -> SrcOffs; \ + int i; + +#define AVIR_RESIZE_PART2 \ + DstLine += DstLineIncr; \ + rpos++; \ + } + + if( FltBank -> getOrder() == 1 ) + { + if( ElCount == 1 ) + { + AVIR_RESIZE_PART1 + + fptype sum0 = ElBiases[ 0 ]; + + for( i = 0; i < IntFltLen; i++ ) + { + sum0 += ( ftp[ i ] + ftp2[ i ] * x ) * Src[ i ]; + } + + DstLine[ 0 ] = sum0; + + AVIR_RESIZE_PART2 + } + else + if( ElCount == 4 ) + { + AVIR_RESIZE_PART1 + + fptype sum0 = ElBiases[ 0 ]; + fptype sum1 = ElBiases[ 1 ]; + fptype sum2 = ElBiases[ 2 ]; + fptype sum3 = ElBiases[ 3 ]; + + for( i = 0; i < IntFltLen; i++ ) + { + const fptype xx = ftp[ i ] + ftp2[ i ] * x; + sum0 += xx * Src[ 0 ]; + sum1 += xx * Src[ 1 ]; + sum2 += xx * Src[ 2 ]; + sum3 += xx * Src[ 3 ]; + Src += 4; + } + + DstLine[ 0 ] = sum0; + DstLine[ 1 ] = sum1; + DstLine[ 2 ] = sum2; + DstLine[ 3 ] = sum3; + + AVIR_RESIZE_PART2 + } + else + if( ElCount == 3 ) + { + AVIR_RESIZE_PART1 + + fptype sum0 = ElBiases[ 0 ]; + fptype sum1 = ElBiases[ 1 ]; + fptype sum2 = ElBiases[ 2 ]; + + for( i = 0; i < IntFltLen; i++ ) + { + const fptype xx = ftp[ i ] + ftp2[ i ] * x; + sum0 += xx * Src[ 0 ]; + sum1 += xx * Src[ 1 ]; + sum2 += xx * Src[ 2 ]; + Src += 3; + } + + DstLine[ 0 ] = sum0; + DstLine[ 1 ] = sum1; + DstLine[ 2 ] = sum2; + + AVIR_RESIZE_PART2 + } + else + if( ElCount == 2 ) + { + AVIR_RESIZE_PART1 + + fptype sum0 = ElBiases[ 0 ]; + fptype sum1 = ElBiases[ 1 ]; + + for( i = 0; i < IntFltLen; i++ ) + { + const fptype xx = ftp[ i ] + ftp2[ i ] * x; + sum0 += xx * Src[ 0 ]; + sum1 += xx * Src[ 1 ]; + Src += 2; + } + + DstLine[ 0 ] = sum0; + DstLine[ 1 ] = sum1; + + AVIR_RESIZE_PART2 + } + } + else + { + if( ElCount == 1 ) + { + AVIR_RESIZE_PART1nx + + fptype sum0 = ElBiases[ 0 ]; + + for( i = 0; i < IntFltLen; i++ ) + { + sum0 += ftp[ i ] * Src[ i ]; + } + + DstLine[ 0 ] = sum0; + + AVIR_RESIZE_PART2 + } + else + if( ElCount == 4 ) + { + AVIR_RESIZE_PART1nx + + fptype sum0 = ElBiases[ 0 ]; + fptype sum1 = ElBiases[ 1 ]; + fptype sum2 = ElBiases[ 2 ]; + fptype sum3 = ElBiases[ 3 ]; + + for( i = 0; i < IntFltLen; i++ ) + { + const fptype xx = ftp[ i ]; + sum0 += xx * Src[ 0 ]; + sum1 += xx * Src[ 1 ]; + sum2 += xx * Src[ 2 ]; + sum3 += xx * Src[ 3 ]; + Src += 4; + } + + DstLine[ 0 ] = sum0; + DstLine[ 1 ] = sum1; + DstLine[ 2 ] = sum2; + DstLine[ 3 ] = sum3; + + AVIR_RESIZE_PART2 + } + else + if( ElCount == 3 ) + { + AVIR_RESIZE_PART1nx + + fptype sum0 = ElBiases[ 0 ]; + fptype sum1 = ElBiases[ 1 ]; + fptype sum2 = ElBiases[ 2 ]; + + for( i = 0; i < IntFltLen; i++ ) + { + const fptype xx = ftp[ i ]; + sum0 += xx * Src[ 0 ]; + sum1 += xx * Src[ 1 ]; + sum2 += xx * Src[ 2 ]; + Src += 3; + } + + DstLine[ 0 ] = sum0; + DstLine[ 1 ] = sum1; + DstLine[ 2 ] = sum2; + + AVIR_RESIZE_PART2 + } + else + if( ElCount == 2 ) + { + AVIR_RESIZE_PART1nx + + fptype sum0 = ElBiases[ 0 ]; + fptype sum1 = ElBiases[ 1 ]; + + for( i = 0; i < IntFltLen; i++ ) + { + const fptype xx = ftp[ i ]; + sum0 += xx * Src[ 0 ]; + sum1 += xx * Src[ 1 ]; + Src += 2; + } + + DstLine[ 0 ] = sum0; + DstLine[ 1 ] = sum1; + + AVIR_RESIZE_PART2 + } + } + } +#undef AVIR_RESIZE_PART2 +#undef AVIR_RESIZE_PART1nx +#undef AVIR_RESIZE_PART1 + + /** + * Function performs resizing of a single scanline assuming that the input + * buffer consists of zero-padded elements (2X upsampling without + * filtering). Similar to the doResize() function otherwise. + * + * @param SrcLine Source scanline buffer. + * @param DstLine Destination (resized) scanline buffer. + * @param DstLineIncr Destination scanline position increment, used for + * horizontal or vertical scanline stepping. + * @param ElBiases Bias values to add to the resulting scanline. + * @param xx Temporary buffer, of size FltBank -> getFilterLen(), must be + * aligned by fpclass :: fpalign. + */ + + void doResize2( const fptype* SrcLine, fptype* DstLine, + const int DstLineIncr, const fptype* const ElBiases, + fptype* const ) const + { + const int IntFltLen0 = FltBank -> getFilterLen(); + const int ElCount = Vars -> ElCount; + const typename CImageResizerFilterStep< fptype, fptypeatom > :: + CResizePos* rpos = &(*RPosBuf)[ 0 ]; + + const typename CImageResizerFilterStep< fptype, fptypeatom > :: + CResizePos* const rpose = rpos + OutLen; + +#define AVIR_RESIZE_PART1 \ + while( rpos < rpose ) \ + { \ + const fptype x = (fptype) rpos -> x; \ + const fptype* const ftp = rpos -> ftp; \ + const fptype* const ftp2 = ftp + IntFltLen0; \ + const fptype* Src = SrcLine + rpos -> SrcOffs; \ + const int IntFltLen = rpos -> fl; \ + int i; + +#define AVIR_RESIZE_PART1nx \ + while( rpos < rpose ) \ + { \ + const fptype* const ftp = rpos -> ftp; \ + const fptype* Src = SrcLine + rpos -> SrcOffs; \ + const int IntFltLen = rpos -> fl; \ + int i; + +#define AVIR_RESIZE_PART2 \ + DstLine += DstLineIncr; \ + rpos++; \ + } + + if( FltBank -> getOrder() == 1 ) + { + if( ElCount == 1 ) + { + AVIR_RESIZE_PART1 + + fptype sum0 = ElBiases[ 0 ]; + + for( i = 0; i < IntFltLen; i += 2 ) + { + sum0 += ( ftp[ i ] + ftp2[ i ] * x ) * Src[ i ]; + } + + DstLine[ 0 ] = sum0; + + AVIR_RESIZE_PART2 + } + else + if( ElCount == 4 ) + { + AVIR_RESIZE_PART1 + + fptype sum0 = ElBiases[ 0 ]; + fptype sum1 = ElBiases[ 1 ]; + fptype sum2 = ElBiases[ 2 ]; + fptype sum3 = ElBiases[ 3 ]; + + for( i = 0; i < IntFltLen; i += 2 ) + { + const fptype xx = ftp[ i ] + ftp2[ i ] * x; + sum0 += xx * Src[ 0 ]; + sum1 += xx * Src[ 1 ]; + sum2 += xx * Src[ 2 ]; + sum3 += xx * Src[ 3 ]; + Src += 4 * 2; + } + + DstLine[ 0 ] = sum0; + DstLine[ 1 ] = sum1; + DstLine[ 2 ] = sum2; + DstLine[ 3 ] = sum3; + + AVIR_RESIZE_PART2 + } + else + if( ElCount == 3 ) + { + AVIR_RESIZE_PART1 + + fptype sum0 = ElBiases[ 0 ]; + fptype sum1 = ElBiases[ 1 ]; + fptype sum2 = ElBiases[ 2 ]; + + for( i = 0; i < IntFltLen; i += 2 ) + { + const fptype xx = ftp[ i ] + ftp2[ i ] * x; + sum0 += xx * Src[ 0 ]; + sum1 += xx * Src[ 1 ]; + sum2 += xx * Src[ 2 ]; + Src += 3 * 2; + } + + DstLine[ 0 ] = sum0; + DstLine[ 1 ] = sum1; + DstLine[ 2 ] = sum2; + + AVIR_RESIZE_PART2 + } + else + if( ElCount == 2 ) + { + AVIR_RESIZE_PART1 + + fptype sum0 = ElBiases[ 0 ]; + fptype sum1 = ElBiases[ 1 ]; + + for( i = 0; i < IntFltLen; i += 2 ) + { + const fptype xx = ftp[ i ] + ftp2[ i ] * x; + sum0 += xx * Src[ 0 ]; + sum1 += xx * Src[ 1 ]; + Src += 2 * 2; + } + + DstLine[ 0 ] = sum0; + DstLine[ 1 ] = sum1; + + AVIR_RESIZE_PART2 + } + } + else + { + if( ElCount == 1 ) + { + AVIR_RESIZE_PART1nx + + fptype sum0 = ElBiases[ 0 ]; + + for( i = 0; i < IntFltLen; i += 2 ) + { + sum0 += ftp[ i ] * Src[ i ]; + } + + DstLine[ 0 ] = sum0; + + AVIR_RESIZE_PART2 + } + else + if( ElCount == 4 ) + { + AVIR_RESIZE_PART1nx + + fptype sum0 = ElBiases[ 0 ]; + fptype sum1 = ElBiases[ 1 ]; + fptype sum2 = ElBiases[ 2 ]; + fptype sum3 = ElBiases[ 3 ]; + + for( i = 0; i < IntFltLen; i += 2 ) + { + const fptype xx = ftp[ i ]; + sum0 += xx * Src[ 0 ]; + sum1 += xx * Src[ 1 ]; + sum2 += xx * Src[ 2 ]; + sum3 += xx * Src[ 3 ]; + Src += 4 * 2; + } + + DstLine[ 0 ] = sum0; + DstLine[ 1 ] = sum1; + DstLine[ 2 ] = sum2; + DstLine[ 3 ] = sum3; + + AVIR_RESIZE_PART2 + } + else + if( ElCount == 3 ) + { + AVIR_RESIZE_PART1nx + + fptype sum0 = ElBiases[ 0 ]; + fptype sum1 = ElBiases[ 1 ]; + fptype sum2 = ElBiases[ 2 ]; + + for( i = 0; i < IntFltLen; i += 2 ) + { + const fptype xx = ftp[ i ]; + sum0 += xx * Src[ 0 ]; + sum1 += xx * Src[ 1 ]; + sum2 += xx * Src[ 2 ]; + Src += 3 * 2; + } + + DstLine[ 0 ] = sum0; + DstLine[ 1 ] = sum1; + DstLine[ 2 ] = sum2; + + AVIR_RESIZE_PART2 + } + else + if( ElCount == 2 ) + { + AVIR_RESIZE_PART1nx + + fptype sum0 = ElBiases[ 0 ]; + fptype sum1 = ElBiases[ 1 ]; + + for( i = 0; i < IntFltLen; i += 2 ) + { + const fptype xx = ftp[ i ]; + sum0 += xx * Src[ 0 ]; + sum1 += xx * Src[ 1 ]; + Src += 2 * 2; + } + + DstLine[ 0 ] = sum0; + DstLine[ 1 ] = sum1; + + AVIR_RESIZE_PART2 + } + } + } +#undef AVIR_RESIZE_PART2 +#undef AVIR_RESIZE_PART1nx +#undef AVIR_RESIZE_PART1 +}; + +/** + * @brief Image resizer's default dithering class. + * + * This class defines an object that performs rounding, clipping and dithering + * operations over horizontal scanline pixels before scanline is stored in the + * output buffer. + * + * The ditherer should expect the same storage order of the pixels in a + * scanline as used in the "filtering step" class. So, a separate ditherer + * class should be defined for each scanline pixel storage style. The default + * ditherer implements a simple rounding without dithering: it can be used for + * an efficient dithering method which can be multi-threaded. + * + * @tparam fptype Floating point type to use for storing pixel data. SIMD + * types can be used. + */ + +template< class fptype > +class CImageResizerDithererDefINL +{ +public: + /** + * Function initializes the ditherer object. + * + * @param aLen Scanline length in pixels to process. + * @param aVars Image resizing-related variables. + * @param aTrMul Bit-depth truncation multiplier. 1 - no additional + * truncation. + * @param aPkOut Peak output value allowed. + */ + + void init( const int aLen, const CImageResizerVars& aVars, + const double aTrMul, const double aPkOut ) + { + Len = aLen; + Vars = &aVars; + LenE = aLen * Vars -> ElCount; + TrMul0 = aTrMul; + PkOut0 = aPkOut; + } + + /** + * @return "True" if dithering is recursive relative to scanlines meaning + * multi-threaded execution is not supported by this dithering method. + */ + + static bool isRecursive() + { + return( false ); + } + + /** + * Function performs rounding and clipping operations. + * + * @param ResScanline The buffer containing the final scanline. + */ + + void dither( fptype* const ResScanline ) const + { + const fptype c0 = (fptype) 0; + const fptype PkOut = (fptype) PkOut0; + int j; + + if( TrMul0 == 1.0 ) + { + // Optimization - do not perform bit depth truncation. + + for( j = 0; j < LenE; j++ ) + { + ResScanline[ j ] = clamp( round( ResScanline[ j ]), c0, + PkOut ); + } + } + else + { + const fptype TrMul = (fptype) TrMul0; + + for( j = 0; j < LenE; j++ ) + { + const fptype z0 = round( ResScanline[ j ] / TrMul ) * TrMul; + ResScanline[ j ] = clamp( z0, c0, PkOut ); + } + } + } + +protected: + int Len; ///< Scanline's length in pixels. + ///< + const CImageResizerVars* Vars; ///< Image resizing-related variables. + ///< + int LenE; ///< = LenE * ElCount. + ///< + double TrMul0; ///< Bit-depth truncation multiplier. + ///< + double PkOut0; ///< Peak output value allowed. + ///< +}; + +/** + * @brief Image resizer's error-diffusion dithering class, interleaved mode. + * + * This ditherer implements error-diffusion dithering which looks good, and + * whose results are compressed by PNG well. This implementation uses + * weighting coefficients obtained via machine optimization and visual + * evaluation. + * + * @tparam fptype Floating point type to use for storing pixel data. SIMD + * types can be used. + */ + +template< class fptype > +class CImageResizerDithererErrdINL : + public CImageResizerDithererDefINL< fptype > +{ +public: + /** + * Function initializes the ditherer object. + * + * @param aLen Scanline length in pixels to process. + * @param aVars Image resizing-related variables. + * @param aTrMul Bit-depth truncation multiplier. 1 - no additional + * truncation. + * @param aPkOut Peak output value allowed. + */ + + void init( const int aLen, const CImageResizerVars& aVars, + const double aTrMul, const double aPkOut ) + { + CImageResizerDithererDefINL< fptype > :: init( aLen, aVars, aTrMul, + aPkOut ); + + ResScanlineDith0.alloc( LenE + Vars -> ElCount, sizeof( fptype )); + ResScanlineDith = ResScanlineDith0 + Vars -> ElCount; + int i; + + for( i = 0; i < LenE + Vars -> ElCount; i++ ) + { + ResScanlineDith0[ i ] = (fptype) 0; + } + } + + static bool isRecursive() + { + return( true ); + } + + void dither( fptype* const ResScanline ) + { + const int ElCount = Vars -> ElCount; + const fptype c0 = (fptype) 0; + const fptype TrMul = (fptype) TrMul0; + const fptype PkOut = (fptype) PkOut0; + int j; + + for( j = 0; j < LenE; j++ ) + { + ResScanline[ j ] += ResScanlineDith[ j ]; + ResScanlineDith[ j ] = (fptype) 0; + } + + for( j = 0; j < LenE - ElCount; j++ ) + { + // Perform rounding, noise estimation and saturation. + + const fptype z0 = round( ResScanline[ j ] / TrMul ) * TrMul; + const fptype Noise = ResScanline[ j ] - z0; + ResScanline[ j ] = clamp( z0, c0, PkOut ); + + ResScanline[ j + ElCount ] += Noise * (fptype) 0.364842; + ResScanlineDith[ j - ElCount ] += Noise * (fptype) 0.207305; + ResScanlineDith[ j ] += Noise * (fptype) 0.364842; + ResScanlineDith[ j + ElCount ] += Noise * (fptype) 0.063011; + } + + while( j < LenE ) + { + const fptype z0 = round( ResScanline[ j ] / TrMul ) * TrMul; + const fptype Noise = ResScanline[ j ] - z0; + ResScanline[ j ] = clamp( z0, c0, PkOut ); + + ResScanlineDith[ j - ElCount ] += Noise * (fptype) 0.207305; + ResScanlineDith[ j ] += Noise * (fptype) 0.364842; + j++; + } + } + +protected: + using CImageResizerDithererDefINL< fptype > :: Len; + using CImageResizerDithererDefINL< fptype > :: Vars; + using CImageResizerDithererDefINL< fptype > :: LenE; + using CImageResizerDithererDefINL< fptype > :: TrMul0; + using CImageResizerDithererDefINL< fptype > :: PkOut0; + + CBuffer< fptype > ResScanlineDith0; ///< Error diffusion buffer. + ///< + fptype* ResScanlineDith; ///< Error diffusion buffer pointer which skips + ///< the first ElCount elements. + ///< +}; + +/** + * @brief Floating-point processing definition and abstraction class. + * + * This class defines several constants and typedefs that point to classes + * that should be used by the image resizing algorithm. Such "definition + * class" can be used to define alternative scanline processing algorithms + * (e.g. SIMD) and image scanline packing styles used during processing. This + * class also offers an abstraction layer for dithering, rounding and + * clamping (saturation) operation. + * + * The fpclass_def class can be used to define processing using both SIMD and + * non-SIMD types, but using algorithms that operate on interleaved pixels, + * and which are non-SIMD optimized themselves. + * + * @tparam afptype Floating point type to use for storing intermediate data + * and variables. For variables that are not used in intensive calculations + * the "double" type is always used. On the latest Intel processors (like + * i7-4770K) there is almost no performance difference between "double" and + * "float". Image quality differences between "double" and "float" are not + * apparent on 8-bit images. At the same time the "float" uses half amount of + * working memory the "double" type uses. SIMD types can be used. The + * functions round() and clamp() in the "avir" or other visible namespace + * should be available for the specified type. SIMD types allow to perform + * resizing of images with more than 4 channels, to be exact 4 * SIMD element + * number (e.g. 16 for float4), without modification of the image resizing + * algorithm required. + * @tparam afptypeatom The atomic type the "afptype" consists of. + * @tparam adith Ditherer class to use during processing. + */ + +template< class afptype, class afptypeatom = afptype, + class adith = CImageResizerDithererDefINL< afptype > > +class fpclass_def +{ +public: + typedef afptype fptype; ///< Floating-point type to use during processing. + ///< + typedef afptypeatom fptypeatom; ///< Atomic type "fptype" consists of. + ///< + static const int fppack = sizeof( fptype ) / sizeof( fptypeatom ); ///< + ///< The number of atomic types stored in a single "fptype" element. + ///< + static const int fpalign = sizeof( fptype ); ///< Suggested alignment size + ///< in bytes. This is not a required alignment, because image + ///< resizing algorithm cannot be made to have a strictly aligned data + ///< access at all steps (e.g. interpolation cannot perform aligned + ///< accesses). + ///< + static const int elalign = 1; ///< Length alignment of arrays of elements. + ///< This applies to filters and intermediate buffers: this constant + ///< forces filters and scanlines to have a length which is a multiple + ///< of this value, for more efficient SIMD implementation. + ///< + static const int packmode = 0; ///< 0 if interleaved packing, 1 if + ///< de-interleaved. + ///< + typedef CImageResizerFilterStepINL< fptype, fptypeatom > CFilterStep; ///< + ///< Filtering step class to use during processing. + ///< + typedef adith CDitherer; ///< Ditherer class to use during processing. + ///< +}; + +/** + * @brief Image resizer class. + * + * The object of this class can be used to resize 1-4 channel images to any + * required size. Resizing is performed by utilizing interpolated sinc + * fractional delay filters plus (if necessary) a cascade of built-in + * sinc function-based 2X upsampling or 2X downsampling stages, followed by a + * correction filtering. + * + * Object of this class can be allocated on stack. + * + * @tparam fpclass Floating-point processing definition class to use. See + * avir::fpclass_def for more details. + */ + +template< class fpclass = fpclass_def< float > > +class CImageResizer +{ + AVIR_NOCTOR( CImageResizer ); + +public: + /** + * Constructor initializes the resizer. + * + * @param aResBitDepth Required bit depth of resulting image (1-16). If + * integer value output is used (e.g. uint8_t), the bit depth also affects + * rounding: for example, if aResBitDepth=6 and "Tout" is uint8_t, the + * result will be rounded to 6 most significant bits (2 least significant + * bits truncated, with dithering applied). + * @param aSrcBitDepth Source image's real bit-depth. Set to 0 to use + * aResBitDepth. + * @param aParams Resizing algorithm's parameters to use. Leave out for + * default values. Can be useful when performing automatic optimization of + * parameters. + */ + + CImageResizer( const int aResBitDepth = 8, const int aSrcBitDepth = 0, + const CImageResizerParams& aParams = CImageResizerParamsDef() ) + : Params( aParams ) + , ResBitDepth( aResBitDepth ) + { + SrcBitDepth = ( aSrcBitDepth == 0 ? ResBitDepth : aSrcBitDepth ); + + initFilterBank( FixedFilterBank, 1.0, false, CFltBuffer() ); + FixedFilterBank.createAllFilters(); + } + + /** + * Function resizes image. + * + * @param SrcBuf Source image buffer. + * @param SrcWidth Source image width. + * @param SrcHeight Source image height. + * @param SrcScanlineSize Physical size of source scanline in elements + * (not bytes). If this value is below 1, SrcWidth * ElCountIO will be + * used as the physical source scanline size. + * @param[out] NewBuf Buffer to accept the resized image. Can be equal to + * SrcBuf if the size of the resized image is smaller or equal to source + * image in size. + * @param NewWidth New image width. + * @param NewHeight New image height. + * @param ElCountIO The number of elements (channels) used to store each + * source and destination pixel (1-4). + * @param k Resizing step (one output pixel corresponds to "k" input + * pixels). A downsizing factor if > 1.0; upsizing factor if <= 1.0. + * Multiply by -1 if you would like to bypass "ox" and "oy" adjustment + * which is done by default to produce a centered image. If step value + * equals 0, the step value will be chosen automatically and independently + * for horizontal and vertical resizing. + * @param[in,out] aVars Pointer to variables structure to be passed to the + * image resizing function. Can be NULL. Only variables that are + * initialized in default constructor of this structure are accepted by + * this function. These variables will not be changed by this function. + * All other variables can be modified by this function. The access to + * this object is not thread-safe, each concurrent instance of this + * function should use a separate aVars object. + * @tparam Tin Input buffer element's type. Can be uint8_t (0-255 value + * range), uint16_t (0-65535 value range), float (0.0-1.0 value range), + * double (0.0-1.0 value range). Larger integer types are treated as + * uint16_t. Signed integer types are unsupported. + * @tparam Tout Output buffer element's type. Can be uint8_t (0-255 value + * range), uint16_t (0-65535 value range), float (0.0-1.0 value range), + * double (0.0-1.0 value range). Larger integer types are treated as + * uint16_t. Signed integer types are unsupported. + */ + + template< class Tin, class Tout > + void resizeImage( const Tin* const SrcBuf, const int SrcWidth, + const int SrcHeight, int SrcScanlineSize, Tout* const NewBuf, + const int NewWidth, const int NewHeight, const int ElCountIO, + const double k, CImageResizerVars* const aVars = NULL ) const + { + if( SrcWidth == 0 || SrcHeight == 0 ) + { + memset( NewBuf, 0, (size_t) NewWidth * NewHeight * + sizeof( Tout )); + + return; + } + else + if( NewWidth == 0 || NewHeight == 0 ) + { + return; + } + + CImageResizerVars DefVars; + CImageResizerVars& Vars = ( aVars == NULL ? DefVars : *aVars ); + + CImageResizerThreadPool DefThreadPool; + CImageResizerThreadPool& ThreadPool = ( Vars.ThreadPool == NULL ? + DefThreadPool : *Vars.ThreadPool ); + + // Define resizing steps, also optionally modify offsets so that + // resizing produces a "centered" image. + + double kx; + double ky; + double ox = Vars.ox; + double oy = Vars.oy; + + if( k == 0.0 ) + { + kx = (double) SrcWidth / NewWidth; + ox += ( kx - 1.0 ) * 0.5; + + ky = (double) SrcHeight / NewHeight; + oy += ( ky - 1.0 ) * 0.5; + } + else + if( k > 0.0 ) + { + kx = k; + ky = k; + + const double ko = ( k - 1.0 ) * 0.5; + ox += ko; + oy += ko; + } + else + { + kx = -k; + ky = -k; + } + + // Evaluate pre-multipliers used on the output stage. + + const bool IsInFloat = ( (Tin) 0.25 != 0 ); + const bool IsOutFloat = ( (Tout) 0.25 != 0 ); + double OutMul; // Output multiplier. + + if( Vars.UseSRGBGamma ) + { + if( IsInFloat ) + { + Vars.InGammaMult = 1.0; + } + else + { + Vars.InGammaMult = + 1.0 / ( sizeof( Tin ) == 1 ? 255.0 : 65535.0 ); + } + + if( IsOutFloat ) + { + Vars.OutGammaMult = 1.0; + } + else + { + Vars.OutGammaMult = ( sizeof( Tout ) == 1 ? 255.0 : 65535.0 ); + } + + OutMul = 1.0; + } + else + { + if( IsOutFloat ) + { + OutMul = 1.0; + } + else + { + OutMul = ( sizeof( Tout ) == 1 ? 255.0 : 65535.0 ); + } + + if( !IsInFloat ) + { + OutMul /= ( sizeof( Tin ) == 1 ? 255.0 : 65535.0 ); + } + } + + // Fill widely-used variables. + + const int ElCount = ( ElCountIO + fpclass :: fppack - 1 ) / + fpclass :: fppack; + + const int NewWidthE = NewWidth * ElCount; + + if( SrcScanlineSize < 1 ) + { + SrcScanlineSize = SrcWidth * ElCountIO; + } + + Vars.ElCount = ElCount; + Vars.ElCountIO = ElCountIO; + Vars.fppack = fpclass :: fppack; + Vars.fpalign = fpclass :: fpalign; + Vars.elalign = fpclass :: elalign; + Vars.packmode = fpclass :: packmode; + + // Horizontal scanline filtering and resizing. + + CDSPFracFilterBankLin< fptype > FltBank; + CFilterSteps FltSteps; + typename CFilterStep :: CRPosBufArray RPosBufArray; + CBuffer< uint8_t > UsedFracMap; + + // Perform the filtering steps modeling at various modes, find the + // most efficient mode for both horizontal and vertical resizing. + + int UseBuildMode = 1; + const int BuildModeCount = + ( FixedFilterBank.getOrder() == 0 ? 4 : 2 ); + + int m; + + if( Vars.BuildMode >= 0 ) + { + UseBuildMode = Vars.BuildMode; + } + else + { + int BestScore = 0x7FFFFFFF; + + for( m = 0; m < BuildModeCount; m++ ) + { + CDSPFracFilterBankLin< fptype > TmpBank; + CFilterSteps TmpSteps; + Vars.k = kx; + Vars.o = ox; + buildFilterSteps( TmpSteps, Vars, TmpBank, OutMul, m, true ); + updateFilterStepBuffers( TmpSteps, Vars, RPosBufArray, + SrcWidth, NewWidth ); + + fillUsedFracMap( TmpSteps[ Vars.ResizeStep ], UsedFracMap ); + const int c = calcComplexity( TmpSteps, Vars, UsedFracMap, + SrcHeight ); + + if( c < BestScore ) + { + UseBuildMode = m; + BestScore = c; + } + } + } + + // Perform the actual filtering steps building. + + Vars.k = kx; + Vars.o = ox; + buildFilterSteps( FltSteps, Vars, FltBank, OutMul, UseBuildMode, + false ); + + updateFilterStepBuffers( FltSteps, Vars, RPosBufArray, SrcWidth, + NewWidth ); + + updateBufLenAndRPosPtrs( FltSteps, Vars, NewWidth ); + + const int ThreadCount = ThreadPool.getSuggestedWorkloadCount(); + // Includes the current thread. + + CStructArray< CThreadData< Tin, Tout > > td; + td.setItemCount( ThreadCount ); + int i; + + for( i = 0; i < ThreadCount; i++ ) + { + if( i > 0 ) + { + ThreadPool.addWorkload( &td[ i ]); + } + + td[ i ].init( i, ThreadCount, FltSteps, Vars ); + + td[ i ].initScanlineQueue( td[ i ].sopResizeH, SrcHeight, + SrcWidth ); + } + + CBuffer< fptype, size_t > FltBuf( (size_t) NewWidthE * SrcHeight, + fpclass :: fpalign ); // Temporary buffer that receives + // horizontally-filtered and resized image. + + for( i = 0; i < SrcHeight; i++ ) + { + td[ i % ThreadCount ].addScanlineToQueue( + (void*) &SrcBuf[ (size_t) i * SrcScanlineSize ], + &FltBuf[ (size_t) i * NewWidthE ]); + } + + ThreadPool.startAllWorkloads(); + td[ 0 ].processScanlineQueue(); + ThreadPool.waitAllWorkloadsToFinish(); + + // Vertical scanline filtering and resizing, reuse previously defined + // filtering steps if possible. + + const int PrevUseBuildMode = UseBuildMode; + + if( Vars.BuildMode >= 0 ) + { + UseBuildMode = Vars.BuildMode; + } + else + { + CImageResizerVars TmpVars( Vars ); + int BestScore = 0x7FFFFFFF; + + for( m = 0; m < BuildModeCount; m++ ) + { + CDSPFracFilterBankLin< fptype > TmpBank; + TmpBank.copyInitParams( FltBank ); + CFilterSteps TmpSteps; + TmpVars.k = ky; + TmpVars.o = oy; + buildFilterSteps( TmpSteps, TmpVars, TmpBank, 1.0, m, true ); + updateFilterStepBuffers( TmpSteps, TmpVars, RPosBufArray, + SrcHeight, NewHeight ); + + fillUsedFracMap( TmpSteps[ TmpVars.ResizeStep ], + UsedFracMap ); + + const int c = calcComplexity( TmpSteps, TmpVars, UsedFracMap, + NewWidth ); + + if( c < BestScore ) + { + UseBuildMode = m; + BestScore = c; + } + } + } + + Vars.k = ky; + Vars.o = oy; + + if( UseBuildMode == PrevUseBuildMode && ky == kx ) + { + if( OutMul != 1.0 ) + { + modifyCorrFilterDCGain( FltSteps, 1.0 / OutMul ); + } + } + else + { + buildFilterSteps( FltSteps, Vars, FltBank, 1.0, UseBuildMode, + false ); + } + + updateFilterStepBuffers( FltSteps, Vars, RPosBufArray, SrcHeight, + NewHeight ); + + updateBufLenAndRPosPtrs( FltSteps, Vars, NewWidth ); + + if( IsOutFloat && sizeof( FltBuf[ 0 ]) == sizeof( Tout ) && + fpclass :: packmode == 0 ) + { + // In-place output. + + for( i = 0; i < ThreadCount; i++ ) + { + td[ i ].initScanlineQueue( td[ i ].sopResizeV, NewWidth, + SrcHeight, NewWidthE, NewWidthE ); + } + + for( i = 0; i < NewWidth; i++ ) + { + td[ i % ThreadCount ].addScanlineToQueue( + &FltBuf[ (size_t) i * ElCount ], + (fptype*) &NewBuf[ (size_t) i * ElCount ]); + } + + ThreadPool.startAllWorkloads(); + td[ 0 ].processScanlineQueue(); + ThreadPool.waitAllWorkloadsToFinish(); + ThreadPool.removeAllWorkloads(); + + return; + } + + CBuffer< fptype, size_t > ResBuf( (size_t) NewWidthE * NewHeight, + fpclass :: fpalign ); + + for( i = 0; i < ThreadCount; i++ ) + { + td[ i ].initScanlineQueue( td[ i ].sopResizeV, NewWidth, + SrcHeight, NewWidthE, NewWidthE ); + } + + const int im = ( fpclass :: packmode == 0 ? ElCount : 1 ); + + for( i = 0; i < NewWidth; i++ ) + { + td[ i % ThreadCount ].addScanlineToQueue( + &FltBuf[ (size_t) i * im ], &ResBuf[ (size_t) i * im ]); + } + + ThreadPool.startAllWorkloads(); + td[ 0 ].processScanlineQueue(); + ThreadPool.waitAllWorkloadsToFinish(); + + if( IsOutFloat ) + { + // Perform output, but skip dithering. + + for( i = 0; i < ThreadCount; i++ ) + { + td[ i ].initScanlineQueue( td[ i ].sopUnpackH, + NewHeight, NewWidth ); + } + + for( i = 0; i < NewHeight; i++ ) + { + td[ i % ThreadCount ].addScanlineToQueue( + &ResBuf[ (size_t) i * NewWidthE ], + &NewBuf[ (size_t) i * NewWidth * ElCountIO ]); + } + + ThreadPool.startAllWorkloads(); + td[ 0 ].processScanlineQueue(); + ThreadPool.waitAllWorkloadsToFinish(); + ThreadPool.removeAllWorkloads(); + + return; + } + + // Perform output with dithering (for integer output only). + + int TruncBits; // The number of lower bits to truncate and dither. + int OutRange; // Output range. + + if( sizeof( Tout ) == 1 ) + { + TruncBits = 8 - ResBitDepth; + OutRange = 255; + } + else + { + TruncBits = 16 - ResBitDepth; + OutRange = 65535; + } + + const double PkOut = OutRange; + const double TrMul = ( TruncBits > 0 ? + PkOut / ( OutRange >> TruncBits ) : 1.0 ); + + if( CDitherer :: isRecursive() ) + { + td[ 0 ].getDitherer().init( NewWidth, Vars, TrMul, PkOut ); + + if( Vars.UseSRGBGamma ) + { + for( i = 0; i < NewHeight; i++ ) + { + fptype* const ResScanline = + &ResBuf[ (size_t) i * NewWidthE ]; + + CFilterStep :: applySRGBGamma( ResScanline, NewWidth, + Vars ); + + td[ 0 ].getDitherer().dither( ResScanline ); + + CFilterStep :: unpackScanline( ResScanline, + &NewBuf[ (size_t) i * NewWidth * ElCountIO ], + NewWidth, Vars ); + } + } + else + { + for( i = 0; i < NewHeight; i++ ) + { + fptype* const ResScanline = + &ResBuf[ (size_t) i * NewWidthE ]; + + td[ 0 ].getDitherer().dither( ResScanline ); + + CFilterStep :: unpackScanline( ResScanline, + &NewBuf[ (size_t) i * NewWidth * ElCountIO ], + NewWidth, Vars ); + } + } + } + else + { + for( i = 0; i < ThreadCount; i++ ) + { + td[ i ].initScanlineQueue( td[ i ].sopDitherAndUnpackH, + NewHeight, NewWidth ); + + td[ i ].getDitherer().init( NewWidth, Vars, TrMul, PkOut ); + } + + for( i = 0; i < NewHeight; i++ ) + { + td[ i % ThreadCount ].addScanlineToQueue( + &ResBuf[ (size_t) i * NewWidthE ], + &NewBuf[ (size_t) i * NewWidth * ElCountIO ]); + } + + ThreadPool.startAllWorkloads(); + td[ 0 ].processScanlineQueue(); + ThreadPool.waitAllWorkloadsToFinish(); + } + + ThreadPool.removeAllWorkloads(); + } + +private: + typedef typename fpclass :: fptype fptype; ///< Floating-point type to use + ///< during processing. + ///< + typedef typename fpclass :: CFilterStep CFilterStep; ///< Filtering step + ///< class to use during processing. + ///< + typedef typename fpclass :: CDitherer CDitherer; ///< Ditherer class to + ///< use during processing. + ///< + CImageResizerParams Params; ///< Algorithm's parameters currently in use. + ///< + int SrcBitDepth; ///< Bit resolution of the source image. + ///< + int ResBitDepth; ///< Bit resolution of the resulting image. + ///< + CDSPFracFilterBankLin< fptype > FixedFilterBank; ///< Fractional delay + ///< filter bank with fixed characteristics, mainly for upsizing + ///< cases. + ///< + + /** + * @brief Filtering steps array. + * + * The object of this class stores filtering steps together. + */ + + typedef CStructArray< CFilterStep > CFilterSteps; + + /** + * Function initializes the filter bank in the specified resizing step + * according to the source and resulting image bit depths. + * + * @param FltBank Filter bank to initialize. + * @param CutoffMult Cutoff multiplier, 0 to 1. 1 corresponds to 0.5pi + * cutoff point. + * @param ForceHiOrder "True" if a high-order interpolation should be + * forced which requires considerably less resources for initialization. + * @param ExtFilter External filter to apply to interpolation filter. + */ + + void initFilterBank( CDSPFracFilterBankLin< fptype >& FltBank, + const double CutoffMult, const bool ForceHiOrder, + const CFltBuffer& ExtFilter ) const + { + const int IntBitDepth = ( ResBitDepth > SrcBitDepth ? ResBitDepth : + SrcBitDepth ); + + const double SNR = -6.02 * ( IntBitDepth + 3 ); + int UseOrder; + int FracCount; // The number of fractional delay filters sampled by + // the filter bank. This variable affects the signal-to-noise + // ratio at interpolation stage. Theoretically, at UseOrder==1, + // 8-bit image resizing requires 66.2 dB SNR or 11. 16-bit + // resizing requires 114.4 dB SNR or 150. At UseOrder=0 the + // required number of filters is exponentially higher. + + if( ForceHiOrder || IntBitDepth > 8 ) + { + UseOrder = 1; // -146 dB max + FracCount = (int) ceil( 0.23134052 * exp( -0.058062929 * SNR )); + } + else + { + UseOrder = 0; // -72 dB max + FracCount = (int) ceil( 0.33287686 * exp( -0.11334583 * SNR )); + } + + if( FracCount < 2 ) + { + FracCount = 2; + } + + FltBank.init( FracCount, UseOrder, Params.IntFltLen / CutoffMult, + Params.IntFltCutoff * CutoffMult, Params.IntFltAlpha, ExtFilter, + fpclass :: fpalign, fpclass :: elalign ); + } + + /** + * Function allocates filter buffer taking "fpclass" alignments into + * account. The allocated buffer may be larger than the requested size: in + * this case the additional elements will be zeroed by this function. + * + * @param Flt Filter buffer. + * @param ReqCapacity The required filter buffer's capacity. + * @param IsModel "True" if filtering steps modeling is performed without + * actual filter allocation. + * @param FltExt If non-NULL this variable will receive the number of + * elements the filter was extended by. + */ + + static void allocFilter( CBuffer< fptype >& Flt, const int ReqCapacity, + const bool IsModel = false, int* const FltExt = NULL ) + { + int UseCapacity = ( ReqCapacity + fpclass :: elalign - 1 ) & + ~( fpclass :: elalign - 1 ); + + int Ext = UseCapacity - ReqCapacity; + + if( FltExt != NULL ) + { + *FltExt = Ext; + } + + if( IsModel ) + { + Flt.forceCapacity( UseCapacity ); + return; + } + + Flt.alloc( UseCapacity, fpclass :: fpalign ); + + while( Ext > 0 ) + { + Ext--; + Flt[ ReqCapacity + Ext ] = (fptype) 0; + } + } + + /** + * Function assigns filter parameters to the specified filtering step + * object. + * + * @param fs Filtering step to assign parameter to. This step cannot be + * the last step if ResampleFactor greater than 1 was specified. + * @param IsUpsample "True" if upsampling step. Should be set to "false" + * if FltCutoff is negative. + * @param ResampleFactor Resampling factor of this filter (>=1). + * @param FltCutoff Filter cutoff point. This value will be divided by the + * ResampleFactor if IsUpsample equals "true". If zero value was + * specified, the "half-band" predefined filter will be created. In this + * case the ResampleFactor will modify the filter cutoff point. + * @param DCGain DC gain to apply to the filter. Assigned to filtering + * step's DCGain variable. + * @param UseFltOrig "True" if the originally-designed filter should be + * left in filtering step's FltOrig buffer. Otherwise it will be freed. + * @param IsModel "True" if filtering steps modeling is performed without + * actual filter building. + */ + + void assignFilterParams( CFilterStep& fs, const bool IsUpsample, + const int ResampleFactor, const double FltCutoff, const double DCGain, + const bool UseFltOrig, const bool IsModel ) const + { + double FltAlpha; + double Len2; + double Freq; + + if( FltCutoff == 0.0 ) + { + const double m = 2.0 / ResampleFactor; + FltAlpha = Params.HBFltAlpha; + Len2 = 0.5 * Params.HBFltLen / m; + Freq = AVIR_PI * Params.HBFltCutoff * m; + } + else + { + FltAlpha = Params.LPFltAlpha; + Len2 = 0.25 * Params.LPFltBaseLen / FltCutoff; + Freq = AVIR_PI * Params.LPFltCutoffMult * FltCutoff; + } + + if( IsUpsample ) + { + Len2 *= ResampleFactor; + Freq /= ResampleFactor; + fs.DCGain = DCGain * ResampleFactor; + } + else + { + fs.DCGain = DCGain; + } + + fs.FltOrig.Len2 = Len2; + fs.FltOrig.Freq = Freq; + fs.FltOrig.Alpha = FltAlpha; + fs.FltOrig.DCGain = fs.DCGain; + + CDSPPeakedCosineLPF w( Len2, Freq, FltAlpha ); + + fs.IsUpsample = IsUpsample; + fs.ResampleFactor = ResampleFactor; + fs.FltLatency = w.fl2; + + int FltExt; // Filter's extension due to fpclass :: elalign. + + if( IsModel ) + { + allocFilter( fs.Flt, w.FilterLen, true, &FltExt ); + + if( UseFltOrig ) + { + // Allocate a real buffer even in modeling mode since this + // filter may be copied by the filter bank. + + fs.FltOrig.alloc( w.FilterLen ); + memset( &fs.FltOrig[ 0 ], 0, + w.FilterLen * sizeof( fs.FltOrig[ 0 ])); + } + } + else + { + fs.FltOrig.alloc( w.FilterLen ); + + w.generateLPF( &fs.FltOrig[ 0 ], fs.DCGain ); + + allocFilter( fs.Flt, fs.FltOrig.getCapacity(), false, &FltExt ); + copyArray( &fs.FltOrig[ 0 ], &fs.Flt[ 0 ], + fs.FltOrig.getCapacity() ); + + if( !UseFltOrig ) + { + fs.FltOrig.free(); + } + } + + if( IsUpsample ) + { + int l = fs.Flt.getCapacity() - fs.FltLatency - ResampleFactor - + FltExt; + + allocFilter( fs.PrefixDC, l, IsModel ); + allocFilter( fs.SuffixDC, fs.FltLatency, IsModel ); + + if( IsModel ) + { + return; + } + + // Create prefix and suffix "tails" used during upsampling. + + const fptype* ip = &fs.Flt[ fs.FltLatency + ResampleFactor ]; + copyArray( ip, &fs.PrefixDC[ 0 ], l ); + + while( true ) + { + ip += ResampleFactor; + l -= ResampleFactor; + + if( l <= 0 ) + { + break; + } + + addArray( ip, &fs.PrefixDC[ 0 ], l ); + } + + l = fs.FltLatency; + fptype* op = &fs.SuffixDC[ 0 ]; + copyArray( &fs.Flt[ 0 ], op, l ); + + while( true ) + { + op += ResampleFactor; + l -= ResampleFactor; + + if( l <= 0 ) + { + break; + } + + addArray( &fs.Flt[ 0 ], op, l ); + } + } + else + if( !UseFltOrig ) + { + fs.EdgePixelCount = fs.EdgePixelCountDef; + } + } + + /** + * Function adds a correction filter that tries to achieve a linear + * frequency response at all frequencies. The actual resulting response + * may feature a slight damping of the highest frequencies since a + * suitably short correction filter cannot fix steep high-frequency + * damping. + * + * This function assumes that the resizing step is currently the last + * step, even if it was not inserted yet: this allows placement of the + * correction filter both before and after the resizing step. + * + * @param Steps Filtering steps. + * @param bw Resulting bandwidth relative to the original bandwidth (which + * is 1.0), usually 1/k. Should be <= 1.0. + * @param IsPreCorrection "True" if the filtering step was already created + * and it is first in the Steps array. "True" also adds edge pixels to + * reduce edge artifacts. + * @param IsModel "True" if filtering steps modeling is performed without + * actual filter building. + */ + + void addCorrectionFilter( CFilterSteps& Steps, const double bw, + const bool IsPreCorrection, const bool IsModel ) const + { + CFilterStep& fs = ( IsPreCorrection ? Steps[ 0 ] : Steps.add() ); + fs.IsUpsample = false; + fs.ResampleFactor = 1; + fs.DCGain = 1.0; + fs.EdgePixelCount = ( IsPreCorrection ? fs.EdgePixelCountDef : 0 ); + + if( IsModel ) + { + allocFilter( fs.Flt, CDSPFIREQ :: calcFilterLength( + Params.CorrFltLen, fs.FltLatency ), true ); + + return; + } + + const int BinCount = 65; // Frequency response bins to control. + const int BinCount1 = BinCount - 1; + double curbw = 1.0; // Bandwidth of the filter at the current step. + int i; + int j; + double re; + double im; + + CBuffer< double > Bins( BinCount ); // Adjustment introduced by all + // steps at all frequencies of interest. + + for( j = 0; j < BinCount; j++ ) + { + Bins[ j ] = 1.0; + } + + const int si = ( IsPreCorrection ? 1 : 0 ); + + for( i = si; i < Steps.getItemCount() - ( si ^ 1 ); i++ ) + { + const CFilterStep& fs = Steps[ i ]; + + if( fs.IsUpsample ) + { + curbw *= fs.ResampleFactor; + + if( fs.FltOrig.getCapacity() > 0 ) + { + continue; + } + } + + const fptype* Flt; + int FltLen; + + if( fs.ResampleFactor == 0 ) + { + Flt = fs.FltBank -> getFilter( 0 ); + FltLen = fs.FltBank -> getFilterLen(); + } + else + { + Flt = &fs.Flt[ 0 ]; + FltLen = fs.Flt.getCapacity(); + } + + // Calculate frequency response adjustment introduced by the + // filter at this step, within the bounds of bandwidth of + // interest. + + const double thm = AVIR_PI * bw / ( curbw * BinCount1 ); + + for( j = 0; j < BinCount; j++ ) + { + calcFIRFilterResponse( Flt, FltLen, j * thm, re, im ); + + Bins[ j ] *= fs.DCGain / sqrt( re * re + im * im ); + } + + if( !fs.IsUpsample && fs.ResampleFactor > 1 ) + { + curbw /= fs.ResampleFactor; + } + } + + // Calculate filter. + + CDSPFIREQ EQ; + EQ.init( bw * 2.0, Params.CorrFltLen, BinCount, 0.0, bw, false, + Params.CorrFltAlpha ); + + fs.FltLatency = EQ.getFilterLatency(); + + CBuffer< double > Filter( EQ.getFilterLength() ); + EQ.buildFilter( Bins, &Filter[ 0 ]); + normalizeFIRFilter( &Filter[ 0 ], Filter.getCapacity(), 1.0 ); + + allocFilter( fs.Flt, Filter.getCapacity() ); + copyArray( &Filter[ 0 ], &fs.Flt[ 0 ], Filter.getCapacity() ); + + // Print a theoretically achieved final frequency response at various + // feature sizes (from DC to 1 pixel). Values above 255 means features + // become brighter, values below 255 means features become dimmer. + +/* const double sbw = ( bw > 1.0 ? 1.0 / bw : 1.0 ); + + for( j = 0; j < BinCount; j++ ) + { + const double th = AVIR_PI * sbw * j / BinCount1; + + calcFIRFilterResponse( &fs.Flt[ 0 ], fs.Flt.getCapacity(), + th, re, im ); + + printf( "%f\n", sqrt( re * re + im * im ) / Bins[ j ] * 255 ); + } + + printf( "***\n" );*/ + } + + /** + * Function adds a sharpening filter if image is being upsized. Such + * sharpening allows to spot interpolation filter's stop-band attenuation: + * if attenuation is too weak, a "dark grid" and other artifacts may + * become visible. + * + * It is assumed that 40 decibel stop-band attenuation should be + * considered a required minimum: this allows application of (deliberately + * strong) 64X sharpening without spotting any artifacts. + * + * @param Steps Filtering steps. + * @param bw Resulting bandwidth relative to the original bandwidth (which + * is 1.0), usually 1/k. + * @param IsModel "True" if filtering steps modeling is performed without + * actual filter building. + */ + + static void addSharpenTest( CFilterSteps& Steps, const double bw, + const bool IsModel ) + { + if( bw <= 1.0 ) + { + return; + } + + const double FltLen = 10.0 * bw; + + CFilterStep& fs = Steps.add(); + fs.IsUpsample = false; + fs.ResampleFactor = 1; + fs.DCGain = 1.0; + fs.EdgePixelCount = 0; + + if( IsModel ) + { + allocFilter( fs.Flt, CDSPFIREQ :: calcFilterLength( FltLen, + fs.FltLatency ), true ); + + return; + } + + const int BinCount = 200; + CBuffer< double > Bins( BinCount ); + int Thresh = (int) round( BinCount / bw * 1.75 ); + + if( Thresh > BinCount ) + { + Thresh = BinCount; + } + + int j; + + for( j = 0; j < Thresh; j++ ) + { + Bins[ j ] = 1.0; + } + + for( j = Thresh; j < BinCount; j++ ) + { + Bins[ j ] = 256.0; + } + + CDSPFIREQ EQ; + EQ.init( bw * 2.0, FltLen, BinCount, 0.0, bw, false, 1.7 ); + + fs.FltLatency = EQ.getFilterLatency(); + + CBuffer< double > Filter( EQ.getFilterLength() ); + EQ.buildFilter( Bins, &Filter[ 0 ]); + normalizeFIRFilter( &Filter[ 0 ], Filter.getCapacity(), 1.0 ); + + allocFilter( fs.Flt, Filter.getCapacity() ); + copyArray( &Filter[ 0 ], &fs.Flt[ 0 ], Filter.getCapacity() ); + +/* for( j = 0; j < BinCount; j++ ) + { + const double th = AVIR_PI * j / ( BinCount - 1 ); + double re; + double im; + + calcFIRFilterResponse( &fs.Flt[ 0 ], fs.Flt.getCapacity(), + th, re, im ); + + printf( "%f\n", sqrt( re * re + im * im )); + } + + printf( "***\n" );*/ + } + + /** + * Function builds sequence of filtering steps depending on the specified + * resizing coefficient. The last steps included are always the resizing + * step then (possibly) the correction step. + * + * @param Steps Array that receives filtering steps. + * @param[out] Vars Variables object. + * @param FltBank Filter bank to initialize and use. + * @param DCGain The overall DC gain to apply. This DC gain is applied to + * the first filtering step only (upsampling or filtering step). + * @param ModeFlags Build mode flags to use. This is a bitmap of switches + * that enable or disable certain algorithm features. + * @param IsModel "True" if filtering steps modeling is performed without + * the actual filter allocation and building. + */ + + void buildFilterSteps( CFilterSteps& Steps, CImageResizerVars& Vars, + CDSPFracFilterBankLin< fptype >& FltBank, const double DCGain, + const int ModeFlags, const bool IsModel ) const + { + Steps.clear(); + + const bool DoFltAndIntCombo = (( ModeFlags & 1 ) != 0 ); // Do filter + // and interpolator combining. + const bool ForceHiOrderInt = (( ModeFlags & 2 ) != 0 ); // Force use + // of a higher-order interpolation. + const bool UseHalfband = (( ModeFlags & 4 ) != 0 ); // Use half-band + // filter. + + const double bw = 1.0 / Vars.k; // Resulting bandwidth. + const int UpsampleFactor = ( (int) floor( Vars.k ) < 2 ? 2 : 1 ); + double IntCutoffMult; // Interpolation filter cutoff multiplier. + CFilterStep* ReuseStep; // If not NULL, resizing step should use + // this step object instead of creating a new one. + CFilterStep* ExtFltStep; // Use FltOrig of this step as the external + // filter to applied to the interpolator. + bool IsPreCorrection; // "True" if the correction filter is applied + // first. + double FltCutoff; // Cutoff frequency of the first filtering step. + double corrbw; ///< Bandwidth at the correction step. + + if( Vars.k <= 1.0 ) + { + IsPreCorrection = true; + FltCutoff = 1.0; + corrbw = 1.0; + Steps.add(); + } + else + { + IsPreCorrection = false; + FltCutoff = bw; + corrbw = bw; + } + + // Add 1 upsampling or several downsampling filters. + + if( UpsampleFactor > 1 ) + { + CFilterStep& fs = Steps.add(); + assignFilterParams( fs, true, UpsampleFactor, FltCutoff, DCGain, + DoFltAndIntCombo, IsModel ); + + IntCutoffMult = FltCutoff * 2.0 / UpsampleFactor; + ReuseStep = NULL; + ExtFltStep = ( DoFltAndIntCombo ? &fs : NULL ); + } + else + { + int DownsampleFactor; + + while( true ) + { + DownsampleFactor = (int) floor( 0.5 / FltCutoff ); + bool DoHBFltAdd = ( UseHalfband && DownsampleFactor > 1 ); + + if( DoHBFltAdd ) + { + assignFilterParams( Steps.add(), false, DownsampleFactor, + 0.0, 1.0, false, IsModel ); + + FltCutoff *= DownsampleFactor; + } + else + { + if( DownsampleFactor < 1 ) + { + DownsampleFactor = 1; + } + + break; + } + } + + CFilterStep& fs = Steps.add(); + assignFilterParams( fs, false, DownsampleFactor, FltCutoff, + DCGain, DoFltAndIntCombo, IsModel ); + + IntCutoffMult = FltCutoff / 0.5; + + if( DoFltAndIntCombo ) + { + ReuseStep = &fs; + ExtFltStep = &fs; + } + else + { + IntCutoffMult *= DownsampleFactor; + ReuseStep = NULL; + ExtFltStep = NULL; + } + } + + // Insert resizing and correction steps. + + CFilterStep& fs = ( ReuseStep == NULL ? Steps.add() : *ReuseStep ); + + Vars.ResizeStep = Steps.getItemCount() - 1; + fs.IsUpsample = false; + fs.ResampleFactor = 0; + fs.DCGain = ( ExtFltStep == NULL ? 1.0 : ExtFltStep -> DCGain ); + + initFilterBank( FltBank, IntCutoffMult, ForceHiOrderInt, + ( ExtFltStep == NULL ? fs.FltOrig : ExtFltStep -> FltOrig )); + + if( FltBank == FixedFilterBank ) + { + fs.FltBank = (CDSPFracFilterBankLin< fptype >*) &FixedFilterBank; + } + else + { + fs.FltBank = &FltBank; + } + + addCorrectionFilter( Steps, corrbw, IsPreCorrection, IsModel ); + + //addSharpenTest( Steps, bw, IsModel ); + } + + /** + * Function extends *this upsampling step so that it produces more + * upsampled pixels that cover the prefix and suffix needs of the next + * step. After the call to this function the InPrefix and InSuffix + * variables of the next step will be set to zero. + * + * @param fs Upsampling filtering step. + * @param NextStep The next step structure. + */ + + static void extendUpsample( CFilterStep& fs, CFilterStep& NextStep ) + { + fs.InPrefix = ( NextStep.InPrefix + fs.ResampleFactor - 1 ) / + fs.ResampleFactor; + + fs.OutPrefix += fs.InPrefix * fs.ResampleFactor; + NextStep.InPrefix = 0; + + fs.InSuffix = ( NextStep.InSuffix + fs.ResampleFactor - 1 ) / + fs.ResampleFactor; + + fs.OutSuffix += fs.InSuffix * fs.ResampleFactor; + NextStep.InSuffix = 0; + } + + /** + * Function fills resizing step's RPosBuf array, excluding the actual + * "ftp" pointers and "SrcOffs" offsets. + * + * This array should be cleared if the resizing step or offset were + * changed. Otherwise this function only fills the elements required to + * cover resizing step's OutLen. + * + * This function is called by the updateFilterStepBuffers() function. + * + * @param fs Resizing step. + * @param Vars Variables object. + */ + + static void fillRPosBuf( CFilterStep& fs, const CImageResizerVars& Vars ) + { + const int PrevLen = fs.RPosBuf -> getCapacity(); + + if( fs.OutLen > PrevLen ) + { + fs.RPosBuf -> increaseCapacity( fs.OutLen ); + } + + typename CFilterStep :: CResizePos* rpos = &(*fs.RPosBuf)[ PrevLen ]; + const int FracCount = fs.FltBank -> getFracCount(); + const double o = Vars.o; + const double k = Vars.k; + int i; + + for( i = PrevLen; i < fs.OutLen; i++ ) + { + const double SrcPos = o + k * i; + const int SrcPosInt = (int) floor( SrcPos ); + const double x = ( SrcPos - SrcPosInt ) * FracCount; + const int fti = (int) x; + rpos -> x = (typename fpclass :: fptypeatom) ( x - fti ); + rpos -> fti = fti; + rpos -> SrcPosInt = SrcPosInt; + rpos++; + } + } + + /** + * Function updates filtering step buffer lengths depending on the + * specified source and new scanline lengths. This function should be + * called after the buildFilterSteps() function. + * + * @param Steps Array that receives filtering steps. + * @param[out] Vars Variables object, will receive buffer size and length. + * This function expects "k" and "o" variable values that will be + * adjusted by this function. + * @param RPosBufArray Resizing position buffers array, used to obtain + * buffer to initialize and use (will be reused if it is already fully or + * partially filled). + * @param SrcLen Source scanline's length in pixels. + * @param NewLen New scanline's length in pixels. + */ + + static void updateFilterStepBuffers( CFilterSteps& Steps, + CImageResizerVars& Vars, + typename CFilterStep :: CRPosBufArray& RPosBufArray, int SrcLen, + const int NewLen ) + { + int upstep = -1; + int InBuf = 0; + int i; + + for( i = 0; i < Steps.getItemCount(); i++ ) + { + CFilterStep& fs = Steps[ i ]; + + fs.Vars = &Vars; + fs.InLen = SrcLen; + fs.InBuf = InBuf; + fs.OutBuf = ( InBuf + 1 ) & 1; + + if( fs.IsUpsample ) + { + upstep = i; + Vars.k *= fs.ResampleFactor; + Vars.o *= fs.ResampleFactor; + fs.InPrefix = 0; + fs.InSuffix = 0; + fs.OutLen = fs.InLen * fs.ResampleFactor; + fs.OutPrefix = fs.FltLatency; + fs.OutSuffix = fs.Flt.getCapacity() - fs.FltLatency - + fs.ResampleFactor; + + int l0 = fs.OutPrefix + fs.OutLen + fs.OutSuffix; + int l = fs.InLen * fs.ResampleFactor + + fs.SuffixDC.getCapacity(); + + if( l > l0 ) + { + fs.OutSuffix += l - l0; + } + + l0 = fs.OutLen + fs.OutSuffix; + + if( fs.PrefixDC.getCapacity() > l0 ) + { + fs.OutSuffix += fs.PrefixDC.getCapacity() - l0; + } + } + else + if( fs.ResampleFactor == 0 ) + { + const int FilterLenD2 = fs.FltBank -> getFilterLen() / 2; + const int FilterLenD21 = FilterLenD2 - 1; + + const int ResizeLPix = (int) floor( Vars.o ) - FilterLenD21; + fs.InPrefix = ( ResizeLPix < 0 ? -ResizeLPix : 0 ); + const int ResizeRPix = (int) floor( Vars.o + + ( NewLen - 1 ) * Vars.k ) + FilterLenD2 + 1; + + fs.InSuffix = ( ResizeRPix > fs.InLen ? + ResizeRPix - fs.InLen : 0 ); + + fs.OutLen = NewLen; + fs.RPosBuf = &RPosBufArray.getRPosBuf( Vars.k, Vars.o, + fs.FltBank -> getFracCount() ); + + fillRPosBuf( fs, Vars ); + } + else + { + Vars.k /= fs.ResampleFactor; + Vars.o /= fs.ResampleFactor; + Vars.o += fs.EdgePixelCount; + + fs.InPrefix = fs.FltLatency; + fs.InSuffix = fs.Flt.getCapacity() - fs.FltLatency - 1; + + // Additionally extend OutLen to produce more precise edge + // pixels. + + fs.OutLen = ( fs.InLen + fs.ResampleFactor - 1 ) / + fs.ResampleFactor + fs.EdgePixelCount; + + fs.InSuffix += ( fs.OutLen - 1 ) * fs.ResampleFactor + 1 - + fs.InLen; + + fs.InPrefix += fs.EdgePixelCount * fs.ResampleFactor; + fs.OutLen += fs.EdgePixelCount; + } + + InBuf = fs.OutBuf; + SrcLen = fs.OutLen; + } + + Steps[ Steps.getItemCount() - 1 ].OutBuf = 2; + Vars.IsResize2 = false; + + if( upstep != -1 ) + { + extendUpsample( Steps[ upstep ], Steps[ upstep + 1 ]); + + if( Steps[ upstep ].ResampleFactor == 2 && + Vars.ResizeStep == upstep + 1 && + fpclass :: packmode == 0 && + Steps[ upstep ].FltOrig.getCapacity() > 0 ) + { + // Interpolation with preceeding 2x filterless upsample, + // interleaved resizing only. + + Vars.IsResize2 = true; + } + } + } + + /** + * Function calculates an optimal intermediate buffer length that will + * cover all needs of the specified filtering steps. This function should + * be called after the updateFilterStepBuffers() function. + * + * Function also updates resizing step's RPosBuf pointers to the filter + * bank and SrcOffs values. + * + * @param Steps Filtering steps. + * @param[out] Vars Variables object, will receive buffer size and length. + * @param ResElIncr Resulting (final) element increment, used to produce + * de-interleaved result. For horizontal processing this value is equal + * to last step's OutLen, for vertical processing this value is equal to + * resulting image's width. + */ + + static void updateBufLenAndRPosPtrs( CFilterSteps& Steps, + CImageResizerVars& Vars, const int ResElIncr ) + { + int MaxPrefix[ 2 ] = { 0, 0 }; + int MaxLen[ 2 ] = { 0, 0 }; + int i; + + for( i = 0; i < Steps.getItemCount(); i++ ) + { + CFilterStep& fs = Steps[ i ]; + const int ib = fs.InBuf; + + if( fs.InPrefix > MaxPrefix[ ib ]) + { + MaxPrefix[ ib ] = fs.InPrefix; + } + + int l = fs.InLen + fs.InSuffix; + + if( l > MaxLen[ ib ]) + { + MaxLen[ ib ] = l; + } + + fs.InElIncr = fs.InPrefix + l; + + if( fs.OutBuf == 2 ) + { + break; + } + + const int ob = fs.OutBuf; + + if( fs.IsUpsample ) + { + if( fs.OutPrefix > MaxPrefix[ ob ]) + { + MaxPrefix[ ob ] = fs.OutPrefix; + } + + l = fs.OutLen + fs.OutSuffix; + + if( l > MaxLen[ ob ]) + { + MaxLen[ ob ] = l; + } + } + else + { + if( fs.OutLen > MaxLen[ ob ]) + { + MaxLen[ ob ] = fs.OutLen; + } + } + } + + // Update OutElIncr values of all steps. + + for( i = 0; i < Steps.getItemCount(); i++ ) + { + CFilterStep& fs = Steps[ i ]; + + if( fs.OutBuf == 2 ) + { + fs.OutElIncr = ResElIncr; + break; + } + + CFilterStep& fs2 = Steps[ i + 1 ]; + + if( fs.IsUpsample ) + { + fs.OutElIncr = fs.OutPrefix + fs.OutLen + fs.OutSuffix; + + if( fs.OutElIncr > fs2.InElIncr ) + { + fs2.InElIncr = fs.OutElIncr; + } + else + { + fs.OutElIncr = fs2.InElIncr; + } + } + else + { + fs.OutElIncr = fs2.InElIncr; + } + } + + // Update temporary buffer's length. + + for( i = 0; i < 2; i++ ) + { + Vars.BufLen[ i ] = MaxPrefix[ i ] + MaxLen[ i ]; + Vars.BufOffs[ i ] = MaxPrefix[ i ]; + + if( Vars.packmode == 0 ) + { + Vars.BufOffs[ i ] *= Vars.ElCount; + } + + Vars.BufLen[ i ] *= Vars.ElCount; + } + + // Update RPosBuf pointers and SrcOffs. + + CFilterStep& fs = Steps[ Vars.ResizeStep ]; + typename CFilterStep :: CResizePos* rpos = &(*fs.RPosBuf)[ 0 ]; + const int em = ( fpclass :: packmode == 0 ? Vars.ElCount : 1 ); + const int fl = fs.FltBank -> getFilterLen(); + const int FilterLenD21 = fl / 2 - 1; + + if( Vars.IsResize2 ) + { + for( i = 0; i < fs.OutLen; i++ ) + { + const int p = rpos -> SrcPosInt - FilterLenD21; + const int fo = p & 1; + rpos -> SrcOffs = ( p + fo ) * em; + rpos -> ftp = fs.FltBank -> getFilter( rpos -> fti ) + fo; + rpos -> fl = fl - fo; + rpos++; + } + } + else + { + for( i = 0; i < fs.OutLen; i++ ) + { + rpos -> SrcOffs = ( rpos -> SrcPosInt - FilterLenD21 ) * em; + rpos -> ftp = fs.FltBank -> getFilter( rpos -> fti ); + rpos++; + } + } + } + + /** + * Function modifies the overall (DC) gain of the correction filter in the + * pre-built filtering steps array. + * + * @param Steps Filtering steps. + * @param m Multiplier to apply to the correction filter. + */ + + void modifyCorrFilterDCGain( CFilterSteps& Steps, const double m ) const + { + CBuffer< fptype >* Flt; + const int z = Steps.getItemCount() - 1; + + if( !Steps[ z ].IsUpsample && Steps[ z ].ResampleFactor == 1 ) + { + Flt = &Steps[ z ].Flt; + } + else + { + Flt = &Steps[ 0 ].Flt; + } + + int i; + + for( i = 0; i < Flt -> getCapacity(); i++ ) + { + (*Flt)[ i ] = (fptype) ( (double) (*Flt)[ i ] * m ); + } + } + + /** + * Function builds a map of used fractional delay filters based on the + * resizing positions buffer. + * + * @param fs Resizing step. + * @param[out] UsedFracMap Map of used fractional delay filters. + */ + + static void fillUsedFracMap( const CFilterStep& fs, + CBuffer< uint8_t >& UsedFracMap ) + { + const int FracCount = fs.FltBank -> getFracCount(); + UsedFracMap.increaseCapacity( FracCount, false ); + memset( &UsedFracMap[ 0 ], 0, FracCount * sizeof( UsedFracMap[ 0 ])); + + typename CFilterStep :: CResizePos* rpos = &(*fs.RPosBuf)[ 0 ]; + int i; + + for( i = 0; i < fs.OutLen; i++ ) + { + UsedFracMap[ rpos -> fti ] |= 1; + rpos++; + } + } + + /** + * Function calculates the overall filtering steps complexity per + * scanline. Each complexity unit corresponds to a single multiply-add + * operation. Data copy and pointer math operations are not included in + * this calculation, it is assumed that they correlate to the multiply-add + * operations. Calculation also does not include final rounding, dithering + * and clamping operations since they cannot be optimized out anyway. + * + * Calculation of the CRPosBuf buffer is not included since it cannot be + * avoided. + * + * This function should be called after the updateFilterStepBuffers() + * function. + * + * @param Steps Filtering steps array. + * @param Vars Variables object. + * @param UsedFracMap The map of used fractional delay filters. + * @param ScanlineCount Scanline count. + */ + + static int calcComplexity( const CFilterSteps& Steps, + const CImageResizerVars& Vars, const CBuffer< uint8_t >& UsedFracMap, + const int ScanlineCount ) + { + int fcnum; // Filter complexity multiplier numerator. + int fcdenom; // Filter complexity multiplier denominator. + + if( Vars.packmode != 0 ) + { + fcnum = 1; + fcdenom = 1; + } + else + { + // In interleaved processing mode, filters require 1 less + // multiplication per 2 multiply-add instructions. + + fcnum = 3; + fcdenom = 4; + } + + int s = 0; // Complexity per one scanline. + int s2 = 0; // Complexity per all scanlines. + int i; + + for( i = 0; i < Steps.getItemCount(); i++ ) + { + const CFilterStep& fs = Steps[ i ]; + + s2 += 65 * fs.Flt.getCapacity(); // Filter creation complexity. + + if( fs.IsUpsample ) + { + if( fs.FltOrig.getCapacity() > 0 ) + { + continue; + } + + s += ( fs.Flt.getCapacity() * + ( fs.InPrefix + fs.InLen + fs.InSuffix ) + + fs.SuffixDC.getCapacity() + fs.PrefixDC.getCapacity() ) * + Vars.ElCount; + } + else + if( fs.ResampleFactor == 0 ) + { + s += fs.FltBank -> getFilterLen() * + ( fs.FltBank -> getOrder() + Vars.ElCount ) * fs.OutLen; + + if( i == Vars.ResizeStep && Vars.IsResize2 ) + { + s >>= 1; + } + + s2 += fs.FltBank -> calcInitComplexity( UsedFracMap ); + } + else + { + s += fs.Flt.getCapacity() * Vars.ElCount * fs.OutLen * + fcnum / fcdenom; + } + } + + return( s + s2 / ScanlineCount ); + } + + /** + * @brief Thread-isolated data used for scanline processing. + * + * This structure holds data necessary for image's horizontal or vertical + * scanline processing, including scanline processing queue. + * + * @tparam Tin Source element data type. Intermediate buffers store data + * in floating point format. + * @tparam Tout Destination element data type. Intermediate buffers store + * data in floating point format. + */ + + template< class Tin, class Tout > + class CThreadData : public CImageResizerThreadPool :: CWorkload + { + public: + virtual void process() + { + processScanlineQueue(); + } + + /** + * This enumeration lists possible scanline operations. + */ + + enum EScanlineOperation + { + sopResizeH, ///< Resize horizontal scanline. + ///< + sopResizeV, ///< Resize vertical scanline. + ///< + sopDitherAndUnpackH, ///< Dither and unpack horizontal scanline. + ///< + sopUnpackH ///< Unpack horizontal scanline. + ///< + }; + + /** + * Function initializes *this thread data object and assigns certain + * variables provided by the higher level code. + * + * @param aThreadIndex Index of this thread data (0-based). + * @param aThreadCount Total number of threads used during processing. + * @param aSteps Filtering steps. + * @param aVars Image resizer variables. + */ + + void init( const int aThreadIndex, const int aThreadCount, + const CFilterSteps& aSteps, const CImageResizerVars& aVars ) + { + ThreadIndex = aThreadIndex; + ThreadCount = aThreadCount; + Steps = &aSteps; + Vars = &aVars; + } + + /** + * Function initializes scanline processing queue, and updates + * capacities of intermediate buffers. + * + * @param aOp Operation to perform over scanline. + * @param TotalLines The total number of scanlines that will be + * processed by all threads. + * @param aSrcLen Source scanline length in pixels. + * @param aSrcIncr Source scanline buffer increment. Ignored in + * horizontal scanline processing. + * @param aResIncr Resulting scanline buffer increment. Ignored in + * horizontal scanline processing. + */ + + void initScanlineQueue( const EScanlineOperation aOp, + const int TotalLines, const int aSrcLen, const int aSrcIncr = 0, + const int aResIncr = 0 ) + { + const int l = Vars -> BufLen[ 0 ] + Vars -> BufLen[ 1 ]; + + if( Bufs.getCapacity() < l ) + { + Bufs.alloc( l, fpclass :: fpalign ); + } + + BufPtrs[ 0 ] = Bufs + Vars -> BufOffs[ 0 ]; + BufPtrs[ 1 ] = Bufs + Vars -> BufLen[ 0 ] + Vars -> BufOffs[ 1 ]; + + int j; + int ml = 0; + + for( j = 0; j < Steps -> getItemCount(); j++ ) + { + const CFilterStep& fs = (*Steps)[ j ]; + + if( fs.ResampleFactor == 0 && + ml < fs.FltBank -> getFilterLen() ) + { + ml = fs.FltBank -> getFilterLen(); + } + } + + TmpFltBuf.alloc( ml, fpclass :: fpalign ); + ScanlineOp = aOp; + SrcLen = aSrcLen; + SrcIncr = aSrcIncr; + ResIncr = aResIncr; + QueueLen = 0; + Queue.increaseCapacity(( TotalLines + ThreadCount - 1 ) / + ThreadCount, false ); + } + + /** + * Function adds a scanline to the queue buffer. The + * initScanlineQueue() function should be called before calling this + * function. The number of calls to this add function should not + * exceed the TotalLines spread over all threads. + * + * @param SrcBuf Source scanline buffer. + * @param ResBuf Resulting scanline buffer. + */ + + void addScanlineToQueue( void* const SrcBuf, void* const ResBuf ) + { + Queue[ QueueLen ].SrcBuf = SrcBuf; + Queue[ QueueLen ].ResBuf = ResBuf; + QueueLen++; + } + + /** + * Function processes all queued scanlines. + */ + + void processScanlineQueue() + { + int i; + + switch( ScanlineOp ) + { + case sopResizeH: + { + for( i = 0; i < QueueLen; i++ ) + { + resizeScanlineH( (Tin*) Queue[ i ].SrcBuf, + (fptype*) Queue[ i ].ResBuf ); + } + + break; + } + + case sopResizeV: + { + for( i = 0; i < QueueLen; i++ ) + { + resizeScanlineV( (fptype*) Queue[ i ].SrcBuf, + (fptype*) Queue[ i ].ResBuf ); + } + + break; + } + + case sopDitherAndUnpackH: + { + if( Vars -> UseSRGBGamma ) + { + for( i = 0; i < QueueLen; i++ ) + { + CFilterStep :: applySRGBGamma( + (fptype*) Queue[ i ].SrcBuf, SrcLen, *Vars ); + + Ditherer.dither( (fptype*) Queue[ i ].SrcBuf ); + + CFilterStep :: unpackScanline( + (fptype*) Queue[ i ].SrcBuf, + (Tout*) Queue[ i ].ResBuf, SrcLen, *Vars ); + } + } + else + { + for( i = 0; i < QueueLen; i++ ) + { + Ditherer.dither( (fptype*) Queue[ i ].SrcBuf ); + + CFilterStep :: unpackScanline( + (fptype*) Queue[ i ].SrcBuf, + (Tout*) Queue[ i ].ResBuf, SrcLen, *Vars ); + } + } + + break; + } + + case sopUnpackH: + { + if( Vars -> UseSRGBGamma ) + { + for( i = 0; i < QueueLen; i++ ) + { + CFilterStep :: applySRGBGamma( + (fptype*) Queue[ i ].SrcBuf, SrcLen, *Vars ); + + CFilterStep :: unpackScanline( + (fptype*) Queue[ i ].SrcBuf, + (Tout*) Queue[ i ].ResBuf, SrcLen, *Vars ); + } + } + else + { + for( i = 0; i < QueueLen; i++ ) + { + CFilterStep :: unpackScanline( + (fptype*) Queue[ i ].SrcBuf, + (Tout*) Queue[ i ].ResBuf, SrcLen, *Vars ); + } + } + + break; + } + } + } + + /** + * Function returns ditherer object associated with *this thread data + * object. + */ + + CDitherer& getDitherer() + { + return( Ditherer ); + } + + private: + int ThreadIndex; ///< Thread index. + ///< + int ThreadCount; ///< Thread count. + ///< + const CFilterSteps* Steps; ///< Filtering steps. + ///< + const CImageResizerVars* Vars; ///< Image resizer variables. + ///< + CBuffer< fptype > Bufs; ///< Flip-flop intermediate buffers. + ///< + fptype* BufPtrs[ 3 ]; ///< Flip-flop buffer pointers (referenced by + ///< filtering step's InBuf and OutBuf indices). + ///< + CBuffer< fptype > TmpFltBuf; ///< Temporary buffer used in the + ///< doResize() function, aligned by fpclass :: fpalign. + ///< + EScanlineOperation ScanlineOp; ///< Operation to perform over + ///< scanline. + ///< + int SrcLen; ///< Source scanline length in the last queue. + ///< + int SrcIncr; ///< Source scanline buffer increment in the last queue. + ///< + int ResIncr; ///< Resulting scanline buffer increment in the last + ///< queue. + ///< + CDitherer Ditherer; ///< Ditherer object to use. + ///< + + /** + * @brief Scanline processing queue item. + * + * Scanline processing queue item. + */ + + struct CQueueItem + { + void* SrcBuf; ///< Source scanline buffer, will by typecasted to + ///< Tin or fptype*. + ///< + void* ResBuf; ///< Resulting scanline buffer, will by typecasted + ///< to Tout or fptype*. + ///< + }; + + CBuffer< CQueueItem > Queue; ///< Scanline processing queue. + ///< + int QueueLen; ///< Queue length. + ///< + + /** + * Function resizes a single horizontal scanline. + * + * @param SrcBuf Source scanline buffer. Can be either horizontal or + * vertical. + * @param ResBuf Resulting scanline buffer. + */ + + void resizeScanlineH( const Tin* const SrcBuf, fptype* const ResBuf ) + { + const CFilterStep& fs0 = (*Steps)[ 0 ]; + + fs0.packScanline( SrcBuf, BufPtrs[ 0 ], SrcLen ); + BufPtrs[ 2 ] = ResBuf; + + fptype ElBiases[ 4 ]; + fs0.calcScanlineBias( BufPtrs[ 0 ], SrcLen, ElBiases ); + fs0.unbiasScanline( BufPtrs[ 0 ], SrcLen, ElBiases ); + + int j; + + for( j = 0; j < Steps -> getItemCount(); j++ ) + { + const CFilterStep& fs = (*Steps)[ j ]; + fs.prepareInBuf( BufPtrs[ fs.InBuf ]); + const int DstIncr = + ( Vars -> packmode == 0 ? Vars -> ElCount : 1 ); + + if( fs.ResampleFactor != 0 ) + { + if( fs.IsUpsample ) + { + fs.doUpsample( BufPtrs[ fs.InBuf ], + BufPtrs[ fs.OutBuf ]); + } + else + { + fs.doFilter( BufPtrs[ fs.InBuf ], + BufPtrs[ fs.OutBuf ], DstIncr ); + } + } + else + { + if( Vars -> IsResize2 ) + { + fs.doResize2( BufPtrs[ fs.InBuf ], + BufPtrs[ fs.OutBuf ], DstIncr, ElBiases, + TmpFltBuf ); + } + else + { + fs.doResize( BufPtrs[ fs.InBuf ], + BufPtrs[ fs.OutBuf ], DstIncr, ElBiases, + TmpFltBuf ); + } + } + } + } + + /** + * Function resizes a single vertical scanline. + * + * @param SrcBuf Source scanline buffer. Can be either horizontal or + * vertical. + * @param ResBuf Resulting scanline buffer. + */ + + void resizeScanlineV( const fptype* const SrcBuf, + fptype* const ResBuf ) + { + const CFilterStep& fs0 = (*Steps)[ 0 ]; + + fs0.convertVtoH( SrcBuf, BufPtrs[ 0 ], SrcLen, SrcIncr ); + BufPtrs[ 2 ] = ResBuf; + + fptype ElBiases[ 4 ]; + fs0.calcScanlineBias( BufPtrs[ 0 ], SrcLen, ElBiases ); + fs0.unbiasScanline( BufPtrs[ 0 ], SrcLen, ElBiases ); + + int j; + + for( j = 0; j < Steps -> getItemCount(); j++ ) + { + const CFilterStep& fs = (*Steps)[ j ]; + fs.prepareInBuf( BufPtrs[ fs.InBuf ]); + const int DstIncr = ( fs.OutBuf == 2 ? ResIncr : + ( Vars -> packmode == 0 ? Vars -> ElCount : 1 )); + + if( fs.ResampleFactor != 0 ) + { + if( fs.IsUpsample ) + { + fs.doUpsample( BufPtrs[ fs.InBuf ], + BufPtrs[ fs.OutBuf ]); + } + else + { + fs.doFilter( BufPtrs[ fs.InBuf ], + BufPtrs[ fs.OutBuf ], DstIncr ); + } + } + else + { + if( Vars -> IsResize2 ) + { + fs.doResize2( BufPtrs[ fs.InBuf ], + BufPtrs[ fs.OutBuf ], DstIncr, ElBiases, + TmpFltBuf ); + } + else + { + fs.doResize( BufPtrs[ fs.InBuf ], + BufPtrs[ fs.OutBuf ], DstIncr, ElBiases, + TmpFltBuf ); + } + } + } + } + }; +}; + +#undef AVIR_PI +#undef AVIR_PId2 +#undef AVIR_NOCTOR + +} // namespace avir + +#endif // AVIR_CIMAGERESIZER_INCLUDED diff --git a/Common/Libs/avir/avir_dil.h b/Common/Libs/avir/avir_dil.h new file mode 100644 index 00000000..14b97be4 --- /dev/null +++ b/Common/Libs/avir/avir_dil.h @@ -0,0 +1,1090 @@ +//$ nobt +//$ nocpp + +/** + * @file avir_dil.h + * + * @brief Inclusion file for de-interleaved image resizing functions. + * + * This file includes the "CImageResizerFilterStepDIL" class which implements + * image resizing functions in de-interleaved mode. + * + * AVIR Copyright (c) 2015-2021 Aleksey Vaneev + */ + +namespace avir { + +/** + * @brief De-interleaved filtering steps implementation class. + * + * This class implements scanline filtering functions in de-interleaved mode. + * This means that pixels are processed in groups. + * + * @tparam fptype Floating point type to use for storing pixel elements. + * SIMD types cannot be used. + * @tparam fptypesimd The SIMD type used to store a pack of "fptype" values. + */ + +template< class fptype, class fptypesimd > +class CImageResizerFilterStepDIL : + public CImageResizerFilterStep< fptype, fptype > +{ +public: + using CImageResizerFilterStep< fptype, fptype > :: IsUpsample; + using CImageResizerFilterStep< fptype, fptype > :: ResampleFactor; + using CImageResizerFilterStep< fptype, fptype > :: Flt; + using CImageResizerFilterStep< fptype, fptype > :: FltOrig; + using CImageResizerFilterStep< fptype, fptype > :: FltLatency; + using CImageResizerFilterStep< fptype, fptype > :: Vars; + using CImageResizerFilterStep< fptype, fptype > :: InLen; + using CImageResizerFilterStep< fptype, fptype > :: InPrefix; + using CImageResizerFilterStep< fptype, fptype > :: InSuffix; + using CImageResizerFilterStep< fptype, fptype > :: InElIncr; + using CImageResizerFilterStep< fptype, fptype > :: OutLen; + using CImageResizerFilterStep< fptype, fptype > :: OutPrefix; + using CImageResizerFilterStep< fptype, fptype > :: OutSuffix; + using CImageResizerFilterStep< fptype, fptype > :: OutElIncr; + using CImageResizerFilterStep< fptype, fptype > :: PrefixDC; + using CImageResizerFilterStep< fptype, fptype > :: SuffixDC; + using CImageResizerFilterStep< fptype, fptype > :: RPosBuf; + using CImageResizerFilterStep< fptype, fptype > :: FltBank; + using CImageResizerFilterStep< fptype, fptype > :: EdgePixelCount; + + /** + * Function performs "packing" (de-interleaving) of a scanline and type + * conversion. If required, the sRGB gamma correction is applied. + * + * @param ip0 Input scanline, pixel elements interleaved. + * @param op0 Output scanline, pixel elements are grouped, "l" elements + * apart. + * @param l The number of pixels to "pack". + */ + + template< class Tin > + void packScanline( const Tin* const ip0, fptype* const op0, + const int l ) const + { + const int ElCount = Vars -> ElCount; + int j; + + if( !Vars -> UseSRGBGamma ) + { + for( j = 0; j < ElCount; j++ ) + { + const Tin* ip = ip0 + j; + fptype* const op = op0 + j * InElIncr; + int i; + + for( i = 0; i < l; i++ ) + { + op[ i ] = (fptype) *ip; + ip += ElCount; + } + } + } + else + { + const fptype gm = (fptype) Vars -> InGammaMult; + + for( j = 0; j < ElCount; j++ ) + { + const Tin* ip = ip0 + j; + fptype* const op = op0 + j * InElIncr; + int i; + + for( i = 0; i < l; i++ ) + { + op[ i ] = convertSRGB2Lin( (fptype) *ip * gm ); + ip += ElCount; + } + } + } + } + + /** + * Function applies Linear to sRGB gamma correction to the specified + * scanline. + * + * @param p Scanline. + * @param l The number of pixels to de-linearize. + * @param Vars0 Image resizing-related variables. + */ + + static void applySRGBGamma( fptype* const p0, const int l, + const CImageResizerVars& Vars0 ) + { + const int ElCount = Vars0.ElCount; + const fptype gm = (fptype) Vars0.OutGammaMult; + int j; + + for( j = 0; j < ElCount; j++ ) + { + fptype* const p = p0 + j * l; + int i; + + for( i = 0; i < l; i++ ) + { + p[ i ] = convertLin2SRGB( p[ i ]) * gm; + } + } + } + + /** + * Function converts vertical scanline to horizontal scanline. This + * function is called by the image resizer when image is resized + * vertically. This means that the vertical scanline is stored in the + * same format produced by the packScanline() and maintained by other + * filtering functions. + * + * @param ip Input vertical scanline, pixel elements are grouped, SrcLen + * elements apart. + * @param op Output buffer (temporary buffer used during resizing), pixel + * elements are grouped, "l" elements apart. + * @param SrcLen The number of pixels in the input scanline, also used to + * calculate input buffer increment. + * @param SrcIncr Input buffer increment to the next vertical pixel. + */ + + void convertVtoH( const fptype* ip, fptype* op, const int SrcLen, + const int SrcIncr ) const + { + const int ElCount = Vars -> ElCount; + const int SrcElIncr = SrcIncr / ElCount; + const int ips1 = SrcElIncr; + const int ips2 = SrcElIncr * 2; + const int ips3 = SrcElIncr * 3; + const int ops1 = InElIncr; + const int ops2 = InElIncr * 2; + const int ops3 = InElIncr * 3; + int j; + + if( ElCount == 1 ) + { + for( j = 0; j < SrcLen; j++ ) + { + op[ 0 ] = ip[ 0 ]; + ip += SrcIncr; + op++; + } + } + else + if( ElCount == 4 ) + { + for( j = 0; j < SrcLen; j++ ) + { + op[ 0 ] = ip[ 0 ]; + op[ ops1 ] = ip[ ips1 ]; + op[ ops2 ] = ip[ ips2 ]; + op[ ops3 ] = ip[ ips3 ]; + ip += SrcIncr; + op++; + } + } + else + if( ElCount == 3 ) + { + for( j = 0; j < SrcLen; j++ ) + { + op[ 0 ] = ip[ 0 ]; + op[ ops1 ] = ip[ ips1 ]; + op[ ops2 ] = ip[ ips2 ]; + ip += SrcIncr; + op++; + } + } + else + if( ElCount == 2 ) + { + for( j = 0; j < SrcLen; j++ ) + { + op[ 0 ] = ip[ 0 ]; + op[ ops1 ] = ip[ ips1 ]; + ip += SrcIncr; + op++; + } + } + } + + /** + * Function performs "unpacking" of a scanline and type conversion + * (truncation is used when floating point is converted to integer). + * The unpacking function assumes that scanline is stored in the style + * produced by the packScanline() function. + * + * @param ip0 Input scanline, pixel elements are grouped, "l" elements + * apart. + * @param op0 Output scanline, pixel elements are interleaved. + * @param l The number of pixels to "unpack". + * @param Vars0 Image resizing-related variables. ElCount is assumed to be + * equal to ElCountIO. + */ + + template< class Tout > + static void unpackScanline( const fptype* const ip0, Tout* const op0, + const int l, const CImageResizerVars& Vars0 ) + { + const int ElCount = Vars0.ElCount; + int j; + + for( j = 0; j < ElCount; j++ ) + { + const fptype* const ip = ip0 + j * l; + Tout* op = op0 + j; + int i; + + for( i = 0; i < l; i++ ) + { + *op = (Tout) ip[ i ]; + op += ElCount; + } + } + } + + /** + * Function calculates scanline's DC gain for each channel, further used + * to "unbias" the scanline. + * + * @param p0 Source scanline. + * @param SrcLen Source scanline's length. + * @param[out] ElBiases Resuling biases. + */ + + void calcScanlineBias( const fptype* const p0, const int SrcLen, + fptype* const ElBiases ) const + { + const int ElCount = Vars -> ElCount; + int j; + + for( j = 0; j < ElCount; j++ ) + { + const fptype* const p = p0 + j * InElIncr; + fptype b = (fptype) 0; + int i; + + for( i = 0; i < SrcLen; i++ ) + { + b += p[ i ]; + } + + ElBiases[ j ] = b / (fptype) SrcLen; + } + } + + /** + * Function applies "unbiasing" to the scanline, by subtracting the + * previously calculated bias (DC gain) values. + * + * @param p0 Scanline. + * @param l Scanline's length. + * @param ElBiases Biases to subtract, for each channel. + */ + + void unbiasScanline( fptype* const p0, const int l, + const fptype* const ElBiases ) const + { + const int ElCount = Vars -> ElCount; + int j; + + for( j = 0; j < ElCount; j++ ) + { + fptype* const p = p0 + j * InElIncr; + const fptype b = ElBiases[ j ]; + int i; + + for( i = 0; i < l; i++ ) + { + p[ i ] -= b; + } + } + } + + /** + * Function prepares input scanline buffer for *this filtering step. + * Left- and right-most pixels are replicated to make sure no buffer + * overrun happens. Such approach also allows to bypass any pointer + * range checks. + * + * @param Src Source buffer. + */ + + void prepareInBuf( fptype* Src ) const + { + if( IsUpsample || InPrefix + InSuffix == 0 ) + { + return; + } + + int j; + + for( j = 0; j < Vars -> ElCount; j++ ) + { + replicateArray( Src, 1, Src - InPrefix, InPrefix, 1 ); + fptype* const Src2 = Src + InLen - 1; + replicateArray( Src2, 1, Src2 + 1, InSuffix, 1 ); + Src += InElIncr; + } + } + + /** + * Function peforms scanline upsampling with filtering. + * + * @param Src Source scanline buffer (length = this -> InLen). Source + * scanline increment will be equal to ElCount. + * @param Dst Destination scanline buffer. + */ + + void doUpsample( const fptype* Src, fptype* Dst ) const + { + const int elalign = Vars -> elalign; + const int opstep = ResampleFactor; + const fptype* const f = Flt; + const int flen = Flt.getCapacity(); + int l; + int i; + int j; + + for( j = 0; j < Vars -> ElCount; j++ ) + { + const fptype* ip = Src; + fptype* op0 = &Dst[ -OutPrefix ]; + memset( op0, 0, ( OutPrefix + OutLen + OutSuffix ) * + sizeof( fptype )); + + if( FltOrig.getCapacity() > 0 ) + { + // Do not perform filtering, only upsample. + + op0 += OutPrefix % ResampleFactor; + l = OutPrefix / ResampleFactor; + + while( l > 0 ) + { + op0[ 0 ] = ip[ 0 ]; + op0 += opstep; + l--; + } + + l = InLen - 1; + + while( l > 0 ) + { + op0[ 0 ] = ip[ 0 ]; + op0 += opstep; + ip++; + l--; + } + + l = OutSuffix / ResampleFactor; + + while( l >= 0 ) + { + op0[ 0 ] = ip[ 0 ]; + op0 += opstep; + l--; + } + + Src += InElIncr; + Dst += OutElIncr; + continue; + } + + l = InPrefix; + fptypesimd ipv = (fptypesimd) ip[ 0 ]; + + while( l > 0 ) + { + for( i = 0; i < flen; i += elalign ) + { + fptypesimd :: addu( op0 + i, + fptypesimd :: load( f + i ) * ipv ); + } + + op0 += opstep; + l--; + } + + l = InLen - 1; + + while( l > 0 ) + { + ipv = (fptypesimd) ip[ 0 ]; + + for( i = 0; i < flen; i += elalign ) + { + fptypesimd :: addu( op0 + i, + fptypesimd :: load( f + i ) * ipv ); + } + + ip++; + op0 += opstep; + l--; + } + + l = InSuffix; + ipv = (fptypesimd) ip[ 0 ]; + + while( l >= 0 ) + { + for( i = 0; i < flen; i += elalign ) + { + fptypesimd :: addu( op0 + i, + fptypesimd :: load( f + i ) * ipv ); + } + + op0 += opstep; + l--; + } + + const fptype* dc = SuffixDC; + l = SuffixDC.getCapacity(); + + for( i = 0; i < l; i += elalign ) + { + fptypesimd :: addu( op0 + i, + fptypesimd :: load( dc + i ) * ipv ); + } + + ipv = (fptypesimd) Src[ 0 ]; + op0 = Dst - InPrefix * opstep; + dc = PrefixDC; + l = PrefixDC.getCapacity(); + + for( i = 0; i < l; i += elalign ) + { + fptypesimd :: addu( op0 + i, + fptypesimd :: load( dc + i ) * ipv ); + } + + Src += InElIncr; + Dst += OutElIncr; + } + } + + /** + * Function peforms scanline filtering with optional downsampling. + * Function makes use of the symmetry of the filter. + * + * @param Src Source scanline buffer (length = this -> InLen). Source + * scanline increment will be equal to 1. + * @param Dst Destination scanline buffer. + * @param DstIncr Destination scanline buffer increment, used for + * horizontal or vertical scanline stepping. + */ + + void doFilter( const fptype* const Src, fptype* Dst, + const int DstIncr ) const + { + const int ElCount = Vars -> ElCount; + const int elalign = Vars -> elalign; + const fptype* const f = &Flt[ 0 ]; + const int flen = Flt.getCapacity(); + const int ipstep = ResampleFactor; + int i; + int j; + + if( ElCount == 1 ) + { + const fptype* ip = Src - EdgePixelCount * ipstep - FltLatency; + fptype* op = Dst; + int l = OutLen; + + while( l > 0 ) + { + fptypesimd s = fptypesimd :: load( f ) * + fptypesimd :: loadu( ip ); + + for( i = elalign; i < flen; i += elalign ) + { + s += fptypesimd :: load( f + i ) * + fptypesimd :: loadu( ip + i ); + } + + op[ 0 ] = s.hadd(); + op += DstIncr; + ip += ipstep; + l--; + } + } + else + if( DstIncr == 1 ) + { + for( j = 0; j < ElCount; j++ ) + { + const fptype* ip = Src - EdgePixelCount * ipstep - + FltLatency + j * InElIncr; + + fptype* op = Dst + j * OutElIncr; + int l = OutLen; + + while( l > 0 ) + { + fptypesimd s = fptypesimd :: load( f ) * + fptypesimd :: loadu( ip ); + + for( i = elalign; i < flen; i += elalign ) + { + s += fptypesimd :: load( f + i ) * + fptypesimd :: loadu( ip + i ); + } + + op[ 0 ] = s.hadd(); + op += DstIncr; + ip += ipstep; + l--; + } + } + } + else + { + const fptype* ip0 = Src - EdgePixelCount * ipstep - FltLatency; + fptype* op0 = Dst; + int l = OutLen; + + while( l > 0 ) + { + const fptype* ip = ip0; + fptype* op = op0; + + for( j = 0; j < ElCount; j++ ) + { + fptypesimd s = fptypesimd :: load( f ) * + fptypesimd :: loadu( ip ); + + for( i = elalign; i < flen; i += elalign ) + { + s += fptypesimd :: load( f + i ) * + fptypesimd :: loadu( ip + i ); + } + + op[ 0 ] = s.hadd(); + ip += InElIncr; + op += OutElIncr; + } + + ip0 += ipstep; + op0 += DstIncr; + l--; + } + } + } + + /** + * Function performs resizing of a single scanline. This function does + * not "know" about the length of the source scanline buffer. This buffer + * should be padded with enough pixels so that ( SrcPos - FilterLenD2 ) is + * always >= 0 and ( SrcPos + ( DstLineLen - 1 ) * k + FilterLenD2 + 1 ) + * does not exceed source scanline's buffer length. SrcLine's increment is + * assumed to be equal to 1. + * + * @param SrcLine Source scanline buffer. + * @param DstLine Destination (resized) scanline buffer. + * @param DstLineIncr Destination scanline position increment, used for + * horizontal or vertical scanline stepping. + * @param ElBiases Bias values to add to the resulting scanline. + * @param xx Temporary buffer, of size FltBank -> getFilterLen(), must be + * aligned by fpclass :: fpalign. + */ + + void doResize( const fptype* SrcLine, fptype* DstLine, + int DstLineIncr, const fptype* const ElBiases, + fptype* const xx ) const + { + const int IntFltLen = FltBank -> getFilterLen(); + const int ElCount = Vars -> ElCount; + const int elalign = Vars -> elalign; + const typename CImageResizerFilterStep< fptype, fptype > :: + CResizePos* rpos = &(*RPosBuf)[ 0 ]; + + int DstLineLen = OutLen; + int i; + int j; + +#define AVIR_RESIZE_PART1 \ + while( DstLineLen > 0 ) \ + { \ + const fptypesimd x = (fptypesimd) rpos -> x; \ + const fptype* ftp = rpos -> ftp; \ + const fptype* ftp2 = rpos -> ftp + IntFltLen; \ + const fptype* Src = SrcLine + rpos -> SrcOffs; + +#define AVIR_RESIZE_PART1nx \ + while( DstLineLen > 0 ) \ + { \ + const fptype* ftp = rpos -> ftp; \ + const fptype* Src = SrcLine + rpos -> SrcOffs; + +#define AVIR_RESIZE_PART2 \ + DstLine += DstLineIncr; \ + rpos++; \ + DstLineLen--; \ + } + + if( ElCount == 1 ) + { + const fptype b = ElBiases[ 0 ]; + + if( FltBank -> getOrder() == 1 ) + { + AVIR_RESIZE_PART1 + + fptypesimd sum = ( fptypesimd :: load( ftp ) + + fptypesimd :: load( ftp2 ) * x ) * + fptypesimd :: loadu( Src ); + + for( i = elalign; i < IntFltLen; i += elalign ) + { + sum += ( fptypesimd :: load( ftp + i ) + + fptypesimd :: load( ftp2 + i ) * x ) * + fptypesimd :: loadu( Src + i ); + } + + DstLine[ 0 ] = sum.hadd() + b; + + AVIR_RESIZE_PART2 + } + else + { + AVIR_RESIZE_PART1nx + + fptypesimd sum = fptypesimd :: load( ftp ) * + fptypesimd :: loadu( Src ); + + for( i = elalign; i < IntFltLen; i += elalign ) + { + sum += fptypesimd :: load( ftp + i ) * + fptypesimd :: loadu( Src + i ); + } + + DstLine[ 0 ] = sum.hadd() + b; + + AVIR_RESIZE_PART2 + } + } + else + if( DstLineIncr == 1 ) + { + // Horizontal-oriented processing, element loop is outer. + + const int SrcIncr = InElIncr; + const int DstLineElIncr = OutElIncr - DstLineIncr * DstLineLen; + + if( FltBank -> getOrder() == 1 ) + { + for( j = 0; j < ElCount; j++ ) + { + const fptype b = ElBiases[ j ]; + + AVIR_RESIZE_PART1 + + fptypesimd sum = 0.0; + + for( i = 0; i < IntFltLen; i += elalign ) + { + sum += ( fptypesimd :: load( ftp + i ) + + fptypesimd :: load( ftp2 + i ) * x ) * + fptypesimd :: loadu( Src + i ); + } + + DstLine[ 0 ] = sum.hadd() + b; + + AVIR_RESIZE_PART2 + + DstLine += DstLineElIncr; + SrcLine += SrcIncr; + DstLineLen = OutLen; + rpos = &(*RPosBuf)[ 0 ]; + } + } + else + { + for( j = 0; j < ElCount; j++ ) + { + const fptype b = ElBiases[ j ]; + + AVIR_RESIZE_PART1nx + + fptypesimd sum = fptypesimd :: load( ftp ) * + fptypesimd :: loadu( Src ); + + for( i = elalign; i < IntFltLen; i += elalign ) + { + sum += fptypesimd :: load( ftp + i ) * + fptypesimd :: loadu( Src + i ); + } + + DstLine[ 0 ] = sum.hadd() + b; + + AVIR_RESIZE_PART2 + + DstLine += DstLineElIncr; + SrcLine += SrcIncr; + DstLineLen = OutLen; + rpos = &(*RPosBuf)[ 0 ]; + } + } + } + else + { + const int SrcIncr = InElIncr; + const int DstLineElIncr = OutElIncr; + DstLineIncr -= DstLineElIncr * ElCount; + + if( FltBank -> getOrder() == 1 ) + { + AVIR_RESIZE_PART1 + + for( i = 0; i < IntFltLen; i += elalign ) + { + ( fptypesimd :: load( ftp + i ) + + fptypesimd :: load( ftp2 + i ) * x ).store( xx + i ); + } + + for( j = 0; j < ElCount; j++ ) + { + fptypesimd sum = fptypesimd :: load( xx ) * + fptypesimd :: loadu( Src ); + + for( i = elalign; i < IntFltLen; i += elalign ) + { + sum += fptypesimd :: load( xx + i ) * + fptypesimd :: loadu( Src + i ); + } + + DstLine[ 0 ] = sum.hadd() + ElBiases[ j ]; + DstLine += DstLineElIncr; + Src += SrcIncr; + } + + AVIR_RESIZE_PART2 + } + else + { + AVIR_RESIZE_PART1nx + + for( j = 0; j < ElCount; j++ ) + { + fptypesimd sum = fptypesimd :: load( ftp ) * + fptypesimd :: loadu( Src ); + + for( i = elalign; i < IntFltLen; i += elalign ) + { + sum += fptypesimd :: load( ftp + i ) * + fptypesimd :: loadu( Src + i ); + } + + DstLine[ 0 ] = sum.hadd() + ElBiases[ j ]; + DstLine += DstLineElIncr; + Src += SrcIncr; + } + + AVIR_RESIZE_PART2 + } + } + +#undef AVIR_RESIZE_PART2 +#undef AVIR_RESIZE_PART1nx +#undef AVIR_RESIZE_PART1 + } + + /** + * Same as doResize(). No specific 2x filter-less upsampling + * optimization. + */ + + void doResize2( const fptype* SrcLine, fptype* DstLine, + int DstLineIncr, const fptype* const ElBiases, + fptype* const xx ) const + { + doResize( SrcLine, DstLine, DstLineIncr, ElBiases, xx ); + } +}; + +/** + * @brief Image resizer's default de-interleaved dithering class. + * + * This class defines an object that performs rounding, clipping and dithering + * operations over horizontal scanline pixels before scanline is stored in the + * output buffer. + * + * This ditherer implementation uses de-interleaved SIMD algorithm. + * + * @tparam fptype Floating point type to use for storing pixel data. SIMD + * types cannot be used. + * @tparam fptypesimd The SIMD type used to store a pack of "fptype" values. + */ + +template< class fptype, class fptypesimd > +class CImageResizerDithererDefDIL +{ +public: + /** + * Function initializes the ditherer object. + * + * @param aLen Scanline length in pixels to process. + * @param aVars Image resizing-related variables. + * @param aTrMul Bit-depth truncation multiplier. 1 - no additional + * truncation. + * @param aPkOut Peak output value allowed. + */ + + void init( const int aLen, const CImageResizerVars& aVars, + const double aTrMul, const double aPkOut ) + { + Len = aLen; + Vars = &aVars; + LenE = aLen * Vars -> ElCount; + TrMul0 = aTrMul; + PkOut0 = aPkOut; + } + + /** + * @return "True" if dithering is recursive relative to scanlines meaning + * multi-threaded execution is not supported by this dithering method. + */ + + static bool isRecursive() + { + return( false ); + } + + /** + * Function performs rounding and clipping operations. + * + * @param ResScanline The buffer containing the final scanline. + */ + + void dither( fptype* const ResScanline ) const + { + const int elalign = Vars -> elalign; + const fptypesimd c0 = 0.0; + const fptypesimd PkOut = (fptypesimd) PkOut0; + int j; + + if( TrMul0 == 1.0 ) + { + // Optimization - do not perform bit truncation. + + for( j = 0; j < LenE - elalign; j += elalign ) + { + const fptypesimd z0 = round( + fptypesimd :: loadu( ResScanline + j )); + + clamp( z0, c0, PkOut ).storeu( ResScanline + j ); + } + + const int lim = LenE - j; + const fptypesimd z0 = round( + fptypesimd :: loadu( ResScanline + j, lim )); + + clamp( z0, c0, PkOut ).storeu( ResScanline + j, lim ); + } + else + { + const fptypesimd TrMul = (fptypesimd) TrMul0; + + for( j = 0; j < LenE - elalign; j += elalign ) + { + const fptypesimd z0 = round( + fptypesimd :: loadu( ResScanline + j ) / TrMul ) * TrMul; + + clamp( z0, c0, PkOut ).storeu( ResScanline + j ); + } + + const int lim = LenE - j; + const fptypesimd z0 = round( + fptypesimd :: loadu( ResScanline + j, lim ) / TrMul ) * TrMul; + + clamp( z0, c0, PkOut ).storeu( ResScanline + j, lim ); + } + } + +protected: + int Len; ///< Scanline's length in pixels. + ///< + const CImageResizerVars* Vars; ///< Image resizing-related variables. + ///< + int LenE; ///< = LenE * ElCount. + ///< + double TrMul0; ///< Bit-depth truncation multiplier. + ///< + double PkOut0; ///< Peak output value allowed. + ///< +}; + +/** + * @brief Image resizer's error-diffusion dithering class, de-interleaved + * mode. + * + * This ditherer implements error-diffusion dithering which looks good, and + * whose results are compressed by PNG well. + * + * @tparam fptype Floating point type to use for storing pixel data. SIMD + * types cannot be used. + * @tparam fptypesimd Processing type, SIMD can be used. + */ + +template< class fptype, class fptypesimd > +class CImageResizerDithererErrdDIL +{ +public: + /** + * Function initializes the ditherer object. + * + * @param aLen Scanline length in pixels to process. + * @param aVars Image resizing-related variables. + * @param aTrMul Bit-depth truncation multiplier. 1 - no additional + * truncation. + * @param aPkOut Peak output value allowed. + */ + + void init( const int aLen, const CImageResizerVars& aVars, + const double aTrMul, const double aPkOut ) + { + Len = aLen; + Vars = &aVars; + LenE = aLen * Vars -> ElCount; + TrMul0 = aTrMul; + PkOut0 = aPkOut; + + ResScanlineDith0.alloc( LenE + Vars -> ElCount, sizeof( fptype )); + ResScanlineDith = ResScanlineDith0 + Vars -> ElCount; + int i; + + for( i = 0; i < LenE + Vars -> ElCount; i++ ) + { + ResScanlineDith0[ i ] = 0.0; + } + } + + static bool isRecursive() + { + return( true ); + } + + void dither( fptype* const ResScanline ) + { + const int ea = Vars -> elalign; + const fptypesimd c0 = 0.0; + const fptypesimd TrMul = (fptypesimd) TrMul0; + const fptypesimd PkOut = (fptypesimd) PkOut0; + int j; + + for( j = 0; j < LenE - ea; j += ea ) + { + fptypesimd :: addu( ResScanline + j, + fptypesimd :: loadu( ResScanlineDith + j )); + + c0.storeu( ResScanlineDith + j ); + } + + int lim = LenE - j; + fptypesimd :: addu( ResScanline + j, + fptypesimd :: loadu( ResScanlineDith + j, lim ), lim ); + + c0.storeu( ResScanlineDith + j, lim ); + + const int Len1 = Len - 1; + fptype* rs = ResScanline; + fptype* rsd = ResScanlineDith; + int i; + + for( i = 0; i < Vars -> ElCount; i++ ) + { + for( j = 0; j < Len1; j++ ) + { + // Perform rounding, noise estimation and saturation. + + fptype* const rsj = rs + j; + const fptype z0 = round( rsj[ 0 ] / TrMul ) * TrMul; + const fptype Noise = rsj[ 0 ] - z0; + rsj[ 0 ] = clamp( z0, (fptype) 0.0, PkOut ); + + fptype* const rsdj = rsd + j; + rsj[ 1 ] += Noise * (fptype) 0.364842; + rsdj[ -1 ] += Noise * (fptype) 0.207305; + rsdj[ 0 ] += Noise * (fptype) 0.364842; + rsdj[ 1 ] += Noise * (fptype) 0.063011; + } + + // Process the last pixel element in scanline. + + const fptype z1 = round( rs[ Len1 ] / TrMul ) * TrMul; + const fptype Noise2 = rs[ Len1 ] - z1; + rs[ Len1 ] = clamp( z1, c0, PkOut ); + + rsd[ Len1 - 1 ] += Noise2 * (fptype) 0.207305; + rsd[ Len1 ] += Noise2 * (fptype) 0.364842; + + rs += Len; + rsd += Len; + } + } + +protected: + int Len; ///< Scanline's length in pixels. + ///< + const CImageResizerVars* Vars; ///< Image resizing-related variables. + ///< + int LenE; ///< = LenE * ElCount. + ///< + double TrMul0; ///< Bit-depth truncation multiplier. + ///< + double PkOut0; ///< Peak output value allowed. + ///< + CBuffer< fptype > ResScanlineDith0; ///< Error propagation buffer for + ///< dithering, first pixel unused. + ///< + fptype* ResScanlineDith; ///< Error propagation buffer pointer which skips + ///< the first ElCount elements. + ///< +}; + +/** + * @brief Floating-point processing definition and abstraction class for + * de-interleaved processing. + * + * This class defines several constants and typedefs that point to classes + * that should be used by the image resizing algorithm. This implementation + * points to de-interleaved processing classes. + * + * @tparam afptype Floating point type to use for storing intermediate data + * and variables. SIMD types should not be used. + * @tparam afptypesimd SIMD type used to perform processing. + * @tparam adith Ditherer class to use during processing. + */ + +template< class afptype, class afptypesimd, + class adith = CImageResizerDithererDefDIL< afptype, afptypesimd > > +class fpclass_def_dil +{ +public: + typedef afptype fptype; ///< Floating-point type to use during processing. + ///< + typedef afptype fptypeatom; ///< Atomic type "fptype" consists of. + ///< + static const int fppack = 1; ///< The number of atomic types stored in a + ///< single "fptype" element. + ///< + static const int fpalign = sizeof( afptypesimd ); ///< Suggested alignment + ///< size in bytes. This is not a required alignment, because image + ///< resizing algorithm cannot be made to have a strictly aligned data + ///< access in all cases (e.g. de-interleaved interpolation cannot + ///< perform aligned accesses). + ///< + static const int elalign = sizeof( afptypesimd ) / sizeof( afptype ); ///< + ///< Length alignment of arrays of elements. This applies to filters + ///< and intermediate buffers: this constant forces filters and + ///< scanlines to have a length which is a multiple of this value, for + ///< more efficient SIMD implementation. + ///< + static const int packmode = 1; ///< 0 if interleaved packing, 1 if + ///< de-interleaved. + ///< + typedef CImageResizerFilterStepDIL< fptype, afptypesimd > CFilterStep; ///< + ///< Filtering step class to use during processing. + ///< + typedef adith CDitherer; ///< Ditherer class to use during processing. + ///< +}; + +} // namespace avir diff --git a/Common/Libs/avir/avir_float4_sse.h b/Common/Libs/avir/avir_float4_sse.h new file mode 100644 index 00000000..6a7d23b1 --- /dev/null +++ b/Common/Libs/avir/avir_float4_sse.h @@ -0,0 +1,319 @@ +//$ nobt +//$ nocpp + +/** + * @file avir_float4_sse.h + * + * @brief Inclusion file for the "float4" type. + * + * This file includes the "float4" SSE-based type used for SIMD variable + * storage and processing. + * + * AVIR Copyright (c) 2015-2020 Aleksey Vaneev + */ + +#ifndef AVIR_FLOAT4_SSE_INCLUDED +#define AVIR_FLOAT4_SSE_INCLUDED + +#include +#include + +namespace avir { + +/** + * @brief SIMD packed 4-float type. + * + * This class implements a packed 4-float type that can be used to perform + * parallel computation using SIMD instructions on SSE-enabled processors. + * This class can be used as the "fptype" argument of the avir::fpclass_def + * class. + */ + +class float4 +{ +public: + float4() + { + } + + float4( const float4& s ) + : value( s.value ) + { + } + + float4( const __m128 s ) + : value( s ) + { + } + + float4( const float s ) + : value( _mm_set1_ps( s )) + { + } + + float4& operator = ( const float4& s ) + { + value = s.value; + return( *this ); + } + + float4& operator = ( const __m128 s ) + { + value = s; + return( *this ); + } + + float4& operator = ( const float s ) + { + value = _mm_set1_ps( s ); + return( *this ); + } + + operator float () const + { + return( _mm_cvtss_f32( value )); + } + + /** + * @param p Pointer to memory from where the value should be loaded, + * should be 16-byte aligned. + * @return float4 value loaded from the specified memory location. + */ + + static float4 load( const float* const p ) + { + return( _mm_load_ps( p )); + } + + /** + * @param p Pointer to memory from where the value should be loaded, + * may have any alignment. + * @return float4 value loaded from the specified memory location. + */ + + static float4 loadu( const float* const p ) + { + return( _mm_loadu_ps( p )); + } + + /** + * @param p Pointer to memory from where the value should be loaded, + * may have any alignment. + * @param lim The maximum number of elements to load, >0. + * @return float4 value loaded from the specified memory location, with + * elements beyond "lim" set to 0. + */ + + static float4 loadu( const float* const p, int lim ) + { + if( lim > 2 ) + { + if( lim > 3 ) + { + return( _mm_loadu_ps( p )); + } + else + { + return( _mm_set_ps( 0.0f, p[ 2 ], p[ 1 ], p[ 0 ])); + } + } + else + { + if( lim == 2 ) + { + return( _mm_set_ps( 0.0f, 0.0f, p[ 1 ], p[ 0 ])); + } + else + { + return( _mm_load_ss( p )); + } + } + } + + /** + * Function stores *this value to the specified memory location. + * + * @param[out] p Output memory location, should be 16-byte aligned. + */ + + void store( float* const p ) const + { + _mm_store_ps( p, value ); + } + + /** + * Function stores *this value to the specified memory location. + * + * @param[out] p Output memory location, may have any alignment. + */ + + void storeu( float* const p ) const + { + _mm_storeu_ps( p, value ); + } + + /** + * Function stores "lim" lower elements of *this value to the specified + * memory location. + * + * @param[out] p Output memory location, may have any alignment. + * @param lim The number of lower elements to store, >0. + */ + + void storeu( float* const p, int lim ) const + { + if( lim > 2 ) + { + if( lim > 3 ) + { + _mm_storeu_ps( p, value ); + } + else + { + _mm_storel_pi( (__m64*) p, value ); + _mm_store_ss( p + 2, _mm_movehl_ps( value, value )); + } + } + else + { + if( lim == 2 ) + { + _mm_storel_pi( (__m64*) p, value ); + } + else + { + _mm_store_ss( p, value ); + } + } + } + + float4& operator += ( const float4& s ) + { + value = _mm_add_ps( value, s.value ); + return( *this ); + } + + float4& operator -= ( const float4& s ) + { + value = _mm_sub_ps( value, s.value ); + return( *this ); + } + + float4& operator *= ( const float4& s ) + { + value = _mm_mul_ps( value, s.value ); + return( *this ); + } + + float4& operator /= ( const float4& s ) + { + value = _mm_div_ps( value, s.value ); + return( *this ); + } + + float4 operator + ( const float4& s ) const + { + return( _mm_add_ps( value, s.value )); + } + + float4 operator - ( const float4& s ) const + { + return( _mm_sub_ps( value, s.value )); + } + + float4 operator * ( const float4& s ) const + { + return( _mm_mul_ps( value, s.value )); + } + + float4 operator / ( const float4& s ) const + { + return( _mm_div_ps( value, s.value )); + } + + /** + * @return Horizontal sum of elements. + */ + + float hadd() const + { + const __m128 v = _mm_add_ps( value, _mm_movehl_ps( value, value )); + const __m128 res = _mm_add_ss( v, _mm_shuffle_ps( v, v, 1 )); + return( _mm_cvtss_f32( res )); + } + + /** + * Function performs in-place addition of a value located in memory and + * the specified value. + * + * @param p Pointer to value where addition happens. May be unaligned. + * @param v Value to add. + */ + + static void addu( float* const p, const float4& v ) + { + ( loadu( p ) + v ).storeu( p ); + } + + /** + * Function performs in-place addition of a value located in memory and + * the specified value. Limited to the specfied number of elements. + * + * @param p Pointer to value where addition happens. May be unaligned. + * @param v Value to add. + * @param lim The element number limit, >0. + */ + + static void addu( float* const p, const float4& v, const int lim ) + { + ( loadu( p, lim ) + v ).storeu( p, lim ); + } + + __m128 value; ///< Packed value of 4 floats. + ///< +}; + +/** + * SIMD rounding function, exact result. + * + * @param v Value to round. + * @return Rounded SIMD value. + */ + +inline float4 round( const float4& v ) +{ + unsigned int prevrm = _MM_GET_ROUNDING_MODE(); + _MM_SET_ROUNDING_MODE( _MM_ROUND_NEAREST ); + + const __m128 res = _mm_cvtepi32_ps( _mm_cvtps_epi32( v.value )); + + _MM_SET_ROUNDING_MODE( prevrm ); + + return( res ); +} + +/** + * SIMD function "clamps" (clips) the specified packed values so that they are + * not lesser than "minv", and not greater than "maxv". + * + * @param Value Value to clamp. + * @param minv Minimal allowed value. + * @param maxv Maximal allowed value. + * @return The clamped value. + */ + +inline float4 clamp( const float4& Value, const float4& minv, + const float4& maxv ) +{ + return( _mm_min_ps( _mm_max_ps( Value.value, minv.value ), maxv.value )); +} + +typedef fpclass_def< avir :: float4, float > fpclass_float4; ///< + ///< Class that can be used as the "fpclass" template parameter of the + ///< avir::CImageResizer class to perform calculation using default + ///< interleaved algorithm, using SIMD float4 type. + ///< + +} // namespace avir + +#endif // AVIR_FLOAT4_SSE_INCLUDED diff --git a/Common/Libs/avir/avir_float8_avx.h b/Common/Libs/avir/avir_float8_avx.h new file mode 100644 index 00000000..ebbd9c75 --- /dev/null +++ b/Common/Libs/avir/avir_float8_avx.h @@ -0,0 +1,359 @@ +//$ nobt +//$ nocpp + +/** + * @file avir_float8_avx.h + * + * @brief Inclusion file for the "float8" type. + * + * This file includes the "float8" AVX-based type used for SIMD variable + * storage and processing. + * + * AVIR Copyright (c) 2015-2020 Aleksey Vaneev + */ + +#ifndef AVIR_FLOAT8_AVX_INCLUDED +#define AVIR_FLOAT8_AVX_INCLUDED + +#include +#include "avir_dil.h" + +namespace avir { + +/** + * @brief SIMD packed 8-float type. + * + * This class implements a packed 8-float type that can be used to perform + * parallel computation using SIMD instructions on AVX-enabled processors. + * This class can be used as the "fptype" argument of the avir::fpclass_def + * or avir::fpclass_def_dil class. + */ + +class float8 +{ +public: + float8() + { + } + + float8( const float8& s ) + : value( s.value ) + { + } + + float8( const __m256 s ) + : value( s ) + { + } + + float8( const float s ) + : value( _mm256_set1_ps( s )) + { + } + + float8& operator = ( const float8& s ) + { + value = s.value; + return( *this ); + } + + float8& operator = ( const __m256 s ) + { + value = s; + return( *this ); + } + + float8& operator = ( const float s ) + { + value = _mm256_set1_ps( s ); + return( *this ); + } + + operator float () const + { + return( _mm_cvtss_f32( _mm256_extractf128_ps( value, 0 ))); + } + + /** + * @param p Pointer to memory from where the value should be loaded, + * should be 32-byte aligned. + * @return float8 value loaded from the specified memory location. + */ + + static float8 load( const float* const p ) + { + return( _mm256_load_ps( p )); + } + + /** + * @param p Pointer to memory from where the value should be loaded, + * may have any alignment. + * @return float8 value loaded from the specified memory location. + */ + + static float8 loadu( const float* const p ) + { + return( _mm256_loadu_ps( p )); + } + + /** + * @param p Pointer to memory from where the value should be loaded, + * may have any alignment. + * @param lim The maximum number of elements to load, >0. + * @return float8 value loaded from the specified memory location, with + * elements beyond "lim" set to 0. + */ + + static float8 loadu( const float* const p, const int lim ) + { + __m128 lo; + __m128 hi; + + if( lim > 4 ) + { + lo = _mm_loadu_ps( p ); + hi = loadu4( p + 4, lim - 4 ); + } + else + { + lo = loadu4( p, lim ); + hi = _mm_setzero_ps(); + } + + return( _mm256_insertf128_ps( _mm256_castps128_ps256( lo ), hi, 1 )); + } + + /** + * Function stores *this value to the specified memory location. + * + * @param[out] p Output memory location, should be 32-byte aligned. + */ + + void store( float* const p ) const + { + _mm256_store_ps( p, value ); + } + + /** + * Function stores *this value to the specified memory location. + * + * @param[out] p Output memory location, may have any alignment. + */ + + void storeu( float* const p ) const + { + _mm256_storeu_ps( p, value ); + } + + /** + * Function stores "lim" lower elements of *this value to the specified + * memory location. + * + * @param[out] p Output memory location, may have any alignment. + * @param lim The number of lower elements to store, >0. + */ + + void storeu( float* p, int lim ) const + { + __m128 v; + + if( lim > 4 ) + { + _mm_storeu_ps( p, _mm256_extractf128_ps( value, 0 )); + v = _mm256_extractf128_ps( value, 1 ); + p += 4; + lim -= 4; + } + else + { + v = _mm256_extractf128_ps( value, 0 ); + } + + if( lim > 2 ) + { + if( lim > 3 ) + { + _mm_storeu_ps( p, v ); + } + else + { + _mm_storel_pi( (__m64*) p, v ); + _mm_store_ss( p + 2, _mm_movehl_ps( v, v )); + } + } + else + { + if( lim == 2 ) + { + _mm_storel_pi( (__m64*) p, v ); + } + else + { + _mm_store_ss( p, v ); + } + } + } + + float8& operator += ( const float8& s ) + { + value = _mm256_add_ps( value, s.value ); + return( *this ); + } + + float8& operator -= ( const float8& s ) + { + value = _mm256_sub_ps( value, s.value ); + return( *this ); + } + + float8& operator *= ( const float8& s ) + { + value = _mm256_mul_ps( value, s.value ); + return( *this ); + } + + float8& operator /= ( const float8& s ) + { + value = _mm256_div_ps( value, s.value ); + return( *this ); + } + + float8 operator + ( const float8& s ) const + { + return( _mm256_add_ps( value, s.value )); + } + + float8 operator - ( const float8& s ) const + { + return( _mm256_sub_ps( value, s.value )); + } + + float8 operator * ( const float8& s ) const + { + return( _mm256_mul_ps( value, s.value )); + } + + float8 operator / ( const float8& s ) const + { + return( _mm256_div_ps( value, s.value )); + } + + /** + * @return Horizontal sum of elements. + */ + + float hadd() const + { + __m128 v = _mm_add_ps( _mm256_extractf128_ps( value, 0 ), + _mm256_extractf128_ps( value, 1 )); + + v = _mm_hadd_ps( v, v ); + v = _mm_hadd_ps( v, v ); + return( _mm_cvtss_f32( v )); + } + + /** + * Function performs in-place addition of a value located in memory and + * the specified value. + * + * @param p Pointer to value where addition happens. May be unaligned. + * @param v Value to add. + */ + + static void addu( float* const p, const float8& v ) + { + ( loadu( p ) + v ).storeu( p ); + } + + /** + * Function performs in-place addition of a value located in memory and + * the specified value. Limited to the specfied number of elements. + * + * @param p Pointer to value where addition happens. May be unaligned. + * @param v Value to add. + * @param lim The element number limit, >0. + */ + + static void addu( float* const p, const float8& v, const int lim ) + { + ( loadu( p, lim ) + v ).storeu( p, lim ); + } + + __m256 value; ///< Packed value of 8 floats. + ///< + +private: + /** + * @param p Pointer to memory from where the value should be loaded, + * may have any alignment. + * @param lim The maximum number of elements to load, >0. + * @return __m128 value loaded from the specified memory location, with + * elements beyond "lim" set to 0. + */ + + static __m128 loadu4( const float* const p, const int lim ) + { + if( lim > 2 ) + { + if( lim > 3 ) + { + return( _mm_loadu_ps( p )); + } + else + { + return( _mm_set_ps( 0.0f, p[ 2 ], p[ 1 ], p[ 0 ])); + } + } + else + { + if( lim == 2 ) + { + return( _mm_set_ps( 0.0f, 0.0f, p[ 1 ], p[ 0 ])); + } + else + { + return( _mm_load_ss( p )); + } + } + } +}; + +/** + * SIMD rounding function, exact result. + * + * @param v Value to round. + * @return Rounded SIMD value. + */ + +inline float8 round( const float8& v ) +{ + return( _mm256_round_ps( v.value, + ( _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC ))); +} + +/** + * SIMD function "clamps" (clips) the specified packed values so that they are + * not lesser than "minv", and not greater than "maxv". + * + * @param Value Value to clamp. + * @param minv Minimal allowed value. + * @param maxv Maximal allowed value. + * @return The clamped value. + */ + +inline float8 clamp( const float8& Value, const float8& minv, + const float8& maxv ) +{ + return( _mm256_min_ps( _mm256_max_ps( Value.value, minv.value ), + maxv.value )); +} + +typedef fpclass_def_dil< float, avir :: float8 > fpclass_float8_dil; ///< + ///< Class that can be used as the "fpclass" template parameter of the + ///< avir::CImageResizer class to perform calculation using + ///< de-interleaved SIMD algorithm, using SIMD float8 type. + ///< + +} // namespace avir + +#endif // AVIR_FLOAT8_AVX_INCLUDED diff --git a/Common/Libs/avir/lancir.h b/Common/Libs/avir/lancir.h new file mode 100644 index 00000000..61e3c559 --- /dev/null +++ b/Common/Libs/avir/lancir.h @@ -0,0 +1,2329 @@ +//$ nobt +//$ nocpp + +/** + * @file lancir.h + * + * @brief The self-contained "lancir" inclusion file. + * + * This is the self-contained inclusion file for the "LANCIR" image resizer, + * a part of the AVIR library. Features scalar, AVX, SSE2, and NEON + * optimizations as well as progressive resizing technique which provides a + * better CPU cache performance. + * + * AVIR Copyright (c) 2015-2021 Aleksey Vaneev + * + * @mainpage + * + * @section intro_sec Introduction + * + * Description is available at https://github.com/avaneev/avir + * + * @section license License + * + * License + * + * Copyright (c) 2015-2021 Aleksey Vaneev + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * @version 3.0.7 + */ + +#ifndef AVIR_CLANCIR_INCLUDED +#define AVIR_CLANCIR_INCLUDED + +#include +#include +#include + +#if defined( __AVX__ ) || defined( __AVX2__ ) + + #include + + #define LANCIR_AVX + #define LANCIR_SSE2 // Some functions use SSE2; AVX has a higher priority. + #define LANCIR_ALIGN 32 + +#elif defined( __SSE4_2__ ) || defined( __SSE4_1__ ) || \ + defined( __SSSE3__ ) || defined( __SSE3__ ) || defined( __SSE2__ ) || \ + defined( __x86_64__ ) || defined( _M_AMD64 ) || defined( _M_X64 ) || \ + defined( __amd64 ) + + #include + + #define LANCIR_SSE2 + #define LANCIR_ALIGN 16 + +#elif defined( __aarch64__ ) || defined( __arm64__ ) || defined( __ARM_NEON ) + + #include + + #define LANCIR_NEON + #define LANCIR_ALIGN 16 + +#else // NEON + + #define LANCIR_ALIGN 4 + +#endif // NEON + +namespace avir { + +/** + * The macro equals to "pi" constant, fills 53-bit floating point mantissa. + * Undefined at the end of file. + */ + +#define LANCIR_PI 3.1415926535897932 + +/** + * Function reallocates a typed buffer if its current length is smaller than + * the required length. + * + * @param buf0 Reference to the pointer of the previously allocated buffer. + * @param buf Reference to address-aligned "buf0" pointer. + * @param len The current length of the "buf0". + * @param newlen A new required length. + * @tparam Tb Buffer element type. + * @tparam Tl Length variable type. + */ + +template< typename Tb, typename Tl > +inline void reallocBuf( Tb*& buf0, Tb*& buf, Tl& len, Tl newlen ) +{ + newlen += LANCIR_ALIGN; + + if( newlen > len ) + { + delete[] buf0; + len = newlen; + buf0 = new Tb[ newlen ]; + buf = (Tb*) (( (uintptr_t) buf0 + LANCIR_ALIGN - 1 ) & + ~(uintptr_t) ( LANCIR_ALIGN - 1 )); + } +} + +/** + * Function reallocates a typed buffer if its current length is smaller than + * the required length. + * + * @param buf Reference to the pointer of the previously allocated buffer; + * address alignment will not be applied. + * @param len The current length of the "buf0". + * @param newlen A new required length. + * @tparam Tb Buffer element type. + * @tparam Tl Length variable type. + */ + +template< typename Tb, typename Tl > +inline void reallocBuf( Tb*& buf, Tl& len, const Tl newlen ) +{ + if( newlen > len ) + { + delete[] buf; + len = newlen; + buf = new Tb[ newlen ]; + } +} + +/** + * @brief LANCIR image resizer class. + * + * The object of this class can be used to resize 1-4 channel images to any + * required size. Resizing is performed by utilizing Lanczos filters, with + * 8-bit precision. This class offers a kind of "optimal" Lanczos resampling + * implementation. + * + * Object of this class can be allocated on stack. + * + * Note that object of this class does not free temporary buffers and + * variables after the resizeImage() function call (until object's + * destruction): these buffers are reused (or reallocated) on subsequent + * calls, thus making batch resizing of images faster. This means resizing is + * not thread-safe: a separate object should be created for each thread. + */ + +class CLancIR +{ +private: + CLancIR( const CLancIR& ) + { + // Unsupported. + } + + CLancIR& operator = ( const CLancIR& ) + { + // Unsupported. + return( *this ); + } + +public: + CLancIR() + : FltBuf0( NULL ) + , FltBuf0Len( 0 ) + , spv0( NULL ) + , spv0len( 0 ) + { + } + + ~CLancIR() + { + delete[] FltBuf0; + delete[] spv0; + } + + /** + * Function resizes an image and performs input-to-output type conversion, + * if necessary. + * + * @param[in] SrcBuf Source image buffer. + * @param SrcWidth Source image width, in pixels. + * @param SrcHeight Source image height, in pixels. + * @param SrcSSize Physical size of the source scanline, in elements (not + * bytes). If this value is below 1, SrcWidth * ElCount will be used. + * @param[out] NewBuf Buffer to accept the resized image. Can be equal to + * SrcBuf if the size of the resized image is smaller or equal to the + * SrcBuf in size. Specifying a correctly-sized SrcBuf here may be an + * efficient approach for just-in-time resizing of small graphical assets, + * right after they were loaded: this may provide a better CPU cache + * performance, and reduce the number of memory allocations. + * @param NewWidth New image width, in pixels. + * @param NewHeight New image height, in pixels. + * @param NewSSize Physical size of the destination scanline, in elements + * (not bytes). If this value is below 1, NewWidth * ElCount will be used. + * @param ElCount The number of elements (channels) used to store each + * source and destination pixel (1-4). + * @param kx0 Resizing step - horizontal (one output pixel corresponds to + * "k" input pixels). A downsizing factor if > 1.0; upsizing factor + * if <= 1.0. Multiply by -1 if you would like to bypass "ox" and "oy" + * adjustment which is done by default to produce a centered image. If + * the step value equals 0, the step value will be chosen automatically. + * @param ky0 Resizing step - vertical. Same as "kx0". + * @param ox Start X pixel offset within source image (can be negative). + * Positive offset moves the image to the left. + * @param oy Start Y pixel offset within source image (can be negative). + * Positive offset moves the image to the top. + * @tparam Tin Input buffer's element type. Can be uint8_t (0-255 value + * range), uint16_t (0-65535 value range), float (0-1 value range), double + * (0-1 value range). uint32_t type is treated as uint16_t. Signed integer + * types and larger integer types are unsupported. + * @tparam Tout Output buffer's element type, treated like "Tin". If "Tin" + * and "Tout" types do not match, an output value scaling will be applied. + * Floating-point output will not clamped/clipped/saturated, integer + * output is always rounded and clamped. + */ + + template< typename Tin, typename Tout > + void resizeImage( const Tin* const SrcBuf, const int SrcWidth, + const int SrcHeight, const int SrcSSize, Tout* const NewBuf, + const int NewWidth, const int NewHeight, const int NewSSize, + const int ElCount, const double kx0 = 0.0, const double ky0 = 0.0, + double ox = 0.0, double oy = 0.0 ) + { + if( NewWidth <= 0 || NewHeight <= 0 ) + { + return; + } + + const int OutSSize = NewWidth * ElCount; + const size_t NewScanlineSize = ( NewSSize < 1 ? OutSSize : NewSSize ); + + if( SrcWidth <= 0 || SrcHeight <= 0 ) + { + memset( NewBuf, 0, NewScanlineSize * NewHeight * sizeof( Tout )); + return; + } + + const size_t SrcScanlineSize = ( SrcSSize < 1 ? + SrcWidth * ElCount : SrcSSize ); + + const double la = 3.0; // Lanczos "a" parameter. + double kx; + double ky; + + if( kx0 == 0.0 ) + { + kx = (double) SrcWidth / NewWidth; + ox += ( kx - 1.0 ) * 0.5; + } + else + if( kx0 > 0.0 ) + { + kx = kx0; + ox += ( kx0 - 1.0 ) * 0.5; + } + else + { + kx = -kx0; + } + + if( ky0 == 0.0 ) + { + ky = (double) SrcHeight / NewHeight; + oy += ( ky - 1.0 ) * 0.5; + } + else + if( ky0 > 0.0 ) + { + ky = ky0; + oy += ( ky0 - 1.0 ) * 0.5; + } + else + { + ky = -ky0; + } + + if( rfv.update( la, ky, ElCount )) + { + rsv.reset(); + rsh.reset(); + } + + CResizeFilters* rfh; // Pointer to resizing filters for horizontal + // resizing, may equal to "rfv" if the same stepping is in use. + + if( kx == ky ) + { + rfh = &rfv; + } + else + { + rfh = &rfh0; + + if( rfh0.update( la, kx, ElCount )) + { + rsh.reset(); + } + } + + rsv.update( SrcHeight, NewHeight, oy, rfv ); + rsh.update( SrcWidth, NewWidth, ox, *rfh ); + + // Allocate/resize intermediate buffers. + + const int svs = ( rsv.padl + SrcHeight + rsv.padr ) * ElCount; + reallocBuf( spv0, spv, spv0len, ( svs > OutSSize ? svs : OutSSize )); + + const size_t FltWidthE = ( rsh.padl + SrcWidth + rsh.padr ) * ElCount; + reallocBuf( FltBuf0, FltBuf, FltBuf0Len, FltWidthE * NewHeight ); + + // Calculate vertical progressive resizing's batch size. Progressive + // batching is used to try to keep addressing within the cache + // capacity. This technique definitely works well for single-threaded + // resizing on most CPUs, but may not provide an additional benefit + // for multi-threaded resizing, or in a system-wide high-load + // situations. + + const double CacheSize = 5500000.0; // Tuned for various CPUs. + const double OpSize = (double) SrcScanlineSize * SrcHeight * + sizeof( Tin ) + (double) FltWidthE * NewHeight * sizeof( float ); + + int BatchSize = (int) ( NewHeight * CacheSize / ( OpSize + 1.0 )); + + if( BatchSize < 16 ) + { + BatchSize = 16; + } + + // Perform vertical resizing. + + float* opf = FltBuf + rsh.padl * ElCount; + const CResizePos* rp = rsv.pos; + int bl = NewHeight; + int i; + + while( bl > 0 ) + { + const int bc = ( bl > BatchSize ? BatchSize : bl ); + + const int kl = rfv.KernelLen; + const Tin* ip = SrcBuf; + float* op = opf; + + const int so = rp -> so; + float* const sp = spv + so * ElCount; + + int cc = ( rp + bc - 1 ) -> so - so + kl; // Pixel copy count. + int rl = 0; // Leftmost pixel's replication count. + int rr = 0; // Rightmost pixel's replication count. + + const int socc = so + cc; + const int spe = rsv.padl + SrcHeight; + + // Calculate scanline copying and padding parameters, depending on + // the batch's size and its vertical offset. + + if( so < rsv.padl ) + { + if( socc <= rsv.padl ) + { + rl = cc; + cc = 0; + } + else + { + if( socc > spe ) + { + rr = socc - spe; + cc -= rr; + } + + rl = rsv.padl - so; + cc -= rl; + } + } + else + { + if( so >= spe ) + { + rr = cc; + cc = 0; + ip += SrcHeight * SrcScanlineSize; + } + else + { + if( socc > spe ) + { + rr = socc - spe; + cc -= rr; + } + + ip += ( so - rsv.padl ) * SrcScanlineSize; + } + } + + // Batched vertical resizing. + + if( ElCount == 1 ) + { + for( i = 0; i < SrcWidth; i++ ) + { + copyScanline1v( ip, SrcScanlineSize, sp, cc, rl, rr ); + resize1( spv, op, FltWidthE, rp, kl, bc ); + ip += 1; + op += 1; + } + } + else + if( ElCount == 2 ) + { + for( i = 0; i < SrcWidth; i++ ) + { + copyScanline2v( ip, SrcScanlineSize, sp, cc, rl, rr ); + resize2( spv, op, FltWidthE, rp, kl, bc ); + ip += 2; + op += 2; + } + } + else + if( ElCount == 3 ) + { + for( i = 0; i < SrcWidth; i++ ) + { + copyScanline3v( ip, SrcScanlineSize, sp, cc, rl, rr ); + resize3( spv, op, FltWidthE, rp, kl, bc ); + ip += 3; + op += 3; + } + } + else // ElCount == 4 + { + for( i = 0; i < SrcWidth; i++ ) + { + copyScanline4v( ip, SrcScanlineSize, sp, cc, rl, rr ); + resize4( spv, op, FltWidthE, rp, kl, bc ); + ip += 4; + op += 4; + } + } + + opf += bc * FltWidthE; + rp += bc; + bl -= bc; + } + + // Prepare output-related constants. + + const bool IsOutFloat = ( (Tout) 0.25 != 0 ); + const int Clamp = ( sizeof( Tout ) == 1 ? 255 : 65535 ); + float OutMul = ( IsOutFloat ? 1.0f : (float) Clamp ); + + if( (Tin) 0.25 == 0 ) + { + OutMul /= ( sizeof( Tin ) == 1 ? 255 : 65535 ); + } + + // Perform horizontal resizing and produce final output. + + float* ip = FltBuf; + Tout* opn = NewBuf; + + if( ElCount == 1 ) + { + for( i = 0; i < NewHeight; i++ ) + { + padScanline1h( ip, rsh, SrcWidth ); + resize1( ip, spv, 1, rsh.pos, rfh -> KernelLen, NewWidth ); + copyToOutput( spv, opn, OutSSize, Clamp, IsOutFloat, OutMul ); + ip += FltWidthE; + opn += NewScanlineSize; + } + } + else + if( ElCount == 2 ) + { + for( i = 0; i < NewHeight; i++ ) + { + padScanline2h( ip, rsh, SrcWidth ); + resize2( ip, spv, 2, rsh.pos, rfh -> KernelLen, NewWidth ); + copyToOutput( spv, opn, OutSSize, Clamp, IsOutFloat, OutMul ); + ip += FltWidthE; + opn += NewScanlineSize; + } + } + else + if( ElCount == 3 ) + { + for( i = 0; i < NewHeight; i++ ) + { + padScanline3h( ip, rsh, SrcWidth ); + resize3( ip, spv, 3, rsh.pos, rfh -> KernelLen, NewWidth ); + copyToOutput( spv, opn, OutSSize, Clamp, IsOutFloat, OutMul ); + ip += FltWidthE; + opn += NewScanlineSize; + } + } + else // ElCount == 4 + { + for( i = 0; i < NewHeight; i++ ) + { + padScanline4h( ip, rsh, SrcWidth ); + resize4( ip, spv, 4, rsh.pos, rfh -> KernelLen, NewWidth ); + copyToOutput( spv, opn, OutSSize, Clamp, IsOutFloat, OutMul ); + ip += FltWidthE; + opn += NewScanlineSize; + } + } + } + +protected: + float* FltBuf0; ///< Intermediate resizing buffer. + ///< + size_t FltBuf0Len; ///< Length of "FltBuf0". + ///< + float* FltBuf; ///< Address-aligned "FltBuf0". + ///< + float* spv0; ///< Scanline buffer for vertical resizing, also used at the + ///< output stage. + ///< + int spv0len; ///< Length of "spv0". + ///< + float* spv; ///< Address-aligned "spv0". + ///< + + class CResizeScanline; + + /** + * Class implements fractional delay filter bank calculation. + */ + + class CResizeFilters + { + friend class CResizeScanline; + + public: + int KernelLen; ///< Resampling filter kernel's length, taps. Available + ///< after the update() function call. Always an even value, + ///< should not be lesser than 4. + ///< + + CResizeFilters() + : Filters( NULL ) + , FiltersLen( 0 ) + , la( 0.0 ) + , k( 0.0 ) + , ElCount( 0 ) + { + memset( Bufs0, 0, sizeof( Bufs0 )); + memset( Bufs0Len, 0, sizeof( Bufs0Len )); + } + + ~CResizeFilters() + { + int i; + + for( i = 0; i < BufCount; i++ ) + { + delete[] Bufs0[ i ]; + } + + delete[] Filters; + } + + /** + * Function updates the resizing filter bank. + * + * @param la0 Lanczos "a" parameter value (>=2.0), can be fractional. + * @param k0 Resizing step. + * @param ElCount0 Image's element count, may be used for SIMD filter + * tap replication. + * @return "True" if an update occured and scanline resizing positions + * should be updated unconditionally. + */ + + bool update( const double la0, const double k0, const int ElCount0 ) + { + if( la0 == la && k0 == k && ElCount0 == ElCount ) + { + return( false ); + } + + la = la0; + k = k0; + ElCount = ElCount0; + + NormFreq = ( k <= 1.0 ? 1.0 : 1.0 / k ); + Freq = LANCIR_PI * NormFreq; + FreqA = LANCIR_PI * NormFreq / la; + + Len2 = la / NormFreq; + fl2 = (int) ceil( Len2 ); + KernelLen = fl2 + fl2; + + #if LANCIR_ALIGN > 4 + + ElRepl = ElCount; + KernelLenA = KernelLen * ElRepl; + + const int elalign = + (int) ( LANCIR_ALIGN / sizeof( float )) - 1; + + KernelLenA = ( KernelLenA + elalign ) & ~elalign; + + #else // LANCIR_ALIGN > 4 + + ElRepl = 1; + KernelLenA = KernelLen; + + #endif // LANCIR_ALIGN > 4 + + FracCount = 1000; // Enough for Lanczos-3 implicit 8-bit precision. + + reallocBuf( Filters, FiltersLen, FracCount + 1 ); // Add +1 to + // cover cases of fractional delay == 1.0 due to rounding. + + memset( Filters, 0, FiltersLen * sizeof( Filters[ 0 ])); + + setBuf( 0 ); + + return( true ); + } + + /** + * Function returns filter at the specified fractional offset. This + * function can only be called after a prior update() function call. + * + * @param x Fractional offset, [0; 1]. + */ + + const float* getFilter( const double x ) + { + const int Frac = (int) ( x * FracCount + 0.5 ); + float* flt = Filters[ Frac ]; + + if( flt != NULL ) + { + return( flt ); + } + + flt = Bufs[ CurBuf ] + CurBufFill * KernelLenA; + Filters[ Frac ] = flt; + CurBufFill++; + + if( CurBufFill == BufLen ) + { + setBuf( CurBuf + 1 ); + } + + makeFilterNorm( flt, 1.0 - (double) Frac / FracCount ); + + if( ElRepl > 1 ) + { + replicateFilter( flt, KernelLen, ElRepl ); + } + + return( flt ); + } + + protected: + double NormFreq; ///< Normalized frequency of the filter. + ///< + double Freq; ///< Circular frequency of the filter. + ///< + double FreqA; ///< Circular frequency of the window function. + ///< + double Len2; ///< Half resampling filter's length, unrounded. + ///< + int fl2; ///< Half resampling filter's length, integer. + ///< + int FracCount; ///< The number of fractional positions for which + ///< filters can be created. + ///< + int KernelLenA; ///< SIMD-aligned and replicated filter kernel's + ///< length. + ///< + int ElRepl; ///< The number of repetitions of each filter tap. + ///< + static const int BufCount = 4; ///< The maximal number of buffers that + ///< can be in use. + ///< + static const int BufLen = 256; ///< The number of fractional filters + ///< a single buffer may contain. Both "BufLen" and "BufCount" + ///< should correspond to the "FracCount" used. + ///< + float* Bufs0[ BufCount ]; ///< Buffers that hold all filters, + ///< original. + ///< + int Bufs0Len[ BufCount ]; ///< Allocated lengthes in "Bufs0", in + ///< "float" elements. + ///< + float* Bufs[ BufCount ]; ///< Address-aligned "Bufs0". + ///< + int CurBuf; ///< Filter buffer currently being filled. + ///< + int CurBufFill; ///< The number of fractional positions filled in the + ///< current filter buffer. + ///< + float** Filters; ///< Fractional delay filters for all positions. + ///< A particular pointer equals NULL if a filter for such + ///< position has not been created yet. + ///< + int FiltersLen; ///< Allocated length of Filters, in elements. + ///< + double la; ///< Current "la". + ///< + double k; ///< Current "k". + ///< + int ElCount; ///< Current "ElCount". + ///< + + /** + * Function changes the buffer currently being filled, check its + * size and reallocates it if necessary, then resets its fill counter. + * + * @param bi New current buffer index. + */ + + void setBuf( const int bi ) + { + reallocBuf( Bufs0[ bi ], Bufs[ bi ], Bufs0Len[ bi ], + BufLen * KernelLenA ); + + CurBuf = bi; + CurBufFill = 0; + } + + /** + * @brief Sine-wave signal generator class. + * + * Class implements sine-wave signal generator without biasing, with + * constructor-based initialization only. This generator uses an + * oscillator instead of the "sin" function. + */ + + class CSineGen + { + public: + /** + * Constructor initializes *this sine-wave signal generator. + * + * @param si Sine function increment, in radians. + * @param ph Starting phase, in radians. Add 0.5 * LANCIR_PI for + * cosine function. + */ + + CSineGen( const double si, const double ph ) + : svalue1( sin( ph )) + , svalue2( sin( ph - si )) + , sincr( 2.0 * cos( si )) + { + } + + /** + * @return The next value of the sine-wave, without biasing. + */ + + double generate() + { + const double res = svalue1; + + svalue1 = sincr * res - svalue2; + svalue2 = res; + + return( res ); + } + + private: + double svalue1; ///< Current sine value. + ///< + double svalue2; ///< Previous sine value. + ///< + double sincr; ///< Sine value increment. + ///< + }; + + /** + * Function creates a filter for the specified fractional delay. The + * update() function should be called prior to calling this function. + * The created filter is normalized (DC gain=1). + * + * @param[out] op Output filter buffer. + * @param FracDelay Fractional delay, 0 to 1, inclusive. + */ + + void makeFilterNorm( float* op, const double FracDelay ) const + { + CSineGen f( Freq, Freq * ( FracDelay - fl2 )); + CSineGen fw( FreqA, FreqA * ( FracDelay - fl2 )); + + float* op0 = op; + double s = 0.0; + double ut; + + int t = -fl2; + + if( t + FracDelay < -Len2 ) + { + f.generate(); + fw.generate(); + *op = (float) 0; + op++; + t++; + } + + int IsZeroX = ( fabs( FracDelay - 1.0 ) < 0x1p-42 ); + int mt = 0 - IsZeroX; + IsZeroX = ( IsZeroX || fabs( FracDelay ) < 0x1p-42 ); + + while( t < mt ) + { + ut = t + FracDelay; + *op = (float) ( f.generate() * fw.generate() / ( ut * ut )); + s += *op; + op++; + t++; + } + + if( IsZeroX ) // t+FracDelay==0 + { + *op = (float) ( Freq * FreqA ); + s += *op; + f.generate(); + fw.generate(); + } + else + { + ut = FracDelay; // t==0 + *op = (float) ( f.generate() * fw.generate() / ( ut * ut )); + s += *op; + } + + mt = fl2 - 2; + + while( t < mt ) + { + op++; + t++; + ut = t + FracDelay; + *op = (float) ( f.generate() * fw.generate() / ( ut * ut )); + s += *op; + } + + op++; + ut = t + 1 + FracDelay; + + if( ut > Len2 ) + { + *op = (float) 0; + } + else + { + *op = (float) ( f.generate() * fw.generate() / ( ut * ut )); + s += *op; + } + + s = 1.0 / s; + t = (int) ( op - op0 + 1 ); + + while( t != 0 ) + { + *op0 = (float) ( *op0 * s ); + op0++; + t--; + } + } + + /** + * Function replicates taps of the specified filter so that it can + * be used with SIMD loading instructions. This function works + * "in-place". + * + * @param[in,out] p Filter buffer pointer, should be sized to contain + * "kl * erp" elements. + * @param kl Filter kernel's length, in taps. + * @param erp The number of repetitions to apply. + */ + + static void replicateFilter( float* const p, const int kl, + const int erp ) + { + const float* ip = p + kl - 1; + float* op = p + ( kl - 1 ) * erp; + int c = kl; + + if( erp == 2 ) + { + while( c != 0 ) + { + const float v = *ip; + op[ 0 ] = v; + op[ 1 ] = v; + ip--; + op -= 2; + c--; + } + } + else + if( erp == 3 ) + { + while( c != 0 ) + { + const float v = *ip; + op[ 0 ] = v; + op[ 1 ] = v; + op[ 2 ] = v; + ip--; + op -= 3; + c--; + } + } + else // erp == 4 + { + while( c != 0 ) + { + const float v = *ip; + op[ 0 ] = v; + op[ 1 ] = v; + op[ 2 ] = v; + op[ 3 ] = v; + ip--; + op -= 4; + c--; + } + } + } + }; + + /** + * Structure defines source scanline positions and filters for each + * destination pixel. + */ + + struct CResizePos + { + uintptr_t spo; ///< Source scanline's pixel offset, in bytes. + ///< + const float* flt; ///< Fractional delay filter. + ///< + int so; ///< Offset within the source scanline, in pixels. + ///< + }; + + /** + * Class contains resizing positions, and prepares source scanline + * positions for resize filtering. The public variables become available + * after the update() function call. + */ + + class CResizeScanline + { + public: + int padl; ///< Left-padding (in pixels) required for source scanline. + ///< + int padr; ///< Right-padding (in pixels) required for source scanline. + ///< + CResizePos* pos; ///< Source scanline positions (offsets) and filters + ///< for each destination pixel position. + ///< + + CResizeScanline() + : pos( NULL ) + , poslen( 0 ) + , SrcLen( 0 ) + , DstLen( 0 ) + , o( 0.0 ) + { + } + + ~CResizeScanline() + { + delete[] pos; + } + + /** + * Function "resets" *this object so that the next update() call fully + * updates the position buffer. Reset is necessary if the filter + * object was updated. + */ + + void reset() + { + SrcLen = 0; + } + + /** + * Function updates resizing positions, updates "padl", "padr" and + * "pos" buffer. + * + * @param SrcLen0 Source image scanline length, used to create a + * scanline buffer without length pre-calculation. + * @param DstLen0 Destination image scanline length. + * @param o0 Initial source image offset. + * @param rf Resizing filters object. + */ + + void update( const int SrcLen0, const int DstLen0, const double o0, + CResizeFilters& rf ) + { + if( SrcLen0 == SrcLen && DstLen0 == DstLen && o0 == o ) + { + return; + } + + SrcLen = SrcLen0; + DstLen = DstLen0; + o = o0; + + const int fl2m1 = rf.fl2 - 1; + padl = fl2m1 - (int) floor( o0 ); + + if( padl < 0 ) + { + padl = 0; + } + + // Make sure "padr" and "pos" are in sync: calculate ending "pos" + // offset in advance. + + const double k = rf.k; + + const int DstLen_m1 = DstLen - 1; + const double oe = o0 + k * DstLen_m1; + const int ie = (int) floor( oe ); + + padr = ie + rf.fl2 + 1 - SrcLen; + + if( padr < 0 ) + { + padr = 0; + } + + reallocBuf( pos, poslen, DstLen ); + + const size_t ElCountF = rf.ElCount * sizeof( float ); + const int so = padl - fl2m1; + CResizePos* rp = pos; + int i; + + for( i = 0; i < DstLen_m1; i++ ) + { + const double ox = o0 + k * i; + const int ix = (int) floor( ox ); + + rp -> so = so + ix; + rp -> spo = rp -> so * ElCountF; + rp -> flt = rf.getFilter( ox - ix ); + rp++; + } + + rp -> so = so + ie; + rp -> spo = rp -> so * ElCountF; + rp -> flt = rf.getFilter( oe - ie ); + } + + protected: + int poslen; ///< Allocated "pos" buffer's length. + ///< + int SrcLen; ///< Current SrcLen. + ///< + int DstLen; ///< Current DstLen. + ///< + double o; ///< Current "o". + ///< + }; + + CResizeFilters rfv; ///< Resizing filters for vertical resizing. + ///< + CResizeFilters rfh0; ///< Resizing filters for horizontal resizing (may + ///< not be in use). + ///< + CResizeScanline rsv; ///< Vertical resize scanline. + ///< + CResizeScanline rsh; ///< Horizontal resize scanline. + ///< + + /** + * Function copies scanline (fully or partially) from the source buffer, + * in its native format, to the internal scanline buffer, in preparation + * for vertical resizing. Variants for 1-4-channel images. + * + * @param ip Source scanline buffer pointer. + * @param ipinc "ip" increment per pixel. + * @param op Output scanline pointer. + * @param cc Source pixel copy count. + * @param repl Leftmost pixel's replication count. + * @param repr Rightmost pixel's replication count. + * @tparam T Source buffer's element type. + */ + + template< typename T > + static void copyScanline1v( const T* ip, const size_t ipinc, float* op, + int cc, int repl, int repr ) + { + float v0; + + if( repl > 0 ) + { + v0 = (float) ip[ 0 ]; + + do + { + op[ 0 ] = v0; + op += 1; + + } while( --repl != 0 ); + } + + while( cc != 0 ) + { + op[ 0 ] = (float) ip[ 0 ]; + ip += ipinc; + op += 1; + cc--; + } + + if( repr > 0 ) + { + const T* const ipe = ip - ipinc; + v0 = (float) ipe[ 0 ]; + + do + { + op[ 0 ] = v0; + op += 1; + + } while( --repr != 0 ); + } + } + + template< typename T > + static void copyScanline2v( const T* ip, const size_t ipinc, float* op, + int cc, int repl, int repr ) + { + float v0, v1; + + if( repl > 0 ) + { + v0 = (float) ip[ 0 ]; + v1 = (float) ip[ 1 ]; + + do + { + op[ 0 ] = v0; + op[ 1 ] = v1; + op += 2; + + } while( --repl != 0 ); + } + + while( cc != 0 ) + { + op[ 0 ] = (float) ip[ 0 ]; + op[ 1 ] = (float) ip[ 1 ]; + ip += ipinc; + op += 2; + cc--; + } + + if( repr > 0 ) + { + const T* const ipe = ip - ipinc; + v0 = (float) ipe[ 0 ]; + v1 = (float) ipe[ 1 ]; + + do + { + op[ 0 ] = v0; + op[ 1 ] = v1; + op += 2; + + } while( --repr != 0 ); + } + } + + template< typename T > + static void copyScanline3v( const T* ip, const size_t ipinc, float* op, + int cc, int repl, int repr ) + { + float v0, v1, v2; + + if( repl > 0 ) + { + v0 = (float) ip[ 0 ]; + v1 = (float) ip[ 1 ]; + v2 = (float) ip[ 2 ]; + + do + { + op[ 0 ] = v0; + op[ 1 ] = v1; + op[ 2 ] = v2; + op += 3; + + } while( --repl != 0 ); + } + + while( cc != 0 ) + { + op[ 0 ] = (float) ip[ 0 ]; + op[ 1 ] = (float) ip[ 1 ]; + op[ 2 ] = (float) ip[ 2 ]; + ip += ipinc; + op += 3; + cc--; + } + + if( repr > 0 ) + { + const T* const ipe = ip - ipinc; + v0 = (float) ipe[ 0 ]; + v1 = (float) ipe[ 1 ]; + v2 = (float) ipe[ 2 ]; + + do + { + op[ 0 ] = v0; + op[ 1 ] = v1; + op[ 2 ] = v2; + op += 3; + + } while( --repr != 0 ); + } + } + + template< typename T > + static void copyScanline4v( const T* ip, const size_t ipinc, float* op, + int cc, int repl, int repr ) + { + float v0, v1, v2, v3; + + if( repl > 0 ) + { + v0 = (float) ip[ 0 ]; + v1 = (float) ip[ 1 ]; + v2 = (float) ip[ 2 ]; + v3 = (float) ip[ 3 ]; + + do + { + op[ 0 ] = v0; + op[ 1 ] = v1; + op[ 2 ] = v2; + op[ 3 ] = v3; + op += 4; + + } while( --repl != 0 ); + } + + while( cc != 0 ) + { + op[ 0 ] = (float) ip[ 0 ]; + op[ 1 ] = (float) ip[ 1 ]; + op[ 2 ] = (float) ip[ 2 ]; + op[ 3 ] = (float) ip[ 3 ]; + ip += ipinc; + op += 4; + cc--; + } + + if( repr > 0 ) + { + const T* const ipe = ip - ipinc; + v0 = (float) ipe[ 0 ]; + v1 = (float) ipe[ 1 ]; + v2 = (float) ipe[ 2 ]; + v3 = (float) ipe[ 3 ]; + + do + { + op[ 0 ] = v0; + op[ 1 ] = v1; + op[ 2 ] = v2; + op[ 3 ] = v3; + op += 4; + + } while( --repr != 0 ); + } + } + + /** + * Function pads the specified scanline buffer to the left and right by + * replicating its first and last available pixels, in preparation for + * horizontal resizing. Variants for 1-4-channel images. + * + * @param[in,out] op Scanline buffer to pad. + * @param rs Scanline resizing positions object. + * @param l Source scanline's length, in pixels. + */ + + static void padScanline1h( float* op, CResizeScanline& rs, const int l ) + { + const float* ip = op + rs.padl; + + float v0 = ip[ 0 ]; + int i; + + for( i = 0; i < rs.padl; i++ ) + { + op[ i ] = v0; + } + + ip += l; + op += rs.padl + l; + + v0 = ip[ -1 ]; + + for( i = 0; i < rs.padr; i++ ) + { + op[ i ] = v0; + } + } + + static void padScanline2h( float* op, CResizeScanline& rs, const int l ) + { + const float* ip = op + rs.padl * 2; + + float v0 = ip[ 0 ]; + float v1 = ip[ 1 ]; + int i; + + for( i = 0; i < rs.padl; i++ ) + { + op[ 0 ] = v0; + op[ 1 ] = v1; + op += 2; + } + + const int lc = l * 2; + ip += lc; + op += lc; + + v0 = ip[ -2 ]; + v1 = ip[ -1 ]; + + for( i = 0; i < rs.padr; i++ ) + { + op[ 0 ] = v0; + op[ 1 ] = v1; + op += 2; + } + } + + static void padScanline3h( float* op, CResizeScanline& rs, const int l ) + { + const float* ip = op + rs.padl * 3; + + float v0 = ip[ 0 ]; + float v1 = ip[ 1 ]; + float v2 = ip[ 2 ]; + int i; + + for( i = 0; i < rs.padl; i++ ) + { + op[ 0 ] = v0; + op[ 1 ] = v1; + op[ 2 ] = v2; + op += 3; + } + + const int lc = l * 3; + ip += lc; + op += lc; + + v0 = ip[ -3 ]; + v1 = ip[ -2 ]; + v2 = ip[ -1 ]; + + for( i = 0; i < rs.padr; i++ ) + { + op[ 0 ] = v0; + op[ 1 ] = v1; + op[ 2 ] = v2; + op += 3; + } + } + + static void padScanline4h( float* op, CResizeScanline& rs, const int l ) + { + const float* ip = op + rs.padl * 4; + + float v0 = ip[ 0 ]; + float v1 = ip[ 1 ]; + float v2 = ip[ 2 ]; + float v3 = ip[ 3 ]; + int i; + + for( i = 0; i < rs.padl; i++ ) + { + op[ 0 ] = v0; + op[ 1 ] = v1; + op[ 2 ] = v2; + op[ 3 ] = v3; + op += 4; + } + + const int lc = l * 4; + ip += lc; + op += lc; + + v0 = ip[ -4 ]; + v1 = ip[ -3 ]; + v2 = ip[ -2 ]; + v3 = ip[ -1 ]; + + for( i = 0; i < rs.padr; i++ ) + { + op[ 0 ] = v0; + op[ 1 ] = v1; + op[ 2 ] = v2; + op[ 3 ] = v3; + op += 4; + } + } + + /** + * Function rounds a value and applies clamping. + * + * @param v Value to round and clamp. + * @param Clamp High clamp level; low level is 0. + */ + + static inline int roundclamp( const float v, const int Clamp ) + { + if( v < 0.5f ) + { + return( 0 ); + } + + const int vr = (int) ( v + 0.5f ); + + return( vr > Clamp ? Clamp : vr ); + } + + /** + * Function performs final output of the resized scanline pixels to the + * destination image buffer. + * + * @param[in] ip Input resized scanline. + * @param[out] op Output image buffer. + * @param l Output scanline's size (not pixel count). + * @param Clamp Clamp high level, used if "IsOutFloat" is "false". + * @param IsOutFloat "True" if floating-point output, and no clamping is + * necessary. + * @param OutMul Output multiplier, for value range conversion. + * @tparam T Output buffer's element type. + */ + + template< typename T > + static void copyToOutput( const float* ip, T* op, int l, const int Clamp, + const bool IsOutFloat, const float OutMul ) + { + const bool IsUnityMul = ( OutMul == 1.0f ); + + if( IsOutFloat ) + { + if( IsUnityMul ) + { + if( sizeof( op[ 0 ]) == sizeof( ip[ 0 ])) + { + memcpy( op, ip, l * sizeof( op[ 0 ])); + return; + } + + int l4 = l >> 2; + l &= 3; + + while( l4 != 0 ) + { + op[ 0 ] = (T) ip[ 0 ]; + op[ 1 ] = (T) ip[ 1 ]; + op[ 2 ] = (T) ip[ 2 ]; + op[ 3 ] = (T) ip[ 3 ]; + ip += 4; + op += 4; + l4--; + } + + while( l != 0 ) + { + *op = (T) *ip; + ip++; + op++; + l--; + } + + return; + } + + int l4 = l >> 2; + l &= 3; + bool DoScalar = true; + + if( sizeof( op[ 0 ]) == sizeof( ip[ 0 ])) + { + #if defined( LANCIR_SSE2 ) + + DoScalar = false; + const __m128 om = _mm_set1_ps( OutMul ); + + while( l4 != 0 ) + { + _mm_storeu_ps( (float*) op, + _mm_mul_ps( _mm_load_ps( ip ), om )); + + ip += 4; + op += 4; + l4--; + } + + #elif defined( LANCIR_NEON ) + + DoScalar = false; + const float32x4_t om = vdupq_n_f32( OutMul ); + + while( l4 != 0 ) + { + vst1q_f32( (float*) op, + vmulq_f32( vld1q_f32( ip ), om )); + + ip += 4; + op += 4; + l4--; + } + + #endif // defined( LANCIR_NEON ) + } + + if( DoScalar ) + { + while( l4 != 0 ) + { + op[ 0 ] = (T) ( ip[ 0 ] * OutMul ); + op[ 1 ] = (T) ( ip[ 1 ] * OutMul ); + op[ 2 ] = (T) ( ip[ 2 ] * OutMul ); + op[ 3 ] = (T) ( ip[ 3 ] * OutMul ); + ip += 4; + op += 4; + l4--; + } + } + + while( l != 0 ) + { + *op = (T) ( *ip * OutMul ); + ip++; + op++; + l--; + } + + return; + } + + int l4 = l >> 2; + l &= 3; + + #if defined( LANCIR_SSE2 ) + + const __m128 minv = _mm_setzero_ps(); + const __m128 maxv = _mm_set1_ps( (float) Clamp ); + const __m128 om = _mm_set1_ps( OutMul ); + + unsigned int prevrm = _MM_GET_ROUNDING_MODE(); + _MM_SET_ROUNDING_MODE( _MM_ROUND_NEAREST ); + + if( sizeof( op[ 0 ]) == 4 ) + { + while( l4 != 0 ) + { + const __m128 cv = _mm_max_ps( _mm_min_ps( + _mm_mul_ps( _mm_load_ps( ip ), om ), maxv ), minv ); + + _mm_storeu_si128( (__m128i*) op, _mm_cvtps_epi32( cv )); + + ip += 4; + op += 4; + l4--; + } + } + else + if( sizeof( op[ 0 ]) == 2 ) + { + while( l4 != 0 ) + { + const __m128 cv = _mm_max_ps( _mm_min_ps( + _mm_mul_ps( _mm_load_ps( ip ), om ), maxv ), minv ); + + const __m128i v32 = _mm_cvtps_epi32( cv ); + const __m128i v16s = _mm_shufflehi_epi16( + _mm_shufflelo_epi16( v32, 0 | 2 << 2 ), 0 | 2 << 2 ); + + const __m128i v16 = _mm_shuffle_epi32( v16s, 0 | 2 << 2 ); + + uint64_t tmp[ 2 ]; + _mm_storeu_si128( (__m128i*) tmp, v16 ); + *(uint64_t*) op = tmp[ 0 ]; + + ip += 4; + op += 4; + l4--; + } + } + else + { + while( l4 != 0 ) + { + const __m128 cv = _mm_max_ps( _mm_min_ps( + _mm_mul_ps( _mm_load_ps( ip ), om ), maxv ), minv ); + + const __m128i v32 = _mm_cvtps_epi32( cv ); + const __m128i v16s = _mm_shufflehi_epi16( + _mm_shufflelo_epi16( v32, 0 | 2 << 2 ), 0 | 2 << 2 ); + + const __m128i v16 = _mm_shuffle_epi32( v16s, 0 | 2 << 2 ); + const __m128i v8 = _mm_packus_epi16( v16, v16 ); + + *(uint32_t*) op = _mm_cvtsi128_si32( v8 ); + + ip += 4; + op += 4; + l4--; + } + } + + _MM_SET_ROUNDING_MODE( prevrm ); + + #elif defined( LANCIR_NEON ) + + const float32x4_t minv = vdupq_n_f32( 0.0f ); + const float32x4_t maxv = vdupq_n_f32( (float) Clamp ); + const float32x4_t om = vdupq_n_f32( OutMul ); + const float32x4_t v05 = vdupq_n_f32( 0.5f ); + + if( sizeof( op[ 0 ]) == 4 ) + { + while( l4 != 0 ) + { + const float32x4_t cv = vmaxq_f32( vminq_f32( + vmulq_f32( vld1q_f32( ip ), om ), maxv ), minv ); + + vst1q_u32( (uint32_t*) op, vcvtq_u32_f32( vaddq_f32( + cv, v05 ))); + + ip += 4; + op += 4; + l4--; + } + } + else + if( sizeof( op[ 0 ]) == 2 ) + { + while( l4 != 0 ) + { + const float32x4_t cv = vmaxq_f32( vminq_f32( + vmulq_f32( vld1q_f32( ip ), om ), maxv ), minv ); + + const uint32x4_t v32 = vcvtq_u32_f32( vaddq_f32( cv, v05 )); + const uint16x4_t v16 = vmovn_u32( v32 ); + + vst1_u16( (uint16_t*) op, v16 ); + + ip += 4; + op += 4; + l4--; + } + } + else + { + while( l4 != 0 ) + { + const float32x4_t cv = vmaxq_f32( vminq_f32( + vmulq_f32( vld1q_f32( ip ), om ), maxv ), minv ); + + const uint32x4_t v32 = vcvtq_u32_f32( vaddq_f32( cv, v05 )); + const uint16x4_t v16 = vmovn_u32( v32 ); + const uint8x8_t v8 = vmovn_u16( vcombine_u16( v16, v16 )); + + *(uint32_t*) op = vget_lane_u32( (uint32x2_t) v8, 0 ); + + ip += 4; + op += 4; + l4--; + } + } + + #else // defined( LANCIR_NEON ) + + if( IsUnityMul ) + { + while( l4 != 0 ) + { + op[ 0 ] = (T) roundclamp( ip[ 0 ], Clamp ); + op[ 1 ] = (T) roundclamp( ip[ 1 ], Clamp ); + op[ 2 ] = (T) roundclamp( ip[ 2 ], Clamp ); + op[ 3 ] = (T) roundclamp( ip[ 3 ], Clamp ); + ip += 4; + op += 4; + l4--; + } + } + else + { + while( l4 != 0 ) + { + op[ 0 ] = (T) roundclamp( ip[ 0 ] * OutMul, Clamp ); + op[ 1 ] = (T) roundclamp( ip[ 1 ] * OutMul, Clamp ); + op[ 2 ] = (T) roundclamp( ip[ 2 ] * OutMul, Clamp ); + op[ 3 ] = (T) roundclamp( ip[ 3 ] * OutMul, Clamp ); + ip += 4; + op += 4; + l4--; + } + } + + #endif // defined( LANCIR_NEON ) + + if( IsUnityMul ) + { + while( l != 0 ) + { + *op = (T) roundclamp( *ip, Clamp ); + ip++; + op++; + l--; + } + } + else + { + while( l != 0 ) + { + *op = (T) roundclamp( *ip * OutMul, Clamp ); + ip++; + op++; + l--; + } + } + } + + #define LANCIR_LF_PRE \ + const CResizePos* const rpe = rp + DstLen; \ + while( rp != rpe ) \ + { \ + const float* ip = (float*) ( (uintptr_t) sp + rp -> spo ); \ + const float* flt = rp -> flt; + + #define LANCIR_LF_POST \ + rp++; \ + } + + /** + * Function performs scanline resizing. Variants for 1-4-channel images. + * + * @param[in] sp Source scanline buffer. + * @param[out] op Destination buffer. + * @param opinc "op" increment. + * @param rp Source scanline offsets and resizing filters. + * @param kl Filter kernel's length, in taps (always an even value). + * @param DstLen Destination length, in pixels. + */ + + static void resize1( const float* const sp, float* op, const size_t opinc, + const CResizePos* rp, const int kl, const int DstLen ) + { + const int ci = kl >> 2; + + if(( kl & 3 ) == 0 ) + { + LANCIR_LF_PRE + + int c = ci; + + #if defined( LANCIR_SSE2 ) + + __m128 sum = _mm_mul_ps( _mm_load_ps( flt ), _mm_loadu_ps( ip )); + + while( --c != 0 ) + { + flt += 4; + ip += 4; + sum = _mm_add_ps( sum, _mm_mul_ps( _mm_load_ps( flt ), + _mm_loadu_ps( ip ))); + } + + sum = _mm_add_ps( sum, _mm_movehl_ps( sum, sum )); + + float res = _mm_cvtss_f32( _mm_add_ss( sum, + _mm_shuffle_ps( sum, sum, 1 ))); + + #elif defined( LANCIR_NEON ) + + float32x4_t sum = vmulq_f32( vld1q_f32( flt ), vld1q_f32( ip )); + + while( --c != 0 ) + { + flt += 4; + ip += 4; + sum = vmlaq_f32( sum, vld1q_f32( flt ), vld1q_f32( ip )); + } + + float res = vaddvq_f32( sum ); + + #else // defined( LANCIR_NEON ) + + float sum0 = flt[ 0 ] * ip[ 0 ]; + float sum1 = flt[ 1 ] * ip[ 1 ]; + float sum2 = flt[ 2 ] * ip[ 2 ]; + float sum3 = flt[ 3 ] * ip[ 3 ]; + + while( --c != 0 ) + { + flt += 4; + ip += 4; + sum0 += flt[ 0 ] * ip[ 0 ]; + sum1 += flt[ 1 ] * ip[ 1 ]; + sum2 += flt[ 2 ] * ip[ 2 ]; + sum3 += flt[ 3 ] * ip[ 3 ]; + } + + float res = ( sum0 + sum1 ) + ( sum2 + sum3 ); + + #endif // defined( LANCIR_NEON ) + + op[ 0 ] = res; + op += opinc; + + LANCIR_LF_POST + } + else + { + LANCIR_LF_PRE + + int c = ci; + + #if defined( LANCIR_SSE2 ) + + __m128 sum = _mm_mul_ps( _mm_load_ps( flt ), _mm_loadu_ps( ip )); + + while( --c != 0 ) + { + flt += 4; + ip += 4; + sum = _mm_add_ps( sum, _mm_mul_ps( _mm_load_ps( flt ), + _mm_loadu_ps( ip ))); + } + + sum = _mm_add_ps( sum, _mm_movehl_ps( sum, sum )); + + const __m128 sum2 = _mm_mul_ps( _mm_loadu_ps( flt + 2 ), + _mm_loadu_ps( ip + 2 )); + + sum = _mm_add_ps( sum, _mm_movehl_ps( sum2, sum2 )); + + float res = _mm_cvtss_f32( _mm_add_ss( sum, + _mm_shuffle_ps( sum, sum, 1 ))); + + #elif defined( LANCIR_NEON ) + + float32x4_t sum = vmulq_f32( vld1q_f32( flt ), vld1q_f32( ip )); + + while( --c != 0 ) + { + flt += 4; + ip += 4; + sum = vmlaq_f32( sum, vld1q_f32( flt ), vld1q_f32( ip )); + } + + const float32x2_t sum2 = vadd_f32( vget_high_f32( sum ), + vget_low_f32( sum )); + + float res = vaddv_f32( vmla_f32( sum2, vld1_f32( flt + 4 ), + vld1_f32( ip + 4 ))); + + #else // defined( LANCIR_NEON ) + + float sum0 = flt[ 0 ] * ip[ 0 ]; + float sum1 = flt[ 1 ] * ip[ 1 ]; + float sum2 = flt[ 2 ] * ip[ 2 ]; + float sum3 = flt[ 3 ] * ip[ 3 ]; + + while( --c != 0 ) + { + flt += 4; + ip += 4; + sum0 += flt[ 0 ] * ip[ 0 ]; + sum1 += flt[ 1 ] * ip[ 1 ]; + sum2 += flt[ 2 ] * ip[ 2 ]; + sum3 += flt[ 3 ] * ip[ 3 ]; + } + + float res = ( sum0 + sum1 ) + ( sum2 + sum3 ); + + res += flt[ 4 ] * ip[ 4 ] + flt[ 5 ] * ip[ 5 ]; + + #endif // defined( LANCIR_NEON ) + + op[ 0 ] = res; + op += opinc; + + LANCIR_LF_POST + } + } + + static void resize2( const float* const sp, float* op, const size_t opinc, + const CResizePos* rp, const int kl, const int DstLen ) + { + #if LANCIR_ALIGN > 4 + const int ci = kl >> 2; + const int cir = kl & 3; + #else // LANCIR_ALIGN > 4 + const int ci = kl >> 1; + #endif // LANCIR_ALIGN > 4 + + LANCIR_LF_PRE + + int c = ci; + + #if defined( LANCIR_AVX ) + + __m256 sum = _mm256_mul_ps( _mm256_load_ps( flt ), + _mm256_loadu_ps( ip )); + + while( --c != 0 ) + { + flt += 8; + ip += 8; + sum = _mm256_add_ps( sum, _mm256_mul_ps( _mm256_load_ps( flt ), + _mm256_loadu_ps( ip ))); + } + + __m128 res = _mm_add_ps( _mm256_extractf128_ps( sum, 0 ), + _mm256_extractf128_ps( sum, 1 )); + + if( cir == 2 ) + { + res = _mm_add_ps( res, _mm_mul_ps( _mm_load_ps( flt + 8 ), + _mm_loadu_ps( ip + 8 ))); + } + + res = _mm_add_ps( res, _mm_movehl_ps( res, res )); + + _mm_store_ss( op, res ); + _mm_store_ss( op + 1, _mm_shuffle_ps( res, res, 1 )); + + #elif defined( LANCIR_SSE2 ) + + __m128 sumA = _mm_mul_ps( _mm_load_ps( flt ), _mm_loadu_ps( ip )); + __m128 sumB = _mm_mul_ps( _mm_load_ps( flt + 4 ), + _mm_loadu_ps( ip + 4 )); + + while( --c != 0 ) + { + flt += 8; + ip += 8; + sumA = _mm_add_ps( sumA, _mm_mul_ps( _mm_load_ps( flt ), + _mm_loadu_ps( ip ))); + + sumB = _mm_add_ps( sumB, _mm_mul_ps( _mm_load_ps( flt + 4 ), + _mm_loadu_ps( ip + 4 ))); + } + + sumA = _mm_add_ps( sumA, sumB ); + + if( cir == 2 ) + { + sumA = _mm_add_ps( sumA, _mm_mul_ps( _mm_load_ps( flt + 8 ), + _mm_loadu_ps( ip + 8 ))); + } + + sumA = _mm_add_ps( sumA, _mm_movehl_ps( sumA, sumA )); + + _mm_store_ss( op, sumA ); + _mm_store_ss( op + 1, _mm_shuffle_ps( sumA, sumA, 1 )); + + #elif defined( LANCIR_NEON ) + + float32x4_t sumA = vmulq_f32( vld1q_f32( flt ), vld1q_f32( ip )); + float32x4_t sumB = vmulq_f32( vld1q_f32( flt + 4 ), + vld1q_f32( ip + 4 )); + + while( --c != 0 ) + { + flt += 8; + ip += 8; + sumA = vmlaq_f32( sumA, vld1q_f32( flt ), vld1q_f32( ip )); + sumB = vmlaq_f32( sumB, vld1q_f32( flt + 4 ), + vld1q_f32( ip + 4 )); + } + + sumA = vaddq_f32( sumA, sumB ); + + if( cir == 2 ) + { + sumA = vmlaq_f32( sumA, vld1q_f32( flt + 8 ), + vld1q_f32( ip + 8 )); + } + + vst1_f32( op, vadd_f32( vget_high_f32( sumA ), vget_low_f32( sumA ))); + + #else // defined( LANCIR_NEON ) + + const float xx = flt[ 0 ]; + const float xx2 = flt[ 1 ]; + float sum0 = xx * ip[ 0 ]; + float sum1 = xx * ip[ 1 ]; + float sum2 = xx2 * ip[ 2 ]; + float sum3 = xx2 * ip[ 3 ]; + + while( --c != 0 ) + { + flt += 2; + ip += 4; + const float xx = flt[ 0 ]; + const float xx2 = flt[ 1 ]; + sum0 += xx * ip[ 0 ]; + sum1 += xx * ip[ 1 ]; + sum2 += xx2 * ip[ 2 ]; + sum3 += xx2 * ip[ 3 ]; + } + + op[ 0 ] = sum0 + sum2; + op[ 1 ] = sum1 + sum3; + + #endif // defined( LANCIR_NEON ) + + op += opinc; + + LANCIR_LF_POST + } + + static void resize3( const float* const sp, float* op, const size_t opinc, + const CResizePos* rp, const int kl, const int DstLen ) + { + #if LANCIR_ALIGN > 4 + + const int ci = kl >> 2; + const int cir = kl & 3; + + LANCIR_LF_PRE + + float res[ 12 ]; + int c = ci; + + #if defined( LANCIR_AVX ) + + __m128 sumA = _mm_mul_ps( _mm_load_ps( flt ), _mm_loadu_ps( ip )); + __m256 sumB = _mm256_mul_ps( _mm256_loadu_ps( flt + 4 ), + _mm256_loadu_ps( ip + 4 )); + + while( --c != 0 ) + { + flt += 12; + ip += 12; + sumA = _mm_add_ps( sumA, _mm_mul_ps( _mm_load_ps( flt ), + _mm_loadu_ps( ip ))); + + sumB = _mm256_add_ps( sumB, _mm256_mul_ps( + _mm256_loadu_ps( flt + 4 ), _mm256_loadu_ps( ip + 4 ))); + } + + if( cir == 2 ) + { + sumA = _mm_add_ps( sumA, _mm_mul_ps( _mm_load_ps( flt + 12 ), + _mm_loadu_ps( ip + 12 ))); + } + + _mm_storeu_ps( res, sumA ); + + float o0 = res[ 0 ] + res[ 3 ]; + float o1 = res[ 1 ]; + float o2 = res[ 2 ]; + + _mm256_storeu_ps( res + 4, sumB ); + + o1 += res[ 4 ]; + o2 += res[ 5 ]; + + #elif defined( LANCIR_SSE2 ) + + __m128 sumA = _mm_mul_ps( _mm_load_ps( flt ), _mm_loadu_ps( ip )); + __m128 sumB = _mm_mul_ps( _mm_load_ps( flt + 4 ), + _mm_loadu_ps( ip + 4 )); + + __m128 sumC = _mm_mul_ps( _mm_load_ps( flt + 8 ), + _mm_loadu_ps( ip + 8 )); + + while( --c != 0 ) + { + flt += 12; + ip += 12; + sumA = _mm_add_ps( sumA, _mm_mul_ps( _mm_load_ps( flt ), + _mm_loadu_ps( ip ))); + + sumB = _mm_add_ps( sumB, _mm_mul_ps( _mm_load_ps( flt + 4 ), + _mm_loadu_ps( ip + 4 ))); + + sumC = _mm_add_ps( sumC, _mm_mul_ps( _mm_load_ps( flt + 8 ), + _mm_loadu_ps( ip + 8 ))); + } + + if( cir == 2 ) + { + sumA = _mm_add_ps( sumA, _mm_mul_ps( _mm_load_ps( flt + 12 ), + _mm_loadu_ps( ip + 12 ))); + } + + _mm_storeu_ps( res, sumA ); + _mm_storeu_ps( res + 4, sumB ); + + float o0 = res[ 0 ] + res[ 3 ]; + float o1 = res[ 1 ] + res[ 4 ]; + float o2 = res[ 2 ] + res[ 5 ]; + + _mm_storeu_ps( res + 8, sumC ); + + #elif defined( LANCIR_NEON ) + + float32x4_t sumA = vmulq_f32( vld1q_f32( flt ), vld1q_f32( ip )); + float32x4_t sumB = vmulq_f32( vld1q_f32( flt + 4 ), + vld1q_f32( ip + 4 )); + + float32x4_t sumC = vmulq_f32( vld1q_f32( flt + 8 ), + vld1q_f32( ip + 8 )); + + while( --c != 0 ) + { + flt += 12; + ip += 12; + sumA = vmlaq_f32( sumA, vld1q_f32( flt ), vld1q_f32( ip )); + sumB = vmlaq_f32( sumB, vld1q_f32( flt + 4 ), + vld1q_f32( ip + 4 )); + + sumC = vmlaq_f32( sumC, vld1q_f32( flt + 8 ), + vld1q_f32( ip + 8 )); + } + + if( cir == 2 ) + { + sumA = vmlaq_f32( sumA, vld1q_f32( flt + 12 ), + vld1q_f32( ip + 12 )); + } + + vst1q_f32( res, sumA ); + vst1q_f32( res + 4, sumB ); + + float o0 = res[ 0 ] + res[ 3 ]; + float o1 = res[ 1 ] + res[ 4 ]; + float o2 = res[ 2 ] + res[ 5 ]; + + vst1q_f32( res + 8, sumC ); + + #endif // defined( LANCIR_NEON ) + + o0 += res[ 6 ] + res[ 9 ]; + o1 += res[ 7 ] + res[ 10 ]; + o2 += res[ 8 ] + res[ 11 ]; + + if( cir == 2 ) + { + o1 += flt[ 16 ] * ip[ 16 ]; + o2 += flt[ 17 ] * ip[ 17 ]; + } + + op[ 0 ] = o0; + op[ 1 ] = o1; + op[ 2 ] = o2; + + #else // LANCIR_ALIGN > 4 + + const int ci = kl >> 1; + + LANCIR_LF_PRE + + int c = ci; + + const float xx = flt[ 0 ]; + float sum0 = xx * ip[ 0 ]; + float sum1 = xx * ip[ 1 ]; + float sum2 = xx * ip[ 2 ]; + const float xx2 = flt[ 1 ]; + float sum3 = xx2 * ip[ 3 ]; + float sum4 = xx2 * ip[ 4 ]; + float sum5 = xx2 * ip[ 5 ]; + + while( --c != 0 ) + { + flt += 2; + ip += 6; + const float xx = flt[ 0 ]; + sum0 += xx * ip[ 0 ]; + sum1 += xx * ip[ 1 ]; + sum2 += xx * ip[ 2 ]; + const float xx2 = flt[ 1 ]; + sum3 += xx2 * ip[ 3 ]; + sum4 += xx2 * ip[ 4 ]; + sum5 += xx2 * ip[ 5 ]; + } + + op[ 0 ] = sum0 + sum3; + op[ 1 ] = sum1 + sum4; + op[ 2 ] = sum2 + sum5; + + #endif // LANCIR_ALIGN > 4 + + op += opinc; + + LANCIR_LF_POST + } + + static void resize4( const float* const sp, float* op, const size_t opinc, + const CResizePos* rp, const int kl, const int DstLen ) + { + #if LANCIR_ALIGN > 4 + const int ci = kl >> 1; + #else // LANCIR_ALIGN > 4 + const int ci = kl; + #endif // LANCIR_ALIGN > 4 + + LANCIR_LF_PRE + + int c = ci; + + #if defined( LANCIR_AVX ) + + __m256 sum = _mm256_mul_ps( _mm256_load_ps( flt ), + _mm256_loadu_ps( ip )); + + while( --c != 0 ) + { + flt += 8; + ip += 8; + sum = _mm256_add_ps( sum, _mm256_mul_ps( _mm256_load_ps( flt ), + _mm256_loadu_ps( ip ))); + } + + _mm_store_ps( op, _mm_add_ps( _mm256_extractf128_ps( sum, 0 ), + _mm256_extractf128_ps( sum, 1 ))); + + #elif defined( LANCIR_SSE2 ) + + __m128 sumA = _mm_mul_ps( _mm_load_ps( flt ), _mm_load_ps( ip )); + __m128 sumB = _mm_mul_ps( _mm_load_ps( flt + 4 ), + _mm_load_ps( ip + 4 )); + + while( --c != 0 ) + { + flt += 8; + ip += 8; + sumA = _mm_add_ps( sumA, _mm_mul_ps( _mm_load_ps( flt ), + _mm_load_ps( ip ))); + + sumB = _mm_add_ps( sumB, _mm_mul_ps( _mm_load_ps( flt + 4 ), + _mm_load_ps( ip + 4 ))); + } + + _mm_store_ps( op, _mm_add_ps( sumA, sumB )); + + #elif defined( LANCIR_NEON ) + + float32x4_t sumA = vmulq_f32( vld1q_f32( flt ), vld1q_f32( ip )); + float32x4_t sumB = vmulq_f32( vld1q_f32( flt + 4 ), + vld1q_f32( ip + 4 )); + + while( --c != 0 ) + { + flt += 8; + ip += 8; + sumA = vmlaq_f32( sumA, vld1q_f32( flt ), vld1q_f32( ip )); + sumB = vmlaq_f32( sumB, vld1q_f32( flt + 4 ), + vld1q_f32( ip + 4 )); + } + + vst1q_f32( op, vaddq_f32( sumA, sumB )); + + #else // defined( LANCIR_NEON ) + + const float xx = flt[ 0 ]; + float sum0 = xx * ip[ 0 ]; + float sum1 = xx * ip[ 1 ]; + float sum2 = xx * ip[ 2 ]; + float sum3 = xx * ip[ 3 ]; + + while( --c != 0 ) + { + flt++; + ip += 4; + const float xx = flt[ 0 ]; + sum0 += xx * ip[ 0 ]; + sum1 += xx * ip[ 1 ]; + sum2 += xx * ip[ 2 ]; + sum3 += xx * ip[ 3 ]; + } + + op[ 0 ] = sum0; + op[ 1 ] = sum1; + op[ 2 ] = sum2; + op[ 3 ] = sum3; + + #endif // defined( LANCIR_NEON ) + + op += opinc; + + LANCIR_LF_POST + } + + #undef LANCIR_LF_PRE + #undef LANCIR_LF_POST +}; + +#undef LANCIR_PI +#undef LANCIR_ALIGN + +} // namespace avir + +#endif // AVIR_CLANCIR_INCLUDED diff --git a/Common/Loader/CMakeLists.txt b/Common/Loader/CMakeLists.txt index 11e8fb95..2701aeb7 100644 --- a/Common/Loader/CMakeLists.txt +++ b/Common/Loader/CMakeLists.txt @@ -19,6 +19,7 @@ set(ssLoader_SRCS ssloader_ssce.cpp ssloader_ssee.cpp ssloader_ssqe.cpp + ssloader_ssse.cpp SsEffectBehavior.cpp SsEffectElement.cpp ssstring_uty.cpp @@ -28,6 +29,26 @@ set(ssLoader_SRCS ssInterpolation.cpp ssattribute.cpp sscharconverter.cpp + sscharmap.cpp + + +partvalues/sspartvalue.cpp +partvalues/sspartvalueshape.cpp +partvalues/sspartvaluetext.cpp +partvalues/sspartvaluenines.cpp + +shape/sspolygon.cpp +shape/ssvertex.cpp + +shape/ssshape.cpp +shape/ssshapearrow.cpp +shape/ssshaperectangle.cpp +shape/ssshapestar.cpp +shape/ssshapetriangle.cpp + +nineslice/ssnines.cpp + +text/ssfontdesc.cpp ) #if(APPLE AND (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")) # set(ssLoader_SRCS ${ssLoader_SRCS} sscharconverter_mac.mm) @@ -43,6 +64,7 @@ set(ssLoader_HEADERS ssloader_ssce.h ssloader_ssee.h ssloader_ssqe.h + ssloader_ssse.h sstypes.h ssvalue.h ssInterpolation.h @@ -50,6 +72,25 @@ set(ssLoader_HEADERS ssstring_uty.h # ${CMAKE_CURRENT_SOURCE_DIR}/../Animator/ssplayer_animedecode.h sscharconverter.h + sscharmap.h + +partvalues/sspartvalue.h +partvalues/sspartvalueshape.h +partvalues/sspartvaluetext.h +partvalues/sspartvaluenines.h + + +shape/sspolygon.h +shape/ssvertex.h +shape/ssshape.h +shape/ssshapearrow.h +shape/ssshaperectangle.h +shape/ssshapestar.h +shape/ssshapetriangle.h +nineslice/ssnines.h + +text/ssfontdesc.h + ) include_directories(${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/Common/Loader/SsEffectBehavior.cpp b/Common/Loader/SsEffectBehavior.cpp index f698fd68..34d7e9ad 100644 --- a/Common/Loader/SsEffectBehavior.cpp +++ b/Common/Loader/SsEffectBehavior.cpp @@ -3,7 +3,7 @@ #include #include -namespace spritestudio6 +namespace SpriteStudio { SsEffectBehavior::~SsEffectBehavior() @@ -68,5 +68,5 @@ void SsEffectBehavior::EffectElementLoader(ISsXmlArchiver* ar) } -} // namespace spritestudio6 +} // namespace SpriteStudio diff --git a/Common/Loader/SsEffectBehavior.h b/Common/Loader/SsEffectBehavior.h index 20d92e41..c790109f 100644 --- a/Common/Loader/SsEffectBehavior.h +++ b/Common/Loader/SsEffectBehavior.h @@ -7,7 +7,7 @@ #include -namespace spritestudio6 +namespace SpriteStudio { class SsEffectElementBase; @@ -56,6 +56,6 @@ class SsEffectBehavior -} // namespace spritestudio6 +} // namespace SpriteStudio #endif diff --git a/Common/Loader/SsEffectElement.cpp b/Common/Loader/SsEffectElement.cpp index 3b11a658..c713393d 100644 --- a/Common/Loader/SsEffectElement.cpp +++ b/Common/Loader/SsEffectElement.cpp @@ -14,9 +14,9 @@ #include "ssplayer_render.h" #include "ssplayer_effectfunction.h" */ -namespace spritestudio6 +namespace SpriteStudio { -} // namespace spritestudio6 +} // namespace SpriteStudio diff --git a/Common/Loader/SsEffectElement.h b/Common/Loader/SsEffectElement.h index 03f76dae..bc63e331 100644 --- a/Common/Loader/SsEffectElement.h +++ b/Common/Loader/SsEffectElement.h @@ -6,7 +6,7 @@ #include "ssarchiver.h" #include "SsEffectElement.h" -namespace spritestudio6 +namespace SpriteStudio { enum EffectPartType @@ -720,6 +720,6 @@ class ParticleInfiniteEmitEnabled : public SsEffectElementBase -} // namespace spritestudio6 +} // namespace SpriteStudio #endif diff --git a/Common/Loader/nineslice/ssnines.cpp b/Common/Loader/nineslice/ssnines.cpp new file mode 100644 index 00000000..589fa3f3 --- /dev/null +++ b/Common/Loader/nineslice/ssnines.cpp @@ -0,0 +1,590 @@ +#include "ssnines.h" + +//#include "ssmath.h" +#include "ssplayer_math.h" + + +namespace SpriteStudio +{ + + //! コンストラクタ + SsNines::SsNines() + { + setCoord(SsRectF(0, 0, 1, 1)); + setRegion(SsRectF(0, 0, 1, 1)); + setMargin(SsMargins(0, 0, 0, 0)); + setFillMode(0); + setSize(SsSizeF(1, 1)); + + m_bUpdate = true; + + m_Polygon.clear(); + } + + //! デストラクタ + SsNines::~SsNines() + { + } + + //! 座標を設定 + void SsNines::setCoord(const SsRectF& coord) + { + if (m_Coord != coord) { + m_Coord = coord; + m_bUpdate = true; + } + } + + //! 範囲を設定 + void SsNines::setRegion(const SsRectF& region) + { + if (m_Region != region) { + m_Region = region; + m_bUpdate = true; + } + } + + //! マージンを設定 + void SsNines::setMargin(const SsMargins& margin) + { + if (m_Margin != margin) { + m_Margin = margin; + m_bUpdate = true; + } + } + + //! フィルモードを設定 + void SsNines::setFillMode(int eFillMode) + { + if (m_eFillMode != eFillMode) { + m_eFillMode = eFillMode; + m_bUpdate = true; + } + } + + //! サイズを設定 + void SsNines::setSize(const SsSizeF& size) + { + if (m_Size != size) { + m_Size = size; + m_bUpdate = true; + } + } + + //! 座標を取得 + SsRectF SsNines::getCoord() const + { + return m_Coord; + } + + //! 範囲を取得 + SsRectF SsNines::getRegion() const + { + return m_Region; + } + + //! マージンを取得 + SsMargins SsNines::getMargin() const + { + return m_Margin; + } + + //! フィルモードを取得 + int SsNines::getFillMode() const + { + return m_eFillMode; + } + + //! サイズを取得 + SsSizeF SsNines::getSize() const + { + return m_Size; + } + + bool SsNines::update() + { + bool bUpdate = (m_bUpdate); + + if (!bUpdate) { + return false; + } + + updateSafeMargin(); + updatePoints(); + + createPolygon(); + + m_bUpdate = false; + + return true; + } + + //! ポリゴンを取得 + const SsPolygon& SsNines::getPolygon() const + { + return m_Polygon; + } + + //! ポリゴンを生成 + bool SsNines::createPolygon() + { + bool bResult = true; + + m_Polygon.clear(); + + m_Polygon.setVertexOrder(SsPolygon::VO_TriangleStrip); + + switch (m_eFillMode) { + case 0: + bResult = createStretchPolygon(); + break; + case 1: + bResult = createTilePolygon(); + break; + default: + break; + } + + return bResult; + } + + void SsNines::updateSafeMargin() + { + int iDiff; + int iHalf; + + iDiff = m_Margin.left() + m_Margin.right() - m_Coord.width(); + + if (iDiff > 0) { + iHalf = iDiff / 2; + + m_SafeMargin.setLeft(m_Margin.left() - iHalf); + m_SafeMargin.setRight(m_Margin.right() - (iDiff - iHalf)); + } + else { + m_SafeMargin.setLeft(m_Margin.left()); + m_SafeMargin.setRight(m_Margin.right()); + } + + iDiff = m_Margin.top() + m_Margin.bottom() - m_Coord.height(); + + if (iDiff > 0) { + iHalf = iDiff / 2; + + m_SafeMargin.setTop(m_Margin.top() - iHalf); + m_SafeMargin.setBottom(m_Margin.bottom() - (iDiff - iHalf)); + } + else { + m_SafeMargin.setTop(m_Margin.top()); + m_SafeMargin.setBottom(m_Margin.bottom()); + } + } + + bool SsNines::updatePoints() + { + m_fX2 = m_Size.width() * 0.5f; + m_fY2 = m_Size.height() * 0.5f; + m_f0X = -m_fX2; + m_f3X = m_fX2; + m_f1X = m_f0X + m_SafeMargin.left(); + m_f2X = m_f3X - m_SafeMargin.right(); + m_f0Y = -m_fY2; + m_f3Y = m_fY2; + m_f1Y = m_f0Y + m_SafeMargin.bottom(); + m_f2Y = m_f3Y - m_SafeMargin.top(); + m_f0U = m_Coord.left() / m_Region.width(); + m_f3U = m_Coord.right() / m_Region.width(); + m_f1U = (m_Coord.left() + m_SafeMargin.left()) / m_Region.width(); + m_f2U = (m_Coord.right() - m_SafeMargin.right()) / m_Region.width(); + m_f0V = m_Coord.bottom() / m_Region.height(); + m_f3V = m_Coord.top() / m_Region.height(); + m_f1V = (m_Coord.bottom() - m_SafeMargin.bottom()) / m_Region.height(); + m_f2V = (m_Coord.top() + m_SafeMargin.top()) / m_Region.height(); + + return true; + } + + bool SsNines::createStretchPolygon() + { + m_Polygon.addVertex(SsVertex(SsPoint2(m_f0X, m_f0Y), SsPoint2(m_f0U, m_f0V))); + m_Polygon.addVertex(SsVertex(SsPoint2(m_f0X, m_f1Y), SsPoint2(m_f0U, m_f1V))); + m_Polygon.addVertex(SsVertex(SsPoint2(m_f1X, m_f0Y), SsPoint2(m_f1U, m_f0V))); + m_Polygon.addVertex(SsVertex(SsPoint2(m_f1X, m_f1Y), SsPoint2(m_f1U, m_f1V))); + + m_Polygon.addVertex(SsVertex(SsPoint2(m_f2X, m_f0Y), SsPoint2(m_f2U, m_f0V))); + m_Polygon.addVertex(SsVertex(SsPoint2(m_f2X, m_f1Y), SsPoint2(m_f2U, m_f1V))); + m_Polygon.addVertex(SsVertex(SsPoint2(m_f3X, m_f0Y), SsPoint2(m_f3U, m_f0V))); + m_Polygon.addVertex(SsVertex(SsPoint2(m_f3X, m_f1Y), SsPoint2(m_f3U, m_f1V))); + + m_Polygon.addVertex(SsVertex(SsPoint2(m_f0X, m_f2Y), SsPoint2(m_f0U, m_f2V))); + m_Polygon.addVertex(SsVertex(SsPoint2(m_f0X, m_f3Y), SsPoint2(m_f0U, m_f3V))); + m_Polygon.addVertex(SsVertex(SsPoint2(m_f1X, m_f2Y), SsPoint2(m_f1U, m_f2V))); + m_Polygon.addVertex(SsVertex(SsPoint2(m_f1X, m_f3Y), SsPoint2(m_f1U, m_f3V))); + + m_Polygon.addVertex(SsVertex(SsPoint2(m_f2X, m_f2Y), SsPoint2(m_f2U, m_f2V))); + m_Polygon.addVertex(SsVertex(SsPoint2(m_f2X, m_f3Y), SsPoint2(m_f2U, m_f3V))); + m_Polygon.addVertex(SsVertex(SsPoint2(m_f3X, m_f2Y), SsPoint2(m_f3U, m_f2V))); + m_Polygon.addVertex(SsVertex(SsPoint2(m_f3X, m_f3Y), SsPoint2(m_f3U, m_f3V))); + + m_Polygon.addVertexIndex(0); + m_Polygon.addVertexIndex(1); + m_Polygon.addVertexIndex(2); + m_Polygon.addVertexIndex(3); + m_Polygon.addVertexIndex(4); + m_Polygon.addVertexIndex(5); + m_Polygon.addVertexIndex(6); + m_Polygon.addVertexIndex(7); + m_Polygon.addStride(8); + + m_Polygon.addVertexIndex(8); + m_Polygon.addVertexIndex(9); + m_Polygon.addVertexIndex(10); + m_Polygon.addVertexIndex(11); + m_Polygon.addVertexIndex(12); + m_Polygon.addVertexIndex(13); + m_Polygon.addVertexIndex(14); + m_Polygon.addVertexIndex(15); + m_Polygon.addStride(8); + + m_Polygon.addVertexIndex(1); + m_Polygon.addVertexIndex(8); + m_Polygon.addVertexIndex(3); + m_Polygon.addVertexIndex(10); + m_Polygon.addVertexIndex(5); + m_Polygon.addVertexIndex(12); + m_Polygon.addVertexIndex(7); + m_Polygon.addVertexIndex(14); + m_Polygon.addStride(8); + + return true; + } + + bool SsNines::createTilePolygon() + { + bool bResult = true; + + bResult = bResult && createTilePolygonCC(); + + bResult = bResult && createTilePolygonLC(); + bResult = bResult && createTilePolygonRC(); + bResult = bResult && createTilePolygonCT(); + bResult = bResult && createTilePolygonCB(); + + bResult = bResult && createTilePolygonLT(); + bResult = bResult && createTilePolygonRT(); + bResult = bResult && createTilePolygonLB(); + bResult = bResult && createTilePolygonRB(); + + return bResult; + } + + bool SsNines::createTilePolygonCC() + { + float fDstW = m_f2X - m_f1X; + float fDstH = m_f2Y - m_f1Y; + float fSrcW = m_Coord.width() - m_SafeMargin.left() - m_SafeMargin.right(); + float fSrcH = m_Coord.height() - m_SafeMargin.top() - m_SafeMargin.bottom(); + float fX0; + float fY0; + float fX1; + float fY1; + float fU0; + float fV0; + float fU1; + float fV1; + int iDivW = SsMath::Ceil(fDstW / fSrcW); + int iDivH = SsMath::Ceil(fDstH / fSrcH); + int iStride; + int iIndex = m_Polygon.getVertexCount(); + + for (int iY = 0; iY < iDivH; iY++) { + fY0 = m_f1Y + (fSrcH * iY); + fY1 = fY0 + fSrcH; + + fV0 = m_f1V; + fV1 = m_f2V; + + if (fY1 > m_f2Y) { + fV1 = (m_Coord.top() + m_SafeMargin.top() + (fY1 - m_f2Y)) / m_Region.height(); + fY1 = m_f2Y; + } + + for (int iX = 0; iX < iDivW; iX++) { + fX0 = m_f1X + (fSrcW * iX); + fX1 = fX0 + fSrcW; + + fU0 = m_f1U; + fU1 = m_f2U; + + if (fX1 > m_f2X) { + fU1 = (m_Coord.right() - m_SafeMargin.right() - (fX1 - m_f2X)) / m_Region.width(); + fX1 = m_f2X; + } + + m_Polygon.addVertex(SsVertex(SsPoint2(fX0, fY0), SsPoint2(fU0, fV0))); + m_Polygon.addVertex(SsVertex(SsPoint2(fX0, fY1), SsPoint2(fU0, fV1))); + m_Polygon.addVertex(SsVertex(SsPoint2(fX1, fY0), SsPoint2(fU1, fV0))); + m_Polygon.addVertex(SsVertex(SsPoint2(fX1, fY1), SsPoint2(fU1, fV1))); + } + + iStride = iDivW * 4; + + for (int i = 0; i < iStride; i++) { + m_Polygon.addVertexIndex(iIndex++); + } + + m_Polygon.addStride(iStride); + } + + return true; + } + + bool SsNines::createTilePolygonLC() + { + float fDstH = m_f2Y - m_f1Y; + float fSrcH = m_Coord.height() - m_SafeMargin.top() - m_SafeMargin.bottom(); + float fY0; + float fY1; + float fV0; + float fV1; + int iDivH = SsMath::Ceil(fDstH / fSrcH); + int iStride; + int iIndex = m_Polygon.getVertexCount(); + + for (int iY = 0; iY < iDivH; iY++) { + fY0 = m_f1Y + (fSrcH * iY); + fY1 = fY0 + fSrcH; + + fV0 = m_f1V; + fV1 = m_f2V; + + if (fY1 > m_f2Y) { + fV1 = (m_Coord.top() + m_SafeMargin.top() + (fY1 - m_f2Y)) / m_Region.height(); + fY1 = m_f2Y; + } + + m_Polygon.addVertex(SsVertex(SsPoint2(m_f0X, fY0), SsPoint2(m_f0U, fV0))); + m_Polygon.addVertex(SsVertex(SsPoint2(m_f1X, fY0), SsPoint2(m_f1U, fV0))); + m_Polygon.addVertex(SsVertex(SsPoint2(m_f0X, fY1), SsPoint2(m_f0U, fV1))); + m_Polygon.addVertex(SsVertex(SsPoint2(m_f1X, fY1), SsPoint2(m_f1U, fV1))); + } + + iStride = iDivH * 4; + + for (int i = 0; i < iStride; i++) { + m_Polygon.addVertexIndex(iIndex++); + } + + m_Polygon.addStride(iStride); + + return true; + } + + bool SsNines::createTilePolygonRC() + { + float fDstH = m_f2Y - m_f1Y; + float fSrcH = m_Coord.height() - m_SafeMargin.top() - m_SafeMargin.bottom(); + float fY0; + float fY1; + float fV0; + float fV1; + int iDivH = SsMath::Ceil(fDstH / fSrcH); + int iStride; + int iIndex = m_Polygon.getVertexCount(); + + for (int iY = 0; iY < iDivH; iY++) { + fY0 = m_f1Y + (fSrcH * iY); + fY1 = fY0 + fSrcH; + + fV0 = m_f1V; + fV1 = m_f2V; + + if (fY1 > m_f2Y) { + fV1 = (m_Coord.top() + m_SafeMargin.top() + (fY1 - m_f2Y)) / m_Region.height(); + fY1 = m_f2Y; + } + + m_Polygon.addVertex(SsVertex(SsPoint2(m_f2X, fY0), SsPoint2(m_f2U, fV0))); + m_Polygon.addVertex(SsVertex(SsPoint2(m_f3X, fY0), SsPoint2(m_f3U, fV0))); + m_Polygon.addVertex(SsVertex(SsPoint2(m_f2X, fY1), SsPoint2(m_f2U, fV1))); + m_Polygon.addVertex(SsVertex(SsPoint2(m_f3X, fY1), SsPoint2(m_f3U, fV1))); + } + + iStride = iDivH * 4; + + for (int i = 0; i < iStride; i++) { + m_Polygon.addVertexIndex(iIndex++); + } + + m_Polygon.addStride(iStride); + + return true; + } + + bool SsNines::createTilePolygonCT() + { + float fDstW = m_f2X - m_f1X; + float fSrcW = m_Coord.width() - m_SafeMargin.left() - m_SafeMargin.right(); + float fX0; + float fX1; + float fU0; + float fU1; + int iDivW = SsMath::Ceil(fDstW / fSrcW); + int iStride; + int iIndex = m_Polygon.getVertexCount(); + + for (int iX = 0; iX < iDivW; iX++) { + fX0 = m_f1X + (fSrcW * iX); + fX1 = fX0 + fSrcW; + + fU0 = m_f1U; + fU1 = m_f2U; + + if (fX1 > m_f2X) { + fU1 = (m_Coord.right() - m_SafeMargin.right() - (fX1 - m_f2X)) / m_Region.width(); + fX1 = m_f2X; + } + + m_Polygon.addVertex(SsVertex(SsPoint2(fX0, m_f0Y), SsPoint2(fU0, m_f0V))); + m_Polygon.addVertex(SsVertex(SsPoint2(fX0, m_f1Y), SsPoint2(fU0, m_f1V))); + m_Polygon.addVertex(SsVertex(SsPoint2(fX1, m_f0Y), SsPoint2(fU1, m_f0V))); + m_Polygon.addVertex(SsVertex(SsPoint2(fX1, m_f1Y), SsPoint2(fU1, m_f1V))); + } + + iStride = iDivW * 4; + + for (int i = 0; i < iStride; i++) { + m_Polygon.addVertexIndex(iIndex++); + } + + m_Polygon.addStride(iStride); + + return true; + } + + bool SsNines::createTilePolygonCB() + { + float fDstW = m_f2X - m_f1X; + float fSrcW = m_Coord.width() - m_SafeMargin.left() - m_SafeMargin.right(); + float fX0; + float fX1; + float fU0; + float fU1; + int iDivW = SsMath::Ceil(fDstW / fSrcW); + int iStride; + int iIndex = m_Polygon.getVertexCount(); + + for (int iX = 0; iX < iDivW; iX++) { + fX0 = m_f1X + (fSrcW * iX); + fX1 = fX0 + fSrcW; + + fU0 = m_f1U; + fU1 = m_f2U; + + if (fX1 > m_f2X) { + fU1 = (m_Coord.right() - m_SafeMargin.right() - (fX1 - m_f2X)) / m_Region.width(); + fX1 = m_f2X; + } + + m_Polygon.addVertex(SsVertex(SsPoint2(fX0, m_f2Y), SsPoint2(fU0, m_f2V))); + m_Polygon.addVertex(SsVertex(SsPoint2(fX0, m_f3Y), SsPoint2(fU0, m_f3V))); + m_Polygon.addVertex(SsVertex(SsPoint2(fX1, m_f2Y), SsPoint2(fU1, m_f2V))); + m_Polygon.addVertex(SsVertex(SsPoint2(fX1, m_f3Y), SsPoint2(fU1, m_f3V))); + } + + iStride = iDivW * 4; + + for (int i = 0; i < iStride; i++) { + m_Polygon.addVertexIndex(iIndex++); + } + + m_Polygon.addStride(iStride); + + return true; + } + + bool SsNines::createTilePolygonLT() + { + int iStride; + int iIndex = m_Polygon.getVertexCount(); + + m_Polygon.addVertex(SsVertex(SsPoint2(m_f0X, m_f0Y), SsPoint2(m_f0U, m_f0V))); + m_Polygon.addVertex(SsVertex(SsPoint2(m_f0X, m_f1Y), SsPoint2(m_f0U, m_f1V))); + m_Polygon.addVertex(SsVertex(SsPoint2(m_f1X, m_f0Y), SsPoint2(m_f1U, m_f0V))); + m_Polygon.addVertex(SsVertex(SsPoint2(m_f1X, m_f1Y), SsPoint2(m_f1U, m_f1V))); + + iStride = 4; + + for (int i = 0; i < iStride; i++) { + m_Polygon.addVertexIndex(iIndex++); + } + + m_Polygon.addStride(iStride); + + return true; + } + + bool SsNines::createTilePolygonRT() + { + int iStride; + int iIndex = m_Polygon.getVertexCount(); + + m_Polygon.addVertex(SsVertex(SsPoint2(m_f2X, m_f0Y), SsPoint2(m_f2U, m_f0V))); + m_Polygon.addVertex(SsVertex(SsPoint2(m_f2X, m_f1Y), SsPoint2(m_f2U, m_f1V))); + m_Polygon.addVertex(SsVertex(SsPoint2(m_f3X, m_f0Y), SsPoint2(m_f3U, m_f0V))); + m_Polygon.addVertex(SsVertex(SsPoint2(m_f3X, m_f1Y), SsPoint2(m_f3U, m_f1V))); + + iStride = 4; + + for (int i = 0; i < iStride; i++) { + m_Polygon.addVertexIndex(iIndex++); + } + + m_Polygon.addStride(iStride); + + return true; + } + + bool SsNines::createTilePolygonLB() + { + int iStride; + int iIndex = m_Polygon.getVertexCount(); + + m_Polygon.addVertex(SsVertex(SsPoint2(m_f0X, m_f2Y), SsPoint2(m_f0U, m_f2V))); + m_Polygon.addVertex(SsVertex(SsPoint2(m_f0X, m_f3Y), SsPoint2(m_f0U, m_f3V))); + m_Polygon.addVertex(SsVertex(SsPoint2(m_f1X, m_f2Y), SsPoint2(m_f1U, m_f2V))); + m_Polygon.addVertex(SsVertex(SsPoint2(m_f1X, m_f3Y), SsPoint2(m_f1U, m_f3V))); + + iStride = 4; + + for (int i = 0; i < iStride; i++) { + m_Polygon.addVertexIndex(iIndex++); + } + + m_Polygon.addStride(iStride); + + return true; + } + + bool SsNines::createTilePolygonRB() + { + int iStride; + int iIndex = m_Polygon.getVertexCount(); + + m_Polygon.addVertex(SsVertex(SsPoint2(m_f2X, m_f2Y), SsPoint2(m_f2U, m_f2V))); + m_Polygon.addVertex(SsVertex(SsPoint2(m_f2X, m_f3Y), SsPoint2(m_f2U, m_f3V))); + m_Polygon.addVertex(SsVertex(SsPoint2(m_f3X, m_f2Y), SsPoint2(m_f3U, m_f2V))); + m_Polygon.addVertex(SsVertex(SsPoint2(m_f3X, m_f3Y), SsPoint2(m_f3U, m_f3V))); + + iStride = 4; + + for (int i = 0; i < iStride; i++) { + m_Polygon.addVertexIndex(iIndex++); + } + + m_Polygon.addStride(iStride); + + return true; + } + +}; \ No newline at end of file diff --git a/Common/Loader/nineslice/ssnines.h b/Common/Loader/nineslice/ssnines.h new file mode 100644 index 00000000..6b9a5cea --- /dev/null +++ b/Common/Loader/nineslice/ssnines.h @@ -0,0 +1,155 @@ +#ifndef SSNINES_H +#define SSNINES_H + +#include "../sstypes.h" +#include "../shape/sspolygon.h" + +namespace SpriteStudio +{ + + /*! + * \class SsNines + * \brief 9スライス + */ + class SsNines + { + public: + //! コンストラクタ + SsNines(); + + //! デストラクタ + virtual ~SsNines(); + + //! 座標を設定 + /*! + * \param 座標 + */ + void setCoord(const SsRectF& coord); + + //! 範囲を設定 + /*! + * \param 範囲 + */ + void setRegion(const SsRectF& region); + + //! マージンを設定 + /*! + * \margin マージン + */ + void setMargin(const SsMargins& margin); + + //! フィルモードを設定 + /*! + * \eFillMode フィルモード + */ + void setFillMode(int eFillMode); + + //! サイズを設定 + /*! + * \param サイズ + */ + void setSize(const SsSizeF& size); + + //! 座標を取得 + /*! + * \return 座標 + */ + SsRectF getCoord() const; + + //! 範囲を取得 + /*! + * \return 範囲 + */ + SsRectF getRegion() const; + + //! マージンを取得 + /*! + * \return マージン + */ + SsMargins getMargin() const; + + //! フィルモードを取得 + /*! + * \return フィルモード + */ + int getFillMode() const; + + //! サイズを取得 + /*! + * \return サイズ + */ + SsSizeF getSize() const; + + bool update(); + + //! ポリゴンを取得 + /*! + * \return ポリゴン + */ + const SsPolygon& getPolygon() const; + + protected: + SsRectF m_Coord; //!< 座標 + SsRectF m_Region; //!< 範囲 + SsMargins m_Margin; //!< マージン + int m_eFillMode; //!< フィルモード + SsSizeF m_Size; //!< サイズ + bool m_bUpdate; //!< 更新が必要かどうか + + SsMargins m_SafeMargin; //!< マージン + + float m_fX2; + float m_fY2; + + float m_f0X; + float m_f1X; + float m_f2X; + float m_f3X; + + float m_f0Y; + float m_f1Y; + float m_f2Y; + float m_f3Y; + + float m_f0U; + float m_f1U; + float m_f2U; + float m_f3U; + + float m_f0V; + float m_f1V; + float m_f2V; + float m_f3V; + + SsPolygon m_Polygon; //!< ポリゴン + + //! ポリゴンを生成 + /*! + * \return 成功したかどうか + */ + virtual bool createPolygon(); + + private: + void updateSafeMargin(); + + bool updatePoints(); + + bool createStretchPolygon(); + bool createTilePolygon(); + + bool createTilePolygonCC(); + + bool createTilePolygonLC(); + bool createTilePolygonRC(); + bool createTilePolygonCT(); + bool createTilePolygonCB(); + + bool createTilePolygonLT(); + bool createTilePolygonRT(); + bool createTilePolygonLB(); + bool createTilePolygonRB(); + }; + +}; + +#endif // SSNINES_H diff --git a/Common/Loader/partvalues/sspartvalue.cpp b/Common/Loader/partvalues/sspartvalue.cpp new file mode 100644 index 00000000..c60819ef --- /dev/null +++ b/Common/Loader/partvalues/sspartvalue.cpp @@ -0,0 +1,32 @@ +/*! + * \file sspartvalue.cpp + * \author CRI Middleware Co., Ltd. +*/ +#include "sspartvalue.h" + +namespace SpriteStudio +{ + + //! コンストラクタ + SsPartValue::SsPartValue(const SsString& strTag) + { + m_strTag = strTag; + } + + //! デストラクタ + SsPartValue::~SsPartValue() + { + } + + //! タグを取得 + SsString SsPartValue::getTag() + { + return m_strTag; + } + + //! 複製 + SsPartValue* SsPartValue::duplicate() + { + return new SsPartValue(m_strTag); + } +}; \ No newline at end of file diff --git a/Common/Loader/partvalues/sspartvalue.h b/Common/Loader/partvalues/sspartvalue.h new file mode 100644 index 00000000..56135150 --- /dev/null +++ b/Common/Loader/partvalues/sspartvalue.h @@ -0,0 +1,47 @@ +/*! + * \file sspartvalue.h + * \author CRI Middleware Co., Ltd. +*/ +#ifndef SSPARTVALUE_H +#define SSPARTVALUE_H + +//#include "wtlibstring.h" +//#include "sstypes.h" +#include "../sstypes.h" + +namespace SpriteStudio +{ + /*! + * \class SsPartValue + * \brief パーツパラメータ + */ + class SsPartValue + { + public: + //! コンストラクタ + /*! + * \param strTag タグ + */ + SsPartValue(const SsString& strTag = "unknown"); + + //! デストラクタ + virtual ~SsPartValue(); + + //! タグを取得 + /*! + * \return タグ + */ + SsString getTag(); + + //! 複製 + /*! + * \return パーツパラメータ + */ + virtual SsPartValue* duplicate(); + + private: + SsString m_strTag; //!< タグ + }; +}; + +#endif // SSPARTVALUE_H diff --git a/Common/Loader/partvalues/sspartvaluenines.cpp b/Common/Loader/partvalues/sspartvaluenines.cpp new file mode 100644 index 00000000..1915f6ea --- /dev/null +++ b/Common/Loader/partvalues/sspartvaluenines.cpp @@ -0,0 +1,154 @@ +/*! + * \file sspartvaluenines.cpp + * \author CRI Middleware Co., Ltd. +*/ +#include "sstypes.h" +#include "sspartvaluenines.h" + +//#include "SsGUI.h" + + +namespace SpriteStudio +{ + + + const SsString SsPartValueNines::TAG = "nines"; //!< デフォルトタグ + + //! コンストラクタ + SsPartValueNines::SsPartValueNines() : SsPartValue(TAG) + , m_pNines(new SsNines()) + { + setMask(false); + setCell('-'); + + m_bUpdate = true; + } + + //! デストラクタ + SsPartValueNines::~SsPartValueNines() + { + if (m_pNines) { + delete m_pNines; + m_pNines = nullptr; + } + } + + //! 複製 + SsPartValue* SsPartValueNines::duplicate() + { + SsPartValueNines* pDup = new SsPartValueNines(); + + *pDup->m_pNines = *m_pNines; + + pDup->setMask(m_bMask); + pDup->setCell(m_cCell); + + return pDup; + } + + //! 座標を設定 + void SsPartValueNines::setCoord(const SsRectF& coord) + { + if (m_pNines) { + m_pNines->setCoord(coord); + + m_bUpdate = true; + } + } + + //! 範囲を設定 + void SsPartValueNines::setRegion(const SsRectF& region) + { + if (m_pNines) { + m_pNines->setRegion(region); + + m_bUpdate = true; + } + } + + //! マージンを設定 + void SsPartValueNines::setMargin(const SsMargins& margin) + { + if (m_pNines) { + m_pNines->setMargin(margin); + + m_bUpdate = true; + } + } + + //! フィルモードを設定 + void SsPartValueNines::setFillMode(int eFillMode) + { + if (m_pNines) { + m_pNines->setFillMode(eFillMode); + + m_bUpdate = true; + } + } + + //! マスクを設定 + void SsPartValueNines::setMask(bool bMask) + { + if (m_bMask != bMask) { + m_bMask = bMask; + } + } + + //! セル?を設定 + void SsPartValueNines::setCell(char cCell) + { + if (m_cCell != cCell) { + m_cCell = cCell; + } + } + + //! サイズを設定 + void SsPartValueNines::setSize(const SsSizeF& size) + { + if (m_pNines) { + m_pNines->setSize(size); + + m_bUpdate = true; + } + } + + //! マスクを取得 + bool SsPartValueNines::isMask() const + { + return m_bMask; + } + + //! セル?を取得 + char SsPartValueNines::getCell() const + { + return m_cCell; + } + + bool SsPartValueNines::update() + { + bool bUpdate = (m_bUpdate); + + if (!bUpdate) { + return false; + } + + if (m_pNines) { + m_pNines->update(); + } + + m_bUpdate = false; + + return true; + } + + //! 9スライスを取得 + const SsNines* SsPartValueNines::getNines() + { + if (!update()) { + return m_pNines; + } + + return m_pNines; + } + +}; \ No newline at end of file diff --git a/Common/Loader/partvalues/sspartvaluenines.h b/Common/Loader/partvalues/sspartvaluenines.h new file mode 100644 index 00000000..ecf01712 --- /dev/null +++ b/Common/Loader/partvalues/sspartvaluenines.h @@ -0,0 +1,110 @@ +/*! + * \file sspartvaluenines.h + * \author CRI Middleware Co., Ltd. +*/ +#ifndef SSPARTVALUENINES_H +#define SSPARTVALUENINES_H + +#include "sspartvalue.h" +#include "../nineslice/ssnines.h" + + + +namespace SpriteStudio +{ + + /*! + * \class SsPartValueNines + * \brief 9スライスパーツパラメータ + */ + class SsPartValueNines : public SsPartValue + { + public: + static const SsString TAG; //!< デフォルトタグ + + //! コンストラクタ + SsPartValueNines(); + + //! デストラクタ + ~SsPartValueNines() override; + + //! 複製 + /*! + * \return パーツパラメータ + */ + SsPartValue* duplicate() override; + + //! 座標を設定 + /*! + * \param coord 座標 + */ + void setCoord(const SsRectF& coord); + + //! 範囲を設定 + /*! + * \param coord 範囲 + */ + void setRegion(const SsRectF& region); + + //! マージンを設定 + /*! + * \param margin マージン + */ + void setMargin(const SsMargins& margin); + + //! フィルモードを設定 + /*! + * \param eFillMode フィルモード + */ + void setFillMode(int eFillMode); + + //! マスクを設定 + /*! + * \param bMask マスク + */ + void setMask(bool bMask); + + //! セル?を設定 + /*! + * \param cCell セル? + */ + void setCell(char cCell); + + //! サイズを設定 + /*! + * \param size サイズ + */ + void setSize(const SsSizeF& size); + + //! マスクを取得 + /*! + * \return マスク + */ + bool isMask() const; + + //! セル?を取得 + /*! + * \return セル? + */ + char getCell() const; + + bool update(); + + //! 9スライスを取得 + /*! + * \return シェイプ + */ + const SsNines* getNines(); + + private: + bool m_bMask; //!< マスク + char m_cCell; //!< セル? + + bool m_bUpdate; //!< 更新が必要かどうか + + SsNines* m_pNines; //!< 9スライス + }; + +}; + +#endif // SSPARTVALUENINES_H diff --git a/Common/Loader/partvalues/sspartvalueshape.cpp b/Common/Loader/partvalues/sspartvalueshape.cpp new file mode 100644 index 00000000..d4b4eac8 --- /dev/null +++ b/Common/Loader/partvalues/sspartvalueshape.cpp @@ -0,0 +1,248 @@ +/*! + * \file sspartvalueshape.cpp + * \author CRI Middleware Co., Ltd. +*/ +#include "sspartvalueshape.h" + +#include "../shape/ssshapetriangle.h" +#include "../shape/ssshaperectangle.h" +#include "../shape/ssshapearrow.h" +#include "../shape/ssshapestar.h" + + +namespace SpriteStudio +{ + + + const SsString SsPartValueShape::TAG = "shape"; //!< デフォルトタグ + + std::map SsPartValueShape::s_mapFromType; //!< タイプから文字列への変換マップ + std::map SsPartValueShape::s_mapFromTypeName; //!< タイプ名から文字列への変換マップ + + + + //! 有効なタイプのリストを取得 + SsStringList SsPartValueShape::getAvailableTypeList() + { + SsStringList list; + + if (s_mapFromType.empty()) { + initMap(); + } + + //list = s_mapFromType.values(); + + for (auto item : s_mapFromType) + { + list.push_back( item.second ); + } + + return list; + } + + //! 有効なタイプ名のリストを取得 + SsStringList SsPartValueShape::getAvailableTypeNameList() + { + SsStringList list; + + if (s_mapFromTypeName.empty()) { + initMap(); + } + + //list = s_mapFromTypeName.values(); + for (auto item : s_mapFromTypeName) + { + list.push_back(item.second); + } + + return list; + } + + //! 文字列をタイプに変換 + SsPartValueShape::Type SsPartValueShape::toType(const SsString& strType) + { + if (s_mapFromType.empty()) { + initMap(); + } + + //return s_mapFromType.key(strType, T_Unknown); + + auto result = std::find_if( + s_mapFromType.begin(), + s_mapFromType.end(), + [strType](const auto& mo) {return mo.second == strType; }); + + if (result != s_mapFromType.end()) + { + SsPartValueShape::Type foundkey = result->first; + return foundkey; + } + return T_Unknown; + } + + //! タイプを文字列に変換 + SsString SsPartValueShape::fromType(Type eType) + { + if (s_mapFromType.empty()) { + initMap(); + } + if (s_mapFromType.count(eType) > 0) + { + return s_mapFromType[eType]; + } + return "unknown"; +// return s_mapFromType.value(eType, "unknown"); + } + + //! コンストラクタ + SsPartValueShape::SsPartValueShape() : SsPartValue(TAG) + , m_pShape(nullptr) + { + setType(T_Rectangle); + + setMask(false); + + m_bUpdate = true; + } + + //! デストラクタ + SsPartValueShape::~SsPartValueShape() + { + if (m_pShape) { + delete m_pShape; + m_pShape = nullptr; + } + } + + //! 複製 + SsPartValue* SsPartValueShape::duplicate() + { + SsPartValueShape* pDup = new SsPartValueShape(); + + pDup->setType(m_eType); + + pDup->setMask(m_bMask); + + return pDup; + } + + //! タイプを設定 + void SsPartValueShape::setType(Type eType) + { + if (m_eType != eType) { + m_eType = eType; + + changeShape(eType); + + m_bUpdate = true; + } + } + + //! マスクを設定 + void SsPartValueShape::setMask(bool bMask) + { + if (m_bMask != bMask) { + m_bMask = bMask; + } + } + + //! サイズを設定 + void SsPartValueShape::setSize(const SsSizeF& size) + { + if (m_pShape) { + m_pShape->setSize(size); + + m_bUpdate = true; + } + } + + //! タイプを取得 + SsPartValueShape::Type SsPartValueShape::getType() const + { + return m_eType; + } + + //! マスクを取得 + bool SsPartValueShape::isMask() const + { + return m_bMask; + } + + bool SsPartValueShape::update() + { + bool bUpdate = (m_bUpdate); + + if (!bUpdate) { + return false; + } + + if (m_pShape) { + m_pShape->update(); + } + + m_bUpdate = false; + + return true; + } + + //! シェイプを取得 + const SsShape* SsPartValueShape::getShape() + { + if (!update()) { + return m_pShape; + } + + return m_pShape; + } + + //! マップを初期化 + void SsPartValueShape::initMap() + { + s_mapFromType.clear(); + + // s_mapFromType[T_Unknown] = "unknown"; + s_mapFromType[T_Triangle] = "triangle"; + s_mapFromType[T_Rectangle] = "rectangle"; + s_mapFromType[T_Arrow] = "arrow"; + s_mapFromType[T_Star] = "star"; + + s_mapFromTypeName.clear(); + +#if 0 //外側で定義してもらう + // s_mapFromTypeName[T_Unknown] = SsGUIString( "ShapeTypeUnknown" ).c_str(); + s_mapFromTypeName[T_Triangle] = SsGUIString("ShapeTypeTriangle").c_str(); + s_mapFromTypeName[T_Rectangle] = SsGUIString("ShapeTypeRectangle").c_str(); + s_mapFromTypeName[T_Arrow] = SsGUIString("ShapeTypeArrow").c_str(); + s_mapFromTypeName[T_Star] = SsGUIString("ShapeTypeStar").c_str(); +#endif + } + + + //! シェイプを切替 + void SsPartValueShape::changeShape(Type eType) + { + if (m_pShape) { + delete m_pShape; + m_pShape = nullptr; + } + + switch (eType) { + case T_Triangle: + m_pShape = new SsShapeTriangle(); + break; + case T_Rectangle: + m_pShape = new SsShapeRectangle(); + break; + case T_Arrow: + m_pShape = new SsShapeArrow(); + break; + case T_Star: + m_pShape = new SsShapeStar(); + break; + default: + break; + } + } + + +}; \ No newline at end of file diff --git a/Common/Loader/partvalues/sspartvalueshape.h b/Common/Loader/partvalues/sspartvalueshape.h new file mode 100644 index 00000000..87ae5a97 --- /dev/null +++ b/Common/Loader/partvalues/sspartvalueshape.h @@ -0,0 +1,137 @@ +/*! + * \file sspartvalueshape.h + * \author CRI Middleware Co., Ltd. +*/ +#ifndef SSPARTVALUESHAPE_H +#define SSPARTVALUESHAPE_H + +#include +#include "../sstypes.h" + +#include "sspartvalue.h" +#include "../shape/ssshape.h" + +namespace SpriteStudio +{ + /*! + * \class SsPartValueShape + * \brief シェイプパーツパラメータ + */ + class SsPartValueShape : public SsPartValue + { + public: + static const SsString TAG; //!< デフォルトタグ + + /*! + * \enum SsPartValueShape::Type + * \brief タイプ + */ + enum Type + { + T_Unknown = 0, //!< 不明 + T_Triangle = 3, //!< 三角形 + T_Rectangle = 4, //!< 矩形 + T_Arrow = 7, //!< 矢印形 + T_Star = 10, //!< 星形 + }; + + static std::map s_mapFromType; //!< タイプから文字列への変換マップ + static std::map s_mapFromTypeName; //!< タイプ名から文字列への変換マップ + + //! 有効なタイプのリストを取得 + /*! + * \return 有効なタイプのリスト + */ + static SsStringList getAvailableTypeList(); + + //! 有効なタイプ名のリストを取得 + /*! + * \return 有効なタイプ名のリスト + */ + static SsStringList getAvailableTypeNameList(); + + //! 文字列をタイプに変換 + /*! + * \param strType 文字列 + * \return タイプ + */ + static Type toType(const SsString& strType); + + //! タイプを文字列に変換 + /*! + * \param eType タイプ + * \return 文字列 + */ + static SsString fromType(Type eType); + + //! コンストラクタ + SsPartValueShape(); + + //! デストラクタ + ~SsPartValueShape() override; + + //! 複製 + /*! + * \return パーツパラメータ + */ + SsPartValue* duplicate() override; + + //! タイプを設定 + /*! + * \param eType タイプ + */ + void setType(Type eType); + + //! マスクを設定 + /*! + * \param bMask マスク + */ + void setMask(bool bMask); + + //! サイズを設定 + /*! + * \param size サイズ + */ + void setSize(const SsSizeF& size); + + //! タイプを取得 + /*! + * \return タイプ + */ + Type getType() const; + + //! マスクを取得 + /*! + * \return マスク + */ + bool isMask() const; + + bool update(); + + //! シェイプを取得 + /*! + * \return シェイプ + */ + const SsShape* getShape(); + + private: + Type m_eType; //!< タイプ + bool m_bMask; //!< マスク + + bool m_bUpdate; //!< 更新が必要かどうか + + SsShape* m_pShape; //!< シェイプ + + //! マップを初期化 + static void initMap(); + + //! シェイプを切替 + /*! + * \param eType タイプ + */ + void changeShape(Type eType); + }; + +}; + +#endif // SSPARTVALUESHAPE_H diff --git a/Common/Loader/partvalues/sspartvaluetext.cpp b/Common/Loader/partvalues/sspartvaluetext.cpp new file mode 100644 index 00000000..4f06f2f6 --- /dev/null +++ b/Common/Loader/partvalues/sspartvaluetext.cpp @@ -0,0 +1,353 @@ +/*! + * \file sspartvaluetext.cpp + * \author CRI Middleware Co., Ltd. +*/ +#include "sspartvaluetext.h" + +#include "text/ssfontdesc.h" +//#include "ssfonttexturemng.h" +//#include "sscompmap.h" + +namespace SpriteStudio +{ + const SsString SsPartValueText::TAG = "text"; //!< デフォルトタグ + + //! コンストラクタ + SsPartValueText::SsPartValueText() : SsPartValue( TAG ) + { + setText( "" ); + + //m_pFontTexture = nullptr; + + setSmooth( true ); + setMask( false ); + setWidth( 0 ); + setHeight( 0 ); + #ifdef SSPARTVALUETEXT_SET_CMP + setCmp( "" ); + setCmpSize( SsVector2( 0, 0 ) ); + #endif // SSPARTVALUETEXT_SET_CMP + + m_bUpdate = true; + } + + //! デストラクタ + SsPartValueText::~SsPartValueText() + { +#if IS_EDITOR + m_Image.texture = nullptr; + + SsFontTextureMng::getInstance().release( m_pFontTexture ); + m_pFontTexture = nullptr; +#endif + } + + //! 複製 + SsPartValue* SsPartValueText::duplicate() + { + SsPartValueText* pDup = new SsPartValueText(); + + pDup->setText( m_strText ); + + pDup->m_FontDesc = m_FontDesc; + + + pDup->setSmooth( m_bSmooth ); + pDup->setMask( m_bMask ); + pDup->setWidth( m_iWidth ); + pDup->setHeight( m_iHeight ); + #ifdef SSPARTVALUETEXT_SET_CMP + pDup->setCmp( "" ); + pDup->setCmpSize( SsVector2( 0, 0 ) ); + #endif // SSPARTVALUETEXT_SET_CMP + +#if IS_EDITOR + pDup->m_pFontTexture = nullptr; + m_Image.texture = nullptr; + + SsFontTextureMng::getInstance().release( m_pFontTexture ); + m_pFontTexture = nullptr; +#endif + + return pDup; + } + + //! テキストを設定 + void SsPartValueText::setText( const SsString& strText ) + { + if ( m_strText != strText ) { + m_strText = strText; + m_bUpdate = true; + } + } + + //! ビットマップを設定 + void SsPartValueText::setBitmap( bool bBitmap ) + { + m_FontDesc.setBitmap( bBitmap ); + } + + //! ファミリを設定 + void SsPartValueText::setFamily( const SsString& strFamily ) + { + m_FontDesc.setFamily( strFamily ); + } + + //! キャラマップを設定 + void SsPartValueText::setCharMap( const SsString& strCharMap ) + { + m_FontDesc.setCharMap( strCharMap ); + } + + //! サイズを設定 + void SsPartValueText::setSize( int iSize ) + { + m_FontDesc.setSize( iSize ); + } + + //! スペースを設定 + void SsPartValueText::setSpace( float fSpace ) + { + m_FontDesc.setSpace( fSpace ); + } + + //! アンカーを設定 + void SsPartValueText::setAnchor( SsAnchorButton::Anchor eAnchor ) + { + m_FontDesc.setAnchor( eAnchor ); + } + + //! スムースを設定 + void SsPartValueText::setSmooth( bool bSmooth ) + { + if ( m_bSmooth != bSmooth ) { + m_bSmooth = bSmooth; + } + } + + //! マスクを設定 + void SsPartValueText::setMask( bool bMask ) + { + if ( m_bMask != bMask ) { + m_bMask = bMask; + } + } + + //! 幅を設定 + void SsPartValueText::setWidth( int iWidth ) + { + if ( iWidth < 0 ) iWidth = 0; + if ( iWidth > 8192 ) iWidth = 8192; + + if ( m_iWidth != iWidth ) { + m_iWidth = iWidth; + } + } + + //! 高さを設定 + void SsPartValueText::setHeight( int iHeight ) + { + if ( iHeight < 0 ) iHeight = 0; + if ( iHeight > 8192 ) iHeight = 8192; + + if ( m_iHeight != iHeight ) { + m_iHeight = iHeight; + } + } + + #ifdef SSPARTVALUETEXT_SET_CMP + //! 圧縮ビットマップ文字列を設定 + void SsPartValueText::setCmp( const SsString& strCmp ) + { + m_strCmp = strCmp; + } + + //! 圧縮ビットマップサイズを設定 + void SsPartValueText::setCmpSize( const SsVector2& cmpSize ) + { + m_CmpSize = cmpSize; + } + #endif // SSPARTVALUETEXT_SET_CMP + + //! テキストを取得 + SsString SsPartValueText::getText() const + { + return m_strText; + } + + //! ビットマップを取得 + bool SsPartValueText::isBitmap() const + { + return m_FontDesc.isBitmap(); + } + + //! ファミリを取得 + SsString SsPartValueText::getFamily() const + { + return m_FontDesc.getFamily(); + } + + //! キャラマップを取得 + SsString SsPartValueText::getCharMap() const + { + return m_FontDesc.getCharMap(); + } + + //! サイズを取得 + int SsPartValueText::getSize() const + { + return m_FontDesc.getSize(); + } + + //! スペースを取得 + float SsPartValueText::getSpace() const + { + return m_FontDesc.getSpace(); + } + + //! アンカーを取得 + SsAnchorButton::Anchor SsPartValueText::getAnchor() const + { + return m_FontDesc.getAnchor(); + } + + //! スムースを取得 + bool SsPartValueText::isSmooth() const + { + return m_bSmooth; + } + + //! マスクを取得 + bool SsPartValueText::isMask() const + { + return m_bMask; + } + + //! 幅を取得 + int SsPartValueText::getWidth() const + { + return m_iWidth; + } + + //! 高さを取得 + int SsPartValueText::getHeight() const + { + return m_iHeight; + } + + #ifdef SSPARTVALUETEXT_GET_CMP + //! 圧縮ビットマップ文字列を取得 + SsString SsPartValueText::getCmp() + { + SsCompMap cmp; + + if ( !m_pFontTexture ) { + return ""; + } + + #ifdef SSFONTTEXTURE_GET_BITMAP + cmp.fromImage( m_pFontTexture->getBitmap(), SsCompMap::FM_L4, m_pFontTexture->getImageWidth(), m_pFontTexture->getImageHeight() ); + #endif // SSFONTTEXTURE_GET_BITMAP + + return cmp.encode().toStdString(); + } + + //! 圧縮ビットマップサイズを取得 + SsVector2 SsPartValueText::getCmpSize() + { + if ( !m_pFontTexture ) { + return SsVector2( 0, 0 ); + } + + return SsVector2( m_pFontTexture->getImageWidth(), m_pFontTexture->getImageHeight() ); + } + #endif // SSPARTVALUETEXT_GET_CMP + + bool SsPartValueText::needUpdate() + { +// bool bUpdate = (m_FontDesc.takeUpdate() || m_bUpdate || !m_pFontTexture); + bool bUpdate = (m_FontDesc.takeUpdate() || m_bUpdate ); + + return bUpdate; + + } + + + bool SsPartValueText::update() + { + +#if IS_EDITOR + bool bUpdate = ( m_FontDesc.takeUpdate() || m_bUpdate || !m_pFontTexture ); + + if ( !bUpdate ) { + return false; + } + + SsFontTexture* pFontTexture = m_pFontTexture; + + m_Image.texture = nullptr; + + m_pFontTexture = SsFontTextureMng::getInstance().get( m_strText, m_FontDesc, SsSize( 0, 0 ), SsSize( getWidth(), getHeight() ) ); + SsFontTextureMng::getInstance().release( pFontTexture ); + + m_pFontTexture->setText( m_strText ); + m_pFontTexture->setFontDesc( m_FontDesc ); + m_pFontTexture->setGridSize( SsSize( 0, 0 ) ); + m_pFontTexture->setFixedSize( SsSize( getWidth(), getHeight() ) ); + + #ifdef SSPARTVALUETEXT_SET_CMP + if ( !m_strCmp.empty() ) { + if ( SsFontTextureMng::getInstance().count( m_pFontTexture ) <= 1 ) { + SsCompMap cmp; + + cmp.decode( m_strCmp.c_str(), SsCompMap::FM_L4, m_CmpSize.x, m_CmpSize.y ); + + #ifdef SSFONTTEXTURE_SET_BITMAP + m_pFontTexture->setBitmap( cmp.toImage() ); + #endif // SSFONTTEXTURE_SET_BITMAP + } + + m_strCmp.clear(); + } + #endif // SSPARTVALUETEXT_SET_CMP + + m_pFontTexture->update(); + + m_bUpdate = false; +#endif + + return true; + } + + //! セルを取得 + SsCell* SsPartValueText::getCell() + { +#if 0 + if ( !update() ) { + return &m_Cell; + } +#if IS_EDITOR + m_Image.texture = m_pFontTexture->getTexture(); +#endif + + m_CellMap.pixelSize = SsPoint2( m_pFontTexture->getTextureWidth(), m_pFontTexture->getTextureHeight() ); + //m_CellMap.parent = nullptr; + + m_CellMap.overrideTexSettings = true; + m_CellMap.filterMode = m_bSmooth ? SsTexFilterMode::linear : SsTexFilterMode::nearest; + m_CellMap.wrapMode = SsTexWrapMode::clamp; + + //m_CellMap.image = &m_Image; + + //m_Cell.map = &m_CellMap; + m_Cell.pos = SsVector2( 0, 0 ); + m_Cell.size = SsVector2( m_pFontTexture->getImageWidth(), m_pFontTexture->getImageHeight() ); + m_Cell.pivot = SsVector2( 0, 0 ); + + //m_Cell.calcUvs(); + return &m_Cell; +#endif + return 0; + } + +}; \ No newline at end of file diff --git a/Common/Loader/partvalues/sspartvaluetext.h b/Common/Loader/partvalues/sspartvaluetext.h new file mode 100644 index 00000000..5a10f122 --- /dev/null +++ b/Common/Loader/partvalues/sspartvaluetext.h @@ -0,0 +1,261 @@ +/*! + * \file sspartvaluetext.h + * \author CRI Middleware Co., Ltd. +*/ +#ifndef SSPARTVALUETEXT_H +#define SSPARTVALUETEXT_H + +//#define SSPARTVALUETEXT_SET_CMP +//#define SSPARTVALUETEXT_GET_CMP + +#include "../sstypes.h" +#include "sspartvalue.h" +#include "../ssloader_ssce.h" +#include "../text/ssfontdesc.h" + +#define IS_EDITOR (0) + +//#include "ssfonttexture.h" +//#include "SsCellMap.h" +//#include "SsImage.h" + +namespace SpriteStudio +{ + + + + /*! + * \class SsPartValueText + * \brief テキストパーツパラメータ + */ + class SsPartValueText : public SsPartValue + { + public: + static const SsString TAG; //!< デフォルトタグ + + //! コンストラクタ + SsPartValueText(); + + //! デストラクタ + ~SsPartValueText() override; + + //! 複製 + /*! + * \return パーツパラメータ + */ + SsPartValue* duplicate() override; + + //! テキストを設定 + /*! + * \param strText テキスト + */ + void setText(const SsString& strText); + + //! ビットマップを設定 + /*! + * \param bBitmap ビットマップ + */ + void setBitmap(bool bBitmap); + + //! ファミリを設定 + /*! + * \param strFamily ファミリ + */ + void setFamily(const SsString& strFamily); + + //! キャラマップを設定 + /*! + * \param strCharMap キャラマップ + */ + void setCharMap(const SsString& strCharMap); + + //! サイズを設定 + /*! + * \param iSize サイズ + */ + void setSize(int iSize); + + //! スペースを設定 + /*! + * \param fSpace スペース + */ + void setSpace(float fSpace); + + //! アンカーを設定 + /*! + * \param eAnchor アンカー + */ + void setAnchor(SsAnchorButton::Anchor eAnchor); + + //! スムースを設定 + /*! + * \param bSmooth スムース + */ + void setSmooth(bool bSmooth); + + //! マスクを設定 + /*! + * \param bMask マスク + */ + void setMask(bool bMask); + + //! 幅を設定 + /*! + * \param iWidth 幅 + */ + void setWidth(int iWidth); + + //! 高さを設定 + /*! + * \param iHeight 高さ + */ + void setHeight(int iHeight); + +#ifdef SSPARTVALUETEXT_SET_CMP + //! 圧縮ビットマップ文字列を設定 + /*! + * \param strCmp 圧縮ビットマップ文字列 + */ + void setCmp(const SsString& strCmp); + + //! 圧縮ビットマップサイズを設定 + /*! + * \param cmpSize 圧縮ビットマップサイズ + */ + void setCmpSize(const SsVector2& cmpSize); +#endif // SSPARTVALUETEXT_SET_CMP + + //! テキストを取得 + /*! + * \return テキスト + */ + SsString getText() const; + + //! ビットマップを取得 + /*! + * \return ビットマップ + */ + bool isBitmap() const; + + //! ファミリを取得 + /*! + * \return ファミリ + */ + SsString getFamily() const; + + //! キャラマップを取得 + /*! + * \return キャラマップ + */ + SsString getCharMap() const; + + //! サイズを取得 + /*! + * \return サイズ + */ + int getSize() const; + + //! スペースを取得 + /*! + * \return スペース + */ + float getSpace() const; + + //! アンカーを取得 + /*! + * \return アンカー + */ + SsAnchorButton::Anchor getAnchor() const; + + //! スムースを取得 + /*! + * \return スムース + */ + bool isSmooth() const; + + //! マスクを取得 + /*! + * \return マスク + */ + bool isMask() const; + + //! 幅を取得 + /*! + * \return 幅 + */ + int getWidth() const; + + //! 高さを取得 + /*! + * \return 高さ + */ + int getHeight() const; + +#ifdef SSPARTVALUETEXT_GET_CMP + //! 圧縮ビットマップ文字列を取得 + /*! + * \return 圧縮ビットマップ文字列 + */ + SsString getCmp(); + + //! 圧縮ビットマップサイズを取得 + /*! + * \return 圧縮ビットマップサイズ + */ + SsVector2 getCmpSize(); +#endif // SSPARTVALUETEXT_GET_CMP + + + virtual bool needUpdate(); + + virtual bool update(); + + //! セルを取得 + /*! + * \return セル + */ + virtual SsCell* getCell(); + + + const SsFontDesc& getFontDesc() { + return m_FontDesc + ; + } + + + protected: + SsString m_strText; //!< テキスト + SsFontDesc m_FontDesc; //!< フォント設定 + bool m_bSmooth; //!< スムース + bool m_bMask; //!< マスク + int m_iWidth; //!< 幅 + int m_iHeight; //!< 高さ +#ifdef SSPARTVALUETEXT_SET_CMP + SsString m_strCmp; //!< 圧縮ビットマップ文字列 + SsVector2 m_CmpSize; //!< 圧縮ビットマップサイズ +#endif // SSPARTVALUETEXT_SET_CMP + + bool m_bUpdate; //!< 更新が必要かどうか + +#if IS_EDITOR + SsFontTexture* m_pFontTexture; //!< フォントテクスチャ + SsImage m_Image; //!< イメージ +#else + //ISSTexture* m_pFontTexture; + +#endif + +#if 0 + public: + + SsCellMap m_CellMap; //!< セルマップ + SsCell m_Cell; //!< セル +#endif + }; + + +}; + + + +#endif // SSPARTVALUETEXT_H diff --git a/Common/Loader/shape/sspolygon.cpp b/Common/Loader/shape/sspolygon.cpp new file mode 100644 index 00000000..96b0620f --- /dev/null +++ b/Common/Loader/shape/sspolygon.cpp @@ -0,0 +1,95 @@ +#include "sspolygon.h" + +namespace SpriteStudio +{ + + + //! コンストラクタ + SsPolygon::SsPolygon() + { + clear(); + } + + //! デストラクタ + SsPolygon::~SsPolygon() + { + clear(); + } + + //! クリア + void SsPolygon::clear() + { + m_eVertexOrder = VO_Unknown; + m_listVertex.clear(); + m_listVertexIndex.clear(); + m_listStride.clear(); + } + + //! 頂点順を設定 + void SsPolygon::setVertexOrder(VertexOrder eVertexOrder) + { + m_eVertexOrder = eVertexOrder; + } + + //! 頂点順を取得 + SsPolygon::VertexOrder SsPolygon::getVertexOrder() const + { + return m_eVertexOrder; + } + + //! 頂点を追加 + void SsPolygon::addVertex(const SsVertex& vertex) + { +// m_listVertex.append(vertex); + m_listVertex.push_back(vertex); + } + + //! 頂点インデックスを追加 + void SsPolygon::addVertexIndex(uint32_t vertexIndex) + { + m_listVertexIndex.push_back(vertexIndex); + } + + //! 区切りを追加 + void SsPolygon::addStride(uint32_t stride) + { + m_listStride.push_back(stride); + } + + //! 頂点数を取得 + int SsPolygon::getVertexCount() const + { + return m_listVertex.size(); + } + + //! 頂点インデックス数を取得 + int SsPolygon::getVertexIndexCount() const + { + return m_listVertexIndex.size(); + } + + //! 区切り数を取得 + int SsPolygon::getStrideCount() const + { + return m_listStride.size(); + } + + //! 頂点リストを取得 + const std::list& SsPolygon::getVertices() const + { + return m_listVertex; + } + + //! 頂点インデックスリストを取得 + const std::list& SsPolygon::getVertexIndices() const + { + return m_listVertexIndex; + } + + //! 区切りリストを取得 + const std::list& SsPolygon::getStrides() const + { + return m_listStride; + } + +}; \ No newline at end of file diff --git a/Common/Loader/shape/sspolygon.h b/Common/Loader/shape/sspolygon.h new file mode 100644 index 00000000..1b78f91c --- /dev/null +++ b/Common/Loader/shape/sspolygon.h @@ -0,0 +1,115 @@ +#ifndef SSPOLYGON_H +#define SSPOLYGON_H + +#include "../sstypes.h" +#include "ssvertex.h" +#include + + +namespace SpriteStudio +{ + + /*! + * \class SsPolygon + * \brief ポリゴン + */ + class SsPolygon + { + public: + /*! + * \enum Polygon::VertexOrder + * \brief 頂点順 + */ + enum VertexOrder + { + VO_Unknown = 0, //!< 不明 + VO_TriangleList, //!< 三角リスト + VO_TriangleFan, //!< 三角ファン + VO_TriangleStrip, //!< 三角ストリップ + }; + + //! コンストラクタ + SsPolygon(); + + //! デストラクタ + ~SsPolygon(); + + //! クリア + void clear(); + + //! 頂点順を設定 + /*! + * \param eVertexOrder 頂点順 + */ + void setVertexOrder(VertexOrder eVertexOrder); + + //! 頂点順を取得 + /*! + * \return 頂点順 + */ + VertexOrder getVertexOrder() const; + + //! 頂点を追加 + /*! + * \param vertex 頂点 + */ + void addVertex(const SsVertex& vertex); + + //! 頂点インデックスを追加 + /*! + * \param vertexIndex 頂点インデックス + */ + void addVertexIndex(uint32_t vertexIndex); + + //! 区切りを追加 + /*! + * \param stride 区切り + */ + void addStride(uint32_t stride); + + //! 頂点数を取得 + /*! + * \return 頂点数 + */ + int getVertexCount() const; + + //! 頂点インデックス数を取得 + /*! + * \return 頂点インデックス数 + */ + int getVertexIndexCount() const; + + //! 区切り数を取得 + /*! + * \return 区切り数 + */ + int getStrideCount() const; + + //! 頂点リストを取得 + /*! + * \return 頂点リスト + */ + const std::list& getVertices() const; + + //! 頂点インデックスリストを取得 + /*! + * \return 頂点インデックスリスト + */ + const std::list& getVertexIndices() const; + + //! 区切りリストを取得 + /*! + * \return 区切りリスト + */ + const std::list& getStrides() const; + + private: + VertexOrder m_eVertexOrder; //!< 頂点順 + std::list m_listVertex; //!< 頂点リスト + std::list m_listVertexIndex; //!< 頂点インデックスリスト + std::list m_listStride; //!< 区切りリスト + }; + +}; + +#endif // SSPOLYGON_H diff --git a/Common/Loader/shape/ssshape.cpp b/Common/Loader/shape/ssshape.cpp new file mode 100644 index 00000000..9371610d --- /dev/null +++ b/Common/Loader/shape/ssshape.cpp @@ -0,0 +1,72 @@ +#include "ssshape.h" + + +namespace SpriteStudio +{ + + //! コンストラクタ + SsShape::SsShape() + { + setSize( SsSizeF( 1, 1 ) ); + + m_bUpdate = true; + + m_Polygon.clear(); + } + + //! デストラクタ + SsShape::~SsShape() + { + } + + //! サイズを設定 + void SsShape::setSize( const SsSizeF& size ) + { + if ( m_Size != size ) { + m_Size = size; + m_bUpdate = true; + } + } + + //! サイズを取得 + /*! + * \return サイズ + */ + SsSizeF SsShape::getSize() const + { + return m_Size; + } + + bool SsShape::update() + { + bool bUpdate = ( m_bUpdate ); + + if ( !bUpdate ) { + return false; + } + + createPolygon(); + + m_bUpdate = false; + + return true; + } + + //! ポリゴンを取得 + /*! + * \return ポリゴン + */ + const SsPolygon& SsShape::getPolygon() const + { + return m_Polygon; + } + + //! ポリゴンを生成 + bool SsShape::createPolygon() + { + m_Polygon.clear(); + + return true; + } + +}; \ No newline at end of file diff --git a/Common/Loader/shape/ssshape.h b/Common/Loader/shape/ssshape.h new file mode 100644 index 00000000..89430319 --- /dev/null +++ b/Common/Loader/shape/ssshape.h @@ -0,0 +1,57 @@ +#ifndef SSSHAPE_H +#define SSSHAPE_H + +#include "../sstypes.h" +//#include "../partvalues/ssplayer_partValue.h" +#include "sspolygon.h" +namespace SpriteStudio +{ + + /*! + * \class SsShape + * \brief シェイプ + */ + class SsShape + { + public : + //! コンストラクタ + SsShape(); + + //! デストラクタ + virtual ~SsShape(); + + //! サイズを設定 + /*! + * \param サイズ + */ + void setSize( const SsSizeF& size ); + + //! サイズを取得 + /*! + * \return サイズ + */ + SsSizeF getSize() const; + + bool update(); + + //! ポリゴンを取得 + /*! + * \return ポリゴン + */ + const SsPolygon& getPolygon() const; + + protected : + SsSizeF m_Size; //!< サイズ + bool m_bUpdate; //!< 更新が必要かどうか + + SsPolygon m_Polygon; //!< ポリゴン + + //! ポリゴンを生成 + /*! + * \return 成功したかどうか + */ + virtual bool createPolygon(); + }; +}; + +#endif // SSSHAPE_H diff --git a/Common/Loader/shape/ssshapearrow.cpp b/Common/Loader/shape/ssshapearrow.cpp new file mode 100644 index 00000000..fbb02ddb --- /dev/null +++ b/Common/Loader/shape/ssshapearrow.cpp @@ -0,0 +1,41 @@ +#include "ssshapearrow.h" + +namespace SpriteStudio +{ + + //! コンストラクタ + SsShapeArrow::SsShapeArrow() : SsShape() + { + } + + //! デストラクタ + SsShapeArrow::~SsShapeArrow() + { + } + + //! ポリゴンを生成 + bool SsShapeArrow::createPolygon() + { + float fX2 = m_Size.width() * 0.5f; + float fY2 = m_Size.height() * 0.5f; + float fX4 = m_Size.width() * 0.25f; + float fY4 = m_Size.height() * 0.25f; + + m_Polygon.clear(); + + m_Polygon.setVertexOrder( SsPolygon::VO_TriangleFan ); + + m_Polygon.addVertex( SsVertex( SsPoint2( 0.0f, 0.0f ) ) ); + m_Polygon.addVertex( SsVertex( SsPoint2( 0.0f, fY2 ) ) ); + m_Polygon.addVertex( SsVertex( SsPoint2( fX2, 0.0f ) ) ); + m_Polygon.addVertex( SsVertex( SsPoint2( fX4, 0.0f ) ) ); + m_Polygon.addVertex( SsVertex( SsPoint2( fX4, -fY2 ) ) ); + m_Polygon.addVertex( SsVertex( SsPoint2( -fX4, -fY2 ) ) ); + m_Polygon.addVertex( SsVertex( SsPoint2( -fX4, 0.0f ) ) ); + m_Polygon.addVertex( SsVertex( SsPoint2( -fX2, 0.0f ) ) ); + m_Polygon.addVertex( SsVertex( SsPoint2( 0.0f, fY2 ) ) ); + + return true; + } + +}; diff --git a/Common/Loader/shape/ssshapearrow.h b/Common/Loader/shape/ssshapearrow.h new file mode 100644 index 00000000..f2b8d772 --- /dev/null +++ b/Common/Loader/shape/ssshapearrow.h @@ -0,0 +1,30 @@ +#ifndef SSSHAPEARROW_H +#define SSSHAPEARROW_H + +#include "ssshape.h" + +namespace SpriteStudio +{ + /*! + * \class SsShapeArrow + * \brief 矢印形シェイプ + */ + class SsShapeArrow : public SsShape + { + public : + //! コンストラクタ + SsShapeArrow(); + + //! デストラクタ + ~SsShapeArrow() override; + + protected : + //! ポリゴンを生成 + /*! + * \return 成功したかどうか + */ + bool createPolygon() override; + }; +}; + +#endif // SSSHAPEARROW_H diff --git a/Common/Loader/shape/ssshaperectangle.cpp b/Common/Loader/shape/ssshaperectangle.cpp new file mode 100644 index 00000000..6ed1f21c --- /dev/null +++ b/Common/Loader/shape/ssshaperectangle.cpp @@ -0,0 +1,37 @@ +#include "ssshaperectangle.h" + + +namespace SpriteStudio +{ + + //! コンストラクタ + SsShapeRectangle::SsShapeRectangle() : SsShape() + { + } + + //! デストラクタ + SsShapeRectangle::~SsShapeRectangle() + { + } + + //! ポリゴンを生成 + bool SsShapeRectangle::createPolygon() + { + float fX2 = m_Size.width() * 0.5f; + float fY2 = m_Size.height() * 0.5f; + + m_Polygon.clear(); + + m_Polygon.setVertexOrder( SsPolygon::VO_TriangleFan ); + + m_Polygon.addVertex( SsVertex( SsPoint2( 0.0f, 0.0f ) ) ); + m_Polygon.addVertex( SsVertex( SsPoint2( -fX2, fY2 ) ) ); + m_Polygon.addVertex( SsVertex( SsPoint2( fX2, fY2 ) ) ); + m_Polygon.addVertex( SsVertex( SsPoint2( fX2, -fY2 ) ) ); + m_Polygon.addVertex( SsVertex( SsPoint2( -fX2, -fY2 ) ) ); + m_Polygon.addVertex( SsVertex( SsPoint2( -fX2, fY2 ) ) ); + + return true; + } + +}; \ No newline at end of file diff --git a/Common/Loader/shape/ssshaperectangle.h b/Common/Loader/shape/ssshaperectangle.h new file mode 100644 index 00000000..72345e57 --- /dev/null +++ b/Common/Loader/shape/ssshaperectangle.h @@ -0,0 +1,32 @@ +#ifndef SSSHAPERECTANGLE_H +#define SSSHAPERECTANGLE_H + +#include "ssshape.h" + +namespace SpriteStudio +{ + + /*! + * \class SsShapeRectangle + * \brief 矩形シェイプ + */ + class SsShapeRectangle : public SsShape + { + public : + //! コンストラクタ + SsShapeRectangle(); + + //! デストラクタ + ~SsShapeRectangle() override; + + protected : + //! ポリゴンを生成 + /*! + * \return 成功したかどうか + */ + bool createPolygon() override; + }; + +}; + +#endif // SSSHAPERECTANGLE_H diff --git a/Common/Loader/shape/ssshapestar.cpp b/Common/Loader/shape/ssshapestar.cpp new file mode 100644 index 00000000..64485d8f --- /dev/null +++ b/Common/Loader/shape/ssshapestar.cpp @@ -0,0 +1,65 @@ +#include "ssshapestar.h" + +//#include "ssmath.h" +#include "ssplayer_math.h" + +namespace SpriteStudio +{ + + //! 水平位置に変換 + /*! + * \param fRad ラジアン角 + * \return 水平位置 + */ + static inline float toH( float fRad ) + { + return sinf( DegreeToRadian( fRad ) ); + } + + //! 垂直位置に変換 + /*! + * \param fRad ラジアン角 + * \return 垂直位置 + */ + static inline float toV( float fRad ) + { + return cosf( DegreeToRadian( fRad ) ); + } + + //! コンストラクタ + SsShapeStar::SsShapeStar() : SsShape() + { + } + + //! デストラクタ + SsShapeStar::~SsShapeStar() + { + } + + //! ポリゴンを生成 + bool SsShapeStar::createPolygon() + { + float fX2 = m_Size.width() * 0.5f; + float fY2 = m_Size.height() * 0.5f; + float fX4 = m_Size.width() * 0.25f; + float fY4 = m_Size.height() * 0.25f; + + m_Polygon.clear(); + + m_Polygon.setVertexOrder( SsPolygon::VO_TriangleFan ); + + m_Polygon.addVertex( SsVertex( SsPoint2( 0.0f, 0.0f ) ) ); + + m_Polygon.addVertex( SsVertex( SsPoint2( toH( 0.0f ) * fX2, toV( 0.0f ) * fY2 ) ) ); + + for ( int i = 1; i < 10; i++ ) { + m_Polygon.addVertex( SsVertex( SsPoint2( toH( 36 * i ) * ( ( i % 2 ) ? ( fX4 ) : ( fX2 ) ), toV( 36 * i ) * ( ( i % 2 ) ? ( fY4 ) : ( fY2 ) ) ) ) ); + } + + m_Polygon.addVertex( SsVertex( SsPoint2( toH( 0.0f ) * fX2, toV( 0.0f ) * fY2 ) ) ); + + return true; + } + + +}; \ No newline at end of file diff --git a/Common/Loader/shape/ssshapestar.h b/Common/Loader/shape/ssshapestar.h new file mode 100644 index 00000000..3fecc29d --- /dev/null +++ b/Common/Loader/shape/ssshapestar.h @@ -0,0 +1,31 @@ +#ifndef SSSHAPESTAR_H +#define SSSHAPESTAR_H + +#include "ssshape.h" + +namespace SpriteStudio +{ + + /*! + * \class SsShapeStar + * \brief 星形シェイプ + */ + class SsShapeStar : public SsShape + { + public : + //! コンストラクタ + SsShapeStar(); + + //! デストラクタ + ~SsShapeStar() override; + + protected : + //! ポリゴンを生成 + /*! + * \return 成功したかどうか + */ + bool createPolygon() override; + }; + +}; +#endif // SSSHAPESTAR_H diff --git a/Common/Loader/shape/ssshapetriangle.cpp b/Common/Loader/shape/ssshapetriangle.cpp new file mode 100644 index 00000000..5b9ef3d0 --- /dev/null +++ b/Common/Loader/shape/ssshapetriangle.cpp @@ -0,0 +1,62 @@ +#include "ssshapetriangle.h" + +//#include "ssmath.h" +#include "ssplayer_math.h" + +namespace SpriteStudio +{ + + //! 水平位置に変換 + /*! + * \param fRad ラジアン角 + * \return 水平位置 + */ + static inline float toH( float fRad ) + { + return sinf( DegreeToRadian( fRad ) ); + } + + //! 垂直位置に変換 + /*! + * \param fRad ラジアン角 + * \return 垂直位置 + */ + static inline float toV( float fRad ) + { + return cosf( DegreeToRadian( fRad ) ); + } + + //! コンストラクタ + SsShapeTriangle::SsShapeTriangle() : SsShape() + { + } + + //! デストラクタ + SsShapeTriangle::~SsShapeTriangle() + { + } + + //! ポリゴンを生成 + bool SsShapeTriangle::createPolygon() + { + float fX2 = m_Size.width() * 0.5f; + float fY2 = m_Size.height() * 0.5f; + + m_Polygon.clear(); + + m_Polygon.setVertexOrder( SsPolygon::VO_TriangleFan ); + + m_Polygon.addVertex( SsVertex( SsPoint2( 0.0f, 0.0f ) ) ); + + m_Polygon.addVertex( SsVertex( SsPoint2( toH( 0.0f ) * fX2, toV( 0.0f ) * fY2 ) ) ); + + for ( int i = 1; i < 3; i++ ) { + m_Polygon.addVertex( SsVertex( SsPoint2( toH( 120 * i ) * fX2, toV( 120 * i ) * fY2 ) ) ); + } + + m_Polygon.addVertex( SsVertex( SsPoint2( toH( 0.0f ) * fX2, toV( 0.0f ) * fY2 ) ) ); + + return true; + } + +}; \ No newline at end of file diff --git a/Common/Loader/shape/ssshapetriangle.h b/Common/Loader/shape/ssshapetriangle.h new file mode 100644 index 00000000..c353275c --- /dev/null +++ b/Common/Loader/shape/ssshapetriangle.h @@ -0,0 +1,30 @@ +#ifndef SSSHAPETRIANGLE_H +#define SSSHAPETRIANGLE_H + +#include "ssshape.h" + +namespace SpriteStudio +{ + /*! + * \class SsShapeTriangle + * \brief 三角形シェイプ + */ + class SsShapeTriangle : public SsShape + { + public : + //! コンストラクタ + SsShapeTriangle(); + + //! デストラクタ + ~SsShapeTriangle() override; + + protected : + //! ポリゴンを生成 + /*! + * \return 成功したかどうか + */ + bool createPolygon() override; + }; +}; + +#endif // SSSHAPETRIANGLE_H diff --git a/Common/Loader/shape/ssvertex.cpp b/Common/Loader/shape/ssvertex.cpp new file mode 100644 index 00000000..cec35dc4 --- /dev/null +++ b/Common/Loader/shape/ssvertex.cpp @@ -0,0 +1,44 @@ +#include "ssvertex.h" + +namespace SpriteStudio +{ + //! コンストラクタ + SsVertex::SsVertex() + { + m_Position = SsPoint2(); + m_Coord = SsPoint2(); + } + + //! コンストラクタ + SsVertex::SsVertex(const SsPoint2& position) + { + m_Position = position; + m_Coord = SsPoint2(); + } + + //! コンストラクタ + SsVertex::SsVertex(const SsPoint2& position, const SsPoint2& coord) + { + m_Position = position; + m_Coord = coord; + } + + //! デストラクタ + SsVertex::~SsVertex() + { + } + + //! 位置を取得 + const SsPoint2& SsVertex::getPosition() const + { + return m_Position; + } + + //! 座標を取得 + const SsPoint2& SsVertex::getCoord() const + { + return m_Coord; + } + + +}; \ No newline at end of file diff --git a/Common/Loader/shape/ssvertex.h b/Common/Loader/shape/ssvertex.h new file mode 100644 index 00000000..77a2d70a --- /dev/null +++ b/Common/Loader/shape/ssvertex.h @@ -0,0 +1,53 @@ +#ifndef SSVERTEX_H +#define SSVERTEX_H + +#include "../sstypes.h" + +namespace SpriteStudio +{ + /*! + * \class SsVertex + * \brief 頂点 + */ + class SsVertex + { + public: + //! コンストラクタ + SsVertex(); + + //! コンストラクタ + /*! + * \param position 位置 + */ + SsVertex(const SsPoint2& position); + + //! コンストラクタ + /*! + * \param position 位置 + * \param coord 座標 + */ + SsVertex(const SsPoint2& position, const SsPoint2& coord); + + //! デストラクタ + ~SsVertex(); + + //! 位置を取得 + /*! + * \return 位置 + */ + const SsPoint2& getPosition() const; + + //! 座標を取得 + /*! + * \return 座標 + */ + const SsPoint2& getCoord() const; + + private: + SsPoint2 m_Position; //!< 位置 + SsPoint2 m_Coord; //!< 座標 + }; + +}; + +#endif // SSVERTEX_H diff --git a/Common/Loader/ssInterpolation.cpp b/Common/Loader/ssInterpolation.cpp index 02b9473a..41ed8e2b 100644 --- a/Common/Loader/ssInterpolation.cpp +++ b/Common/Loader/ssInterpolation.cpp @@ -1,7 +1,7 @@ #include "ssloader.h" #include "ssInterpolation.h" -namespace spritestudio6 +namespace SpriteStudio { //--------------------------------------------------------------------------- @@ -122,13 +122,249 @@ static float hermite_(float start, float end, float time, const SsCurve * c) return result; } +#if 1 +//add SS 7.1 + +static float easeIn(float start, float end, float time, float easeingRate) +{ + float t = powf(time, easeingRate); + return linear_(start, end, t); +} +static float easeOut(float start, float end, float time, float easeingRate) +{ + float t = powf(time, 1 / easeingRate); + return linear_(start, end, t); +} +static float easeInOut(float start, float end, float time, float easeingRate) +{ + time *= 2; + float t = 0; + if (time < 1) + { + t = 0.5f * powf(time, easeingRate); + } + else + { + t = 1.0f - 0.5f * powf(2 - time, easeingRate); + } + + return linear_(start, end, t); +} + +static float easeExponentialIn(float start, float end, float time, float easeingRate) +{ + float t = (time == 0 ? 0 : powf(2, 10 * (time / 1 - 1)) - 1 * 0.001f); + return linear_(start, end, t); +} + +static float easeExponentialOut(float start, float end, float time, float easeingRate) +{ + float t = (time == 1 ? 1 : (-powf(2, -10 * time / 1) + 1)); + return linear_(start, end, t); +} + +static float easeExponentialInOut(float start, float end, float time, float easeingRate) +{ + time /= 0.5f; + float t = 0; + if (time < 1) + { + t = 0.5f * powf(2, 10 * (time - 1)); + } + else + { + t = 0.5f * (-powf(2, -10 * (time - 1)) + 2); + } + + return linear_(start, end, t); +} + +#define M_PI_2 1.57079632679489661923 // pi/2 +#define M_PI 3.14159265358979323846 // pi +#define M_PI_X_2 (float)M_PI * 2.0f + + + +static float easeSineIn(float start, float end, float time, float easeingRate) +{ + float t = (-1 * cosf(time * (float)M_PI_2) + 1); + return linear_(start, end, t); +} + +static float easeSineOut(float start, float end, float time, float easeingRate) +{ + float t = (sinf(time * (float)M_PI_2)); + return linear_(start, end, t); +} + +static float easeSineInOut(float start, float end, float time, float easeingRate) +{ + float t = (-0.5f * (cosf((float)M_PI * time) - 1)); + return linear_(start, end, t); +} + +//set period of the wave in radians. +static float easeElasticIn(float start, float end, float time, float fPeriod) +{ + float newT = 0; + if (time == 0 || time == 1) + { + newT = time; + } + else + { + float s = fPeriod / 4; + time = time - 1; + newT = -powf(2, 10 * time) * sinf((time - s) * M_PI_X_2 / fPeriod); + } + + return linear_(start, end, newT); +} + +static float easeElasticOut(float start, float end, float time, float fPeriod) +{ + float newT = 0; + if (time == 0 || time == 1) + { + newT = time; + } + else + { + float s = fPeriod / 4; + newT = powf(2, -10 * time) * sinf((time - s) * M_PI_X_2 / fPeriod) + 1; + } + + return linear_(start, end, newT); +} + +static float easeElasticInOut(float start, float end, float time, float fPeriod) +{ + float newT = 0; + if (time == 0 || time == 1) + { + newT = time; + } + else + { + time = time * 2; + if (!fPeriod) + { + fPeriod = 0.3f * 1.5f; + } + + float s = fPeriod / 4; + + time = time - 1; + if (time < 0) + { + newT = -0.5f * powf(2, 10 * time) * sinf((time - s) * M_PI_X_2 / fPeriod); + } + else + { + newT = powf(2, -10 * time) * sinf((time - s) * M_PI_X_2 / fPeriod) * 0.5f + 1; + } + } + + return linear_(start, end, newT); + +} + +static float bounceTime(float time) +{ + if (time < 1 / 2.75) + { + return 7.5625f * time * time; + } + else + if (time < 2 / 2.75) + { + time -= 1.5f / 2.75f; + return 7.5625f * time * time + 0.75f; + } + else + if (time < 2.5 / 2.75) + { + time -= 2.25f / 2.75f; + return 7.5625f * time * time + 0.9375f; + } + + time -= 2.625f / 2.75f; + return 7.5625f * time * time + 0.984375f; +} + +static float easeBounceIn(float start, float end, float time, float easeingRate) +{ + float newT = 1 - bounceTime(1 - time); + return linear_(start, end, newT); +} + +static float easeBounceOut(float start, float end, float time, float easeingRate) +{ + float newT = bounceTime(time); + return linear_(start, end, newT); +} + +static float easeBounceInOut(float start, float end, float time, float easeingRate) +{ + float newT = 0; + if (time < 0.5f) + { + time = time * 2; + newT = (1 - bounceTime(1 - time)) * 0.5f; + } + else + { + newT = bounceTime(time * 2 - 1) * 0.5f + 0.5f; + } + + return linear_(start, end, newT); +} + +static float easeBackIn(float start, float end, float time, float easeingRate) +{ + float overshoot = 1.70158f; + float newT = (time * time * ((overshoot + 1) * time - overshoot)); + return linear_(start, end, newT); + +} + +static float easeBackOut(float start, float end, float time, float easeingRate) +{ + float overshoot = 1.70158f; + + time = time - 1; + float newT = (time * time * ((overshoot + 1) * time + overshoot) + 1); + return linear_(start, end, newT); + +} + +static float easeBackInOut(float start, float end, float time, float easeingRate) +{ + float overshoot = 1.70158f * 1.525f; + + time = time * 2; + float newT = 0; + if (time < 1) + { + newT = ((time * time * ((overshoot + 1) * time - overshoot)) / 2); + } + else + { + time = time - 2; + newT = ((time * time * ((overshoot + 1) * time + overshoot)) / 2 + 1); + } + return linear_(start, end, newT); +} + +#endif /// SsVector2 のメンバ全体の補間 -SsVector2 SsInterpolate(SsInterpolationType::_enum ipType, float time, SsVector2 start, SsVector2 end, const SsCurve * curve) +//SsVector2 SsInterpolate(SsInterpolationType::_enum ipType, float time, SsVector2 start, SsVector2 end, const SsCurve * curve) +SsVector2 SsInterpolate(SsInterpolationType::_enum ipType, float easingRate, float time, SsVector2 start, SsVector2 end, const SsCurve* curve) { SsVector2 out; - out.x = SsInterpolate(ipType, time, start.x, end.x, curve); - out.y = SsInterpolate(ipType, time, start.y, end.y, curve); + out.x = SsInterpolate(ipType, easingRate , time, start.x, end.x, curve); + out.y = SsInterpolate(ipType, easingRate , time, start.y, end.y, curve); return(out); } @@ -138,8 +374,10 @@ SsVector2 SsInterpolate(SsInterpolationType::_enum ipType, float time, SsVector2 タイプを指定して補間する */ //---------------------------------------------------------------------------- -float SsInterpolate(SsInterpolationType::_enum type, float time, float start, float end, const SsCurve * curve) +//float SsInterpolate(SsInterpolationType::_enum type, float time, float start, float end, const SsCurve * curve) +float SsInterpolate(SsInterpolationType::_enum type, float easingRate, float time, float start, float end, const SsCurve* curve) { + //float easingRate = 1.0f; float r = start; switch (type) { @@ -161,6 +399,62 @@ float SsInterpolate(SsInterpolationType::_enum type, float time, float start, fl case SsInterpolationType::hermite: r = hermite_(start, end, time, curve); break; + //add SS7.1 + case SsInterpolationType::easeIn: + //qDebug() << "easingRate" << easingRate; + r = easeIn(start, end, time, easingRate); + break; + case SsInterpolationType::easeOut: + r = easeOut(start, end, time, easingRate); + break; + case SsInterpolationType::easeInOut: + r = easeInOut(start, end, time, easingRate); + break; + case SsInterpolationType::easeExponentialIn: + r = easeExponentialIn(start, end, time, easingRate); + break; + case SsInterpolationType::easeExponentialOut: + r = easeExponentialOut(start, end, time, easingRate); + break; + case SsInterpolationType::easeExponentialInOut: + r = easeExponentialInOut(start, end, time, easingRate); + break; + case SsInterpolationType::easeSineIn: + r = easeSineIn(start, end, time, easingRate); + break; + case SsInterpolationType::easeSineOut: + r = easeSineOut(start, end, time, easingRate); + break; + case SsInterpolationType::easeSineInOut: + r = easeSineInOut(start, end, time, easingRate); + break; + case SsInterpolationType::easeElasticIn: + r = easeElasticIn(start, end, time, easingRate); + break; + case SsInterpolationType::easeElasticOut: + r = easeElasticOut(start, end, time, easingRate); + break; + case SsInterpolationType::easeElasticInOut: + r = easeElasticInOut(start, end, time, easingRate); + break; + case SsInterpolationType::easeBounceIn: + r = easeBounceIn(start, end, time, easingRate); + break; + case SsInterpolationType::easeBounceOut: + r = easeBounceOut(start, end, time, easingRate); + break; + case SsInterpolationType::easeBounceInOut: + r = easeBounceInOut(start, end, time, easingRate); + break; + case SsInterpolationType::easeBackIn: + r = easeBackIn(start, end, time, easingRate); + break; + case SsInterpolationType::easeBackOut: + r = easeBackOut(start, end, time, easingRate); + break; + case SsInterpolationType::easeBackInOut: + r = easeBackInOut(start, end, time, easingRate); + break; default: //SS_ASSERT_ID(type); break; @@ -168,4 +462,4 @@ float SsInterpolate(SsInterpolationType::_enum type, float time, float start, fl return r; } -} // namespace spritestudio6 +} // namespace SpriteStudio diff --git a/Common/Loader/ssInterpolation.h b/Common/Loader/ssInterpolation.h index 52448833..77736bf2 100644 --- a/Common/Loader/ssInterpolation.h +++ b/Common/Loader/ssInterpolation.h @@ -1,7 +1,7 @@ #ifndef __SSINTERPOLATION__ #define __SSINTERPOLATION__ -namespace spritestudio6 +namespace SpriteStudio { class SsCurve; @@ -18,11 +18,22 @@ inline bool SsNeedsCurveParams(SsInterpolationType::_enum type) return false; } +inline bool SsNeedsEasingParams(SsInterpolationType::_enum type) +{ + if (type >= SsInterpolationType::easeIn && + type <= SsInterpolationType::easeBackInOut) + return true; + return false; +} + ///カーブパラメータ、補完方法により保管された値を生成する -SsVector2 SsInterpolate(SsInterpolationType::_enum ipType, float time, SsVector2 start, SsVector2 end, const SsCurve * curve); -float SsInterpolate(SsInterpolationType::_enum type, float time, float start, float end, const SsCurve * curve); +//SsVector2 SsInterpolate(SsInterpolationType::_enum ipType, float time, SsVector2 start, SsVector2 end, const SsCurve * curve); +SsVector2 SsInterpolate(SsInterpolationType::_enum ipType, float easingRate , float time, SsVector2 start, SsVector2 end, const SsCurve* curve); + +//float SsInterpolate(SsInterpolationType::_enum type, float time, float start, float end, const SsCurve * curve); +float SsInterpolate(SsInterpolationType::_enum type, float easingRate, float time, float start, float end, const SsCurve* curve); -} // namespace spritestudio6 +} // namespace SpriteStudio #endif diff --git a/Common/Loader/ssarchiver.cpp b/Common/Loader/ssarchiver.cpp index 11d974ab..94c699e9 100644 --- a/Common/Loader/ssarchiver.cpp +++ b/Common/Loader/ssarchiver.cpp @@ -2,7 +2,7 @@ #include "ssstring_uty.h" #include "sscharconverter.h" -namespace spritestudio6 +namespace SpriteStudio { bool SsXmlIArchiver::dc_attr( const char* name , SsString& member ) @@ -27,6 +27,17 @@ bool SsXmlIArchiver::dc_attr( const char* name , int& member ) return true; } +bool SsXmlIArchiver::dc_attr(const char* name, float& member) +{ + SPRITESTUDIO6SDK_AR_SELF_CHECK(); + + const char* v = getxml()->Attribute(name); + + member = atof(v); + + return true; +} + bool SsXmlIArchiver::dc( const char* name , int& member ) { @@ -310,16 +321,13 @@ bool StringToIRect( const std::string& str , SsIRect& rect ) split_string( str , ' ' , str_list ); if ( str_list.size() < 4 ) { - rect.x = 0; - rect.y = 0; - rect.w = 0; - rect.h = 0; + rect = SsIRect(); return false; }else{ - rect.x = (int)atof( str_list[0].c_str() ); - rect.y = (int)atof( str_list[1].c_str() ); - rect.w = (int)atof( str_list[2].c_str() ); - rect.h = (int)atof( str_list[3].c_str() ); + rect.setX( (int)atof(str_list[0].c_str()) ); + rect.setY( (int)atof(str_list[1].c_str()) ); + rect.setWidth( (int)atof( str_list[2].c_str() ) ); + rect.setHeight( (int)atof( str_list[3].c_str() ) ); } return true; @@ -329,4 +337,4 @@ void SsArchiverInit() { } -} // namespace spritestudio6 +} // namespace SpriteStudio diff --git a/Common/Loader/ssarchiver.h b/Common/Loader/ssarchiver.h index 1bbffc7f..1d81b1ba 100644 --- a/Common/Loader/ssarchiver.h +++ b/Common/Loader/ssarchiver.h @@ -10,7 +10,7 @@ // MEMO: 定義順の関係でここでusingしてしまうと問題が発生する // using namespace tinyxml2; -namespace spritestudio6 +namespace SpriteStudio { // MEMO: 後に入れ替え可能なようにエリアスで定義しておく。 @@ -90,6 +90,7 @@ class ISsXmlArchiver virtual bool dc_attr( const char* name , SsString& member ) = 0; virtual bool dc_attr( const char* name , int& member ) = 0; + virtual bool dc_attr( const char* name, float& member) = 0; @@ -165,6 +166,7 @@ class SsXmlIArchiver : public ISsXmlArchiver virtual bool dc_attr( const char* name , SsString& member ); virtual bool dc_attr( const char* name , int& member ); + virtual bool dc_attr( const char* name, float& member); @@ -172,6 +174,9 @@ class SsXmlIArchiver : public ISsXmlArchiver template bool dc( const char* name , std::vector& list , const std::string key = "value" ) { list.clear(); + + if (getxml() == nullptr) return false; + libXML::XMLElement* e = getxml()->FirstChildElement( name ); if (e == 0)return false; if ( key != "" ) @@ -213,6 +218,8 @@ class SsXmlIArchiver : public ISsXmlArchiver #define SPRITESTUDIO6SDK_SERIALIZE_BLOCK void __Serialize(ISsXmlArchiver* ar) #define SPRITESTUDIO6SDK_SSAR_DECLARE(t) ar->dc(#t,t) +#define SPRITESTUDIO6SDK_SSAR_DECLARE_EX(name,t) ar->dc(name,t) + #define SPRITESTUDIO6SDK_SSAR_DECLARE_ATTRIBUTE(t) ar->dc_attr(#t,t) #define SPRITESTUDIO6SDK_SSAR_STRUCT_DECLARE(t) {SsXmlIArchiver _ar( ar , #t );\ @@ -223,6 +230,8 @@ inline bool __SSAR_DECLARE_LIST__( ISsXmlArchiver* ar , std::vector& l { if ( ar->getType() == EnumSsArchiver::in ) { + //SsXmlIArchiver* arc = static_cast(ar)); + //return arc->dc(name, list, key); return (static_cast(ar))->dc( name , list , key ); } @@ -234,9 +243,9 @@ inline bool __SSAR_DECLARE_LIST__( ISsXmlArchiver* ar , std::vector& l } -#define SPRITESTUDIO6SDK_SSAR_DECLARE_LIST(t) spritestudio6::__SSAR_DECLARE_LIST__( ar , t , #t) -#define SPRITESTUDIO6SDK_SSAR_DECLARE_LIST2(t,s) spritestudio6::__SSAR_DECLARE_LIST__( ar , t , s) -#define SPRITESTUDIO6SDK_SSAR_DECLARE_LISTEX(t,key) spritestudio6::__SSAR_DECLARE_LIST__( ar , t , #t , key ) +#define SPRITESTUDIO6SDK_SSAR_DECLARE_LIST(t) SpriteStudio::__SSAR_DECLARE_LIST__( ar , t , #t) +#define SPRITESTUDIO6SDK_SSAR_DECLARE_LIST2(t,s) SpriteStudio::__SSAR_DECLARE_LIST__( ar , t , s) +#define SPRITESTUDIO6SDK_SSAR_DECLARE_LISTEX(t,key) SpriteStudio::__SSAR_DECLARE_LIST__( ar , t , #t , key ) template inline bool __SSAR_DECLARE_ENUM__( ISsXmlArchiver* ar ,myclass& type, const char* name ) @@ -268,8 +277,8 @@ inline bool __SSAR_DECLARE_ATTRIBUTE_ENUM__( ISsXmlArchiver* ar ,myclass& type, -#define SPRITESTUDIO6SDK_SSAR_DECLARE_ENUM(t) spritestudio6::__SSAR_DECLARE_ENUM__( ar , t , #t) -#define SPRITESTUDIO6SDK_SSAR_DECLARE_ATTRIBUTE_ENUM(t) spritestudio6::__SSAR_DECLARE_ATTRIBUTE_ENUM__( ar , t , #t) +#define SPRITESTUDIO6SDK_SSAR_DECLARE_ENUM(t) SpriteStudio::__SSAR_DECLARE_ENUM__( ar , t , #t) +#define SPRITESTUDIO6SDK_SSAR_DECLARE_ATTRIBUTE_ENUM(t) SpriteStudio::__SSAR_DECLARE_ATTRIBUTE_ENUM__( ar , t , #t) bool StringToPoint2( const std::string& str , SsPoint2& point ); @@ -285,6 +294,6 @@ void SsArchiverInit(); -} // namespace spritestudio6 +} // namespace SpriteStudio #endif diff --git a/Common/Loader/ssattribute.cpp b/Common/Loader/ssattribute.cpp index a0aa3f0e..c23f312e 100644 --- a/Common/Loader/ssattribute.cpp +++ b/Common/Loader/ssattribute.cpp @@ -3,7 +3,7 @@ #include "ssattribute.h" #include "../Helper/DebugPrint.h" -namespace spritestudio6 +namespace SpriteStudio { @@ -180,7 +180,9 @@ void GetSsUserDataAnime( const SsKeyframe* key , SsUserDataAnime& v ) { v.integer = 0; v.point.x = v.point.y = 0; - v.rect.x = v.rect.y = v.rect.w = v.rect.h = 0; + //v.rect.x = v.rect.y = v.rect.w = v.rect.h = 0; + v.rect = SsIRect(); + v.string = ""; v.useInteger = key->value.IsExistHashkey("integer"); v.usePoint = key->value.IsExistHashkey("point"); @@ -381,4 +383,21 @@ void GetSsDeformAnime(const SsKeyframe* key, SsDeformAttr& v) } -} // namespace spritestudio6 + +//add SS7.1 追加アトリビュート + +void GetSsAudioAttr(const SsKeyframe* key, SsAudioAttr& v) +{ + v.SoundListID = key->value["SoundListID"].get(); + v.SoundName = key->value["SoundName"].get(); + v.LoopNum = key->value["LoopNum"].get(); +} + +void GetSsTexChangeAttr(const SsKeyframe* key, SsTexChangeAttr& v) +{ + v.TextureName = key->value["TextureName"].get(); + +} + + +} // namespace SpriteStudio diff --git a/Common/Loader/ssattribute.h b/Common/Loader/ssattribute.h index 83c75f97..34058b6d 100644 --- a/Common/Loader/ssattribute.h +++ b/Common/Loader/ssattribute.h @@ -8,7 +8,7 @@ #include -namespace spritestudio6 +namespace SpriteStudio { @@ -19,11 +19,14 @@ class SsKeyframe int time; ///< 時間 SsInterpolationType::_enum ipType; ///< 補間タイプ SsCurve curve; ///< 曲線補間計算用パラメータ + float easingRate; //easing~~で使用する変化率 保存必須 add SS7.1 + SsValue value; ///< 値 public: SsKeyframe() : ipType(SsInterpolationType::invalid) , - time(0) + time(0), + easingRate(0) {} virtual ~SsKeyframe(){} @@ -36,6 +39,13 @@ class SsKeyframe { SPRITESTUDIO6SDK_SSAR_DECLARE( curve ); } + + //add SS7.1 + if (SsNeedsEasingParams(ipType)) + { + SPRITESTUDIO6SDK_SSAR_DECLARE_ATTRIBUTE( easingRate ); + } + // -- ここまで add SS7.1 SsValueSeriarizer( ar , value ); @@ -106,8 +116,10 @@ void GetSsSignalAnime( const SsKeyframe* key , SsSignalAttr& v ); void GetSsInstparamAnime( const SsKeyframe* key , SsInstanceAttr& v ); void GetSsEffectParamAnime( const SsKeyframe* key , SsEffectAttr& v ); void GetSsDeformAnime(const SsKeyframe* key, SsDeformAttr& v); +void GetSsAudioAttr(const SsKeyframe* key, SsAudioAttr& v); +void GetSsTexChangeAttr(const SsKeyframe* key, SsTexChangeAttr& v); -} // namespace spritestudio6 +} // namespace SpriteStudio #endif diff --git a/Common/Loader/sscharconverter.cpp b/Common/Loader/sscharconverter.cpp index 72595409..0c198de3 100644 --- a/Common/Loader/sscharconverter.cpp +++ b/Common/Loader/sscharconverter.cpp @@ -14,7 +14,7 @@ #endif -namespace spritestudio6 +namespace SpriteStudio { std::string SsCharConverter::utf8_to_sjis(const std::string &src) { @@ -113,4 +113,4 @@ std::string SsCharConverter::convert_path_string(const std::string &str) { return dst; } -} // namespace spritestudio6 +} // namespace SpriteStudio diff --git a/Common/Loader/sscharconverter.h b/Common/Loader/sscharconverter.h index 6f1b907e..e8124b96 100644 --- a/Common/Loader/sscharconverter.h +++ b/Common/Loader/sscharconverter.h @@ -3,7 +3,7 @@ #include -namespace spritestudio6 +namespace SpriteStudio { class SsCharConverter { @@ -13,6 +13,6 @@ class SsCharConverter { static std::string convert_path_string(const std::string &str); }; -} // namespace spritestudio6 +} // namespace SpriteStudio #endif //SSSDK_SSCHARCONVERTER_H diff --git a/Common/Loader/sscharmap.cpp b/Common/Loader/sscharmap.cpp new file mode 100644 index 00000000..8c4ebba6 --- /dev/null +++ b/Common/Loader/sscharmap.cpp @@ -0,0 +1,1447 @@ +#include "sscharmap.h" +#include +#include +#include +#include +#include + +#include "ssloader_sspj.h" + + +namespace SpriteStudio +{ + + + const std::string WHITESPACE = " \n\r\t\f\v"; + + std::string ltrim(const std::string& s) + { + size_t start = s.find_first_not_of(WHITESPACE); + return (start == std::string::npos) ? "" : s.substr(start); + } + + std::string rtrim(const std::string& s) + { + size_t end = s.find_last_not_of(WHITESPACE); + return (end == std::string::npos) ? "" : s.substr(0, end + 1); + } + + std::string trim(const std::string& s) { + return rtrim(ltrim(s)); + } + + + static int getInteger(const SsString& str) + { + //bool bOk; + int iValue; + + + std::string str2; + + //iValue = str.toInt(&bOk); + iValue = std::stoi(str); + + + //if (!bOk) { + // return 0; + //} + + return iValue; + } + + static bool getBoolean(const SsString& str) + { + return (getInteger(str) != 0); + } + + static SsString getString(const SsString& str, const SsChar& cStart = '"', const SsChar& cEnd = '"') + { + int iLeft; + int iRight; + + + //iLeft = str.indexOf(cStart); + //iRight = str.lastIndexOf(cEnd); + + iLeft = str.find_first_of(cStart); + iRight = str.find_last_of(cEnd); + + if ((iLeft < 0) || (iRight < 0)) { + return ""; + } + + iLeft++; + + + return str.substr(iLeft, iRight - iLeft); + + //return str.mid(iLeft, iRight - iLeft); + } + + static SsStringList splitString(const SsString& str, const SsChar& cSplit, const SsChar& cIgnoreStart = '"', const SsChar& cIgnoreEnd = '"') + { + SsStringList list; + SsString strSplit; + SsChar c; + int iLength; + int iStart; + int iCount; + bool bIgnore; + + iLength = str.length(); + iStart = 0; + iCount = 0; + bIgnore = false; + + for (int i = 0; i < iLength; i++) { + c = str.at(i); + + if (bIgnore) { + if (c == cIgnoreEnd) { + bIgnore = false; + } + } + else { + if (c == cIgnoreStart) { + bIgnore = true; + } + else + if (c == cSplit) { +// strSplit = str.mid(iStart, iCount); + strSplit = str.substr(iStart, iCount); + + if (strSplit.length() > 0) { + //list.append(strSplit); + list.push_back(strSplit); + } + + iStart = i + 1; + iCount = 0; + continue; + } + } + + iCount++; + } + +// strSplit = str.mid(iStart); + strSplit = str.substr(iStart); + + if (strSplit.length() > 0) { +// list.append(strSplit); + list.push_back(strSplit); + } + + return list; + } + + class ParamProc + { + public: + ParamProc(SsCharMap* pCharMap) + { + m_pCharMap = pCharMap; + + m_mapParam.clear(); + } + + ~ParamProc() + { + m_pCharMap = nullptr; + + m_mapParam.clear(); + } + + bool getNameAndValue(const SsString& strParam, SsString& strName, SsString& strValue) + { + SsStringList nameAndValue; + + nameAndValue = splitString(strParam, '='); + + if (nameAndValue.size() != 2) { + return false; + } + + + //strName = nameAndValue[0].trimmed().toLower(); + //strValue = nameAndValue[1].trimmed(); + + + strName = trim(nameAndValue[0]); + std::transform(strName.cbegin(), strName.cend(), strName.begin(), tolower); + + strValue = trim(nameAndValue[1]); + + + return true; + } + + virtual bool init() + { + m_mapParam.clear(); + + return true; + } + + virtual bool push(const SsString& strParam) + { + SsString strName; + SsString strValue; + + if (!getNameAndValue(strParam, strName, strValue)) { + return false; + } + + m_mapParam[strName] = strValue; + + return true; + } + + virtual bool exec() + { + return true; + } + + protected: + SsCharMap* getCharMap() + { + return m_pCharMap; + } + + const std::map& getParams() + { + return m_mapParam; + } + + private: + SsCharMap* m_pCharMap; + + std::map m_mapParam; + }; + + class InfoParamProc : public ParamProc + { + public: + InfoParamProc(SsCharMap* pCharMap) : ParamProc(pCharMap) {} + + virtual bool exec() override + { + const std::map& mapParams = getParams(); + + //foreach(const SsString & e, mapParams.keys()) { + for( auto item : mapParams ){ + const SsString e = item.first; + //getCharMap()->getInfo().set(e, mapParams[e]); + getCharMap()->getInfo().set(e, item.second); + } + + return true; + } + }; + + class CommonParamProc : public ParamProc + { + public: + CommonParamProc(SsCharMap* pCharMap) : ParamProc(pCharMap) {} + + virtual bool exec() override + { + const std::map& mapParams = getParams(); + + //foreach(const SsString & e, mapParams.keys()) { + for (auto item : mapParams) { + const SsString e = item.first; + getCharMap()->getCommon().set(e, item.second); + //getCharMap()->getCommon().set(e, mapParams[e]); + } + + return true; + } + }; + + class PagesParamProc : public ParamProc + { + public: + PagesParamProc(SsCharMap* pCharMap) : ParamProc(pCharMap) {} + + virtual bool exec() override + { + const std::map& mapParams = getParams(); + + int iId = -1; + +// foreach(const SsString & e, mapParams.keys()) { + for (auto item : mapParams) { + auto e = item.first; + if (e == "id") { +// iId = getInteger(mapParams[e]); + iId = getInteger(item.second); + break; + } + } + + if (iId < 0) { + return false; + } + + for (auto item : mapParams) { + auto e = item.first; + //foreach(const SsString & e, mapParams.keys()) { +// getCharMap()->getPages().set(iId, e, mapParams[e]); + getCharMap()->getPages().set(iId, e, item.second); + } + + getCharMap()->getPages().setDir(iId, getCharMap()->getDir()); + //getCharMap()->getPages().loadImage(iId, gController.project_); + getCharMap()->getPages().loadImage(iId, 0 ); + + return true; + } + }; + + class CharsParamProc : public ParamProc + { + public: + CharsParamProc(SsCharMap* pCharMap) : ParamProc(pCharMap) {} + + virtual bool exec() override + { + const std::map& mapParams = getParams(); + + int iId = -1; + +// foreach(const SsString & e, mapParams.keys()) { + for (auto item : mapParams) { + auto e = item.first; + if (e == "id") { +// iId = getInteger(mapParams[e]); + iId = getInteger(item.second); + break; + } + } + + if (iId < 0) { + return false; + } + +// foreach(const SsString & e, mapParams.keys()) { + for (const auto item : mapParams) { + auto e = item.first; +// getCharMap()->getChars().set(iId, e, mapParams[e]); + getCharMap()->getChars().set(iId, e, item.second); + } + + return true; + } + }; + + class KerningsParamProc : public ParamProc + { + public: + KerningsParamProc(SsCharMap* pCharMap) : ParamProc(pCharMap) {} + + virtual bool exec() override + { + const std::map& mapParams = getParams(); + + int iFirst = -1; + +// foreach(const SsString & e, mapParams.keys()) { + for (auto item : mapParams) { + auto e = item.first; + if (e == "first") { +// iFirst = getInteger(mapParams[e]); + iFirst = getInteger(item.second); + break; + } + } + + if (iFirst < 0) { + return false; + } + + for (auto item : mapParams) { + auto e = item.first; + //foreach(const SsString & e, mapParams.keys()) { +// getCharMap()->getKernings().set(iFirst, e, mapParams[e]); + getCharMap()->getKernings().set(iFirst, e, item.second); + } + + return true; + } + }; + + SsCharMap::Info::Info() + { + clear(); + } + + SsCharMap::Info::~Info() + { + clear(); + } + + void SsCharMap::Info::clear() + { + m_strFace.clear(); + m_bUnicode = false; + m_bSmooth = false; + } + + bool SsCharMap::Info::set(const SsString& strName, const SsString& strValue) + { + // face="Hiragino Sans" + // unicode=0 + // smooth=1 + if (strName == "face") { + m_strFace = getString(strValue); + } + else + if (strName == "unicode") { + m_bUnicode = getBoolean(strValue); + } + else + if (strName == "smooth") { + m_bSmooth = getBoolean(strValue); + } + else + { + return false; + } + + return true; + } + + const SsString& SsCharMap::Info::getFace() + { + return m_strFace; + } + + SsCharMap::Common::Common() + { + clear(); + } + + SsCharMap::Common::~Common() + { + clear(); + } + + void SsCharMap::Common::clear() + { + m_iLineHeight = 0; + m_iBase = 0; + m_Scale = SsSizeF(0, 0); + m_iPages = 0; + } + + bool SsCharMap::Common::set(const SsString& strName, const SsString& strValue) + { + // lineHeight=71 + // base=88 + // scaleW=1024 scaleH=1024 + // pages=1 + if (strName == "lineheight") { + m_iLineHeight = getInteger(strValue); + } + else + if (strName == "base") { + m_iBase = getInteger(strValue); + } + else + if (strName == "scalew") { + m_Scale.setWidth(getInteger(strValue)); + } + else + if (strName == "scaleh") { + m_Scale.setHeight(getInteger(strValue)); + } + else + if (strName == "pages") { + m_iPages = getInteger(strValue); + } + else + { + return false; + } + + return true; + } + + int SsCharMap::Common::getLineHeight() + { + return m_iLineHeight; + } + + SsCharMap::Pages::Pages() + { + clear(); + } + + SsCharMap::Pages::~Pages() + { + clear(); + } + + void SsCharMap::Pages::clear() + { +// foreach(SsCharMapPage * e, m_mapPage) { +/* + for (auto item : m_mapPage) { + auto e = item.first; + + if (e->refCount() == 1) { + gController.RemoveObjectFromSourceTree(e); + } + delete e; + } +*/ + m_mapPage.clear(); + } + + void SsCharMap::Pages::dec(SsProject* pProject) + { + /* + foreach(SsCharMapPage * e, m_mapPage) { + if (e->decRef() <= 0) { + pProject->removeResource(e); + } + delete e; + } +*/ + m_mapPage.clear(); + } + + int SsCharMap::Pages::getCount() const + { +// return m_mapPage.count(); + return m_mapPage.size(); + } + + bool SsCharMap::Pages::set(int iId, const SsString& strName, const SsString& strValue) + { + SsCharMapPage* pPage = nullptr; + + + if (!m_mapPage.count(iId)) { +// if (!m_mapPage.contains(iId)) { + pPage = new SsCharMapPage(); + m_mapPage[iId] = pPage; + } + + pPage = m_mapPage[iId]; + + if (strName == "file") { + SsString str = getString(strValue); + pPage->setFile(str); + } + else + { + return false; + } + + return true; + } + +#if 1 + bool SsCharMap::Pages::setDir(int iId, const SsString& dir) + { + SsCharMapPage* pPage = nullptr; + + if (!m_mapPage.count(iId)) { + pPage = new SsCharMapPage(); + m_mapPage[iId] = pPage; + } + + pPage = m_mapPage[iId]; + + pPage->setDir(dir); + + return true; + } +#endif + + + bool SsCharMap::Pages::loadImage(int iId, SsProject* pProject) + { + SsCharMapPage* pPage = nullptr; + +// if (!m_mapPage.contains(iId)) { + if (!m_mapPage.count(iId)) { + pPage = new SsCharMapPage(); + m_mapPage[iId] = pPage; + } + + pPage = m_mapPage[iId]; + + return pPage->loadImage(pProject); + } + +#if 0 + bool SsCharMap::Pages::saveImage(int iId, const QDir& dir) + { + SsCharMapPage* pPage = nullptr; + + if (!m_mapPage.contains(iId)) { + pPage = new SsCharMapPage(); + m_mapPage[iId] = pPage; + } + + pPage = m_mapPage[iId]; + + return pPage->saveImage(dir); + } +#endif + +#if 0 + bool SsCharMap::Pages::reload() + { + //foreach(int e, m_mapPage.keys()) { + for( auto item : m_mapPage ){ + SsCharMapPage* pPage = m_mapPage[item.first]; + if (pPage) + { + pPage->reload(); + } + } + + return true; + } +#endif + + SsRawImage* SsCharMap::Pages::getImage(int iId) + { + SsCharMapPage* pPage = nullptr; + +// if (!m_mapPage.contains(iId)) { + if (!m_mapPage.count(iId)) { + pPage = new SsCharMapPage(); + m_mapPage[iId] = pPage; + } + + pPage = m_mapPage[iId]; + + return pPage->imagePtr; + } + +#if 0 //Animeterの方へ + SsOpenGLTexture* SsCharMap::Pages::getTexture(int iId) + { + SsCharMapPage* pPage = nullptr; + + if (!m_mapPage.contains(iId)) { + pPage = new SsCharMapPage(); + m_mapPage[iId] = pPage; + } + + pPage = m_mapPage[iId]; + + return pPage->getTexture(); + } +#endif + + + SsCharMap::Chars::Elem::Elem() + { + clear(); + } + + SsCharMap::Chars::Elem::~Elem() + { + clear(); + } + + void SsCharMap::Chars::Elem::clear() + { + m_SrcRect = SsIRect(0, 0, 0, 0); + m_Offset = SsPoint2(0, 0); + m_iAdvance = 0; + m_iPage = 0; + } + + void SsCharMap::Chars::Elem::setSrcX(int iX) + { + m_SrcRect.moveLeft(iX); + } + + void SsCharMap::Chars::Elem::setSrcY(int iY) + { + m_SrcRect.moveTop(iY); + } + + void SsCharMap::Chars::Elem::setSrcWidth(int iWidth) + { + m_SrcRect.setWidth(iWidth); + } + + void SsCharMap::Chars::Elem::setSrcHeight(int iHeight) + { + m_SrcRect.setHeight(iHeight); + } + + void SsCharMap::Chars::Elem::setOffsetX(int iX) + { + m_Offset.setX(iX); + } + + void SsCharMap::Chars::Elem::setOffsetY(int iY) + { + m_Offset.setY(iY); + } + + void SsCharMap::Chars::Elem::setAdvance(int iAdvance) + { + m_iAdvance = iAdvance; + } + + void SsCharMap::Chars::Elem::setPage(int iPage) + { + m_iPage = iPage; + } + + const SsIRect* SsCharMap::Chars::Elem::getSrcRect() + { + return &m_SrcRect; + } + + const SsPoint2* SsCharMap::Chars::Elem::getOffset() + { + return &m_Offset; + } + + int SsCharMap::Chars::Elem::getAdvance() + { + return m_iAdvance; + } + + int SsCharMap::Chars::Elem::getPage() + { + return m_iPage; + } + + SsCharMap::Chars::Chars() + { + clear(); + } + + SsCharMap::Chars::~Chars() + { + clear(); + } + + void SsCharMap::Chars::clear() + { + m_Offset = SsPoint2(); + +// foreach(Elem * e, m_mapElem) { + for(auto item : m_mapElem) { + Elem* e = item.second; + delete e; + } + m_mapElem.clear(); + } + + void SsCharMap::Chars::updateOffset() + { + bool bInit = true; + + m_Offset = SsPoint2(); + +// foreach(Elem * e, m_mapElem) { + for(auto item : m_mapElem) { + Elem* e = item.second; + + const SsPoint2* pOffset = e->getOffset(); + + if (bInit || m_Offset.x > pOffset->x) { + m_Offset.setX(pOffset->x); + } + if (bInit || m_Offset.y > pOffset->y) { + m_Offset.setY(pOffset->y); + } + + bInit = false; + } + } + + const SsPoint2* SsCharMap::Chars::getOffset() + { + return &m_Offset; + } + + int SsCharMap::Chars::getCount() + { + return m_mapElem.size(); + } + + void SsCharMap::Chars::getKeys(std::list& list) + { + list.clear(); +// list.append(m_mapElem.keys()); + + for (auto i : m_mapElem) + list.push_back(i.first); + + } + + bool SsCharMap::Chars::set(int iId, const SsString& strName, const SsString& strValue) + { + Elem* pElem = nullptr; + +// if (!m_mapElem.contains(iId)) { + if (!m_mapElem.count(iId)) { + pElem = new Elem(); + m_mapElem[iId] = pElem; + } + + pElem = m_mapElem[iId]; + + // x=918 y=866 width=0 height=0 + // xoffset=0 yoffset=67 + // xadvance=21 + // page=0 + if (strName == "x") { + pElem->setSrcX(getInteger(strValue)); + } + else + if (strName == "y") { + pElem->setSrcY(getInteger(strValue)); + } + else + if (strName == "width") { + pElem->setSrcWidth(getInteger(strValue)); + } + else + if (strName == "height") { + pElem->setSrcHeight(getInteger(strValue)); + } + else + if (strName == "xoffset") { + pElem->setOffsetX(getInteger(strValue)); + } + else + if (strName == "yoffset") { + pElem->setOffsetY(getInteger(strValue)); + } + else + if (strName == "xadvance") { + pElem->setAdvance(getInteger(strValue)); + } + else + if (strName == "page") { + pElem->setPage(getInteger(strValue)); + } + else + { + return false; + } + + return true; + } + + bool SsCharMap::Chars::hasKey(SsChar cChar) + { +// return m_mapElem.contains(cChar); + bool ret = m_mapElem.count(cChar); + return ret; + } + + const SsIRect* SsCharMap::Chars::getSrcRect(SsChar cChar) + { + if (!hasKey(cChar)) { + return nullptr; + } + + return m_mapElem[cChar]->getSrcRect(); + } + + const SsPoint2* SsCharMap::Chars::getOffset(SsChar cChar) + { + if (!hasKey(cChar)) { + return nullptr; + } + + return m_mapElem[cChar]->getOffset(); + } + + int SsCharMap::Chars::getAdvance(SsChar cChar) + { + if (!hasKey(cChar)) { + return -1; + } + + return m_mapElem[cChar]->getAdvance(); + } + + int SsCharMap::Chars::getPage(SsChar cChar) + { + if (!hasKey(cChar)) { + return -1; + } + + return m_mapElem[cChar]->getPage(); + } + + SsCharMap::Kernings::Elem::Elem() + { + clear(); + } + + SsCharMap::Kernings::Elem::~Elem() + { + clear(); + } + + void SsCharMap::Kernings::Elem::clear() + { + m_cNext = '\0'; + m_iAmount = 0; + } + + void SsCharMap::Kernings::Elem::setNext(SsChar cNext) + { + m_cNext = cNext; + } + + void SsCharMap::Kernings::Elem::setAmount(int iAmount) + { + m_iAmount = iAmount; + } + + SsCharMap::Kernings::Kernings() + { + clear(); + } + + SsCharMap::Kernings::~Kernings() + { + clear(); + } + + void SsCharMap::Kernings::clear() + { +// foreach(Elem * e, m_mapElem) { + for(auto item : m_mapElem) { + Elem* e = item.second; + delete e; + } + m_mapElem.clear(); + } + + int SsCharMap::Kernings::getCount() + { + return m_mapElem.size(); + } + + bool SsCharMap::Kernings::set(int iFirst, const SsString& strName, const SsString& strValue) + { + Elem* pElem = nullptr; + +// if (!m_mapElem.contains(iFirst)) { + if (!m_mapElem.count(iFirst)) { + pElem = new Elem(); + m_mapElem[iFirst] = pElem; + } + + pElem = m_mapElem[iFirst]; + + // second? + // amount? + if (strName == "second") { + pElem->setNext(getInteger(strValue)); + } + else + if (strName == "amount") { + pElem->setAmount(getInteger(strValue)); + } + else + { + return false; + } + + return true; + } + +#if 0 + SsString + SsCharMap::projRelPath() const + { + SsProject* project = (SsProject*)parent; + SsString p(filePath); + // フルパスでない時のみ基準ディレクトリ+相対ファイルパスにする。 + if (!SsPath::isAbsolute(filePath)) + p = SsPath::makeAbsolute(project->getAbsDir(SsBaseDirType::none), filePath); + + return project->makeRelPath(p, ""); //この関数SsFileObjectでよくない? + + } + + SsString SsCharMap::defaultFileExtension() + { + return _D("fnt"); + } + + SsString SsCharMap::fileFilter() + { + return _D("BMFont files (*.fnt)"); + } + + SsCharMap* + SsCharMap::createFromFile(const SsString& path, const SsFileIoOption& option, OnLoadFunc onLoadFunc) + { + std::unique_ptr p(new SsCharMap); + + // パスは追加時のキーになるので必須 + p->filePath = path; + + // ファイルを読み込む + if (!p->loadFromFile(p->filePath, option)) + { + if (p->isMissing) + { + // プロジェクト上に赤字で表示するためファイルが存在しない場合でもオブジェクトを返す。 + return p.release(); + } +#if 1 // プロジェクト上に赤字で表示するため読み込みエラーの場合でもオブジェクトを返す。 2013.04.03 水 14:53 + p->isMissing = true; + //p->dirty = false; + p->setDirty_(false); + + return p.release(); +#else + return NULL; +#endif + } + + return p.release(); + } + +#endif + +#if 0 + SsCharMap::SsCharMap(SsFileObject* pParent) + { + // ? + dirty_ = false; + parent = pParent; + + clear(); + } +#endif + SsCharMap::SsCharMap() + { + clear(); + } + + + SsCharMap::~SsCharMap() + { + clear(); + } + + const SsString& SsCharMap::getDir() + { + return m_Dir; + } + + SsCharMap::Info& SsCharMap::getInfo() + { + return m_Info; + } + + SsCharMap::Common& SsCharMap::getCommon() + { + return m_Common; + } + + SsCharMap::Pages& SsCharMap::getPages() + { + return m_Pages; + } + + SsCharMap::Chars& SsCharMap::getChars() + { + return m_Chars; + } + + SsCharMap::Kernings& SsCharMap::getKernings() + { + return m_Kernings; + } + + void SsCharMap::clear() + { + m_Dir = ""; + m_strFile.clear(); + + m_Info.clear(); + m_Common.clear(); + clearPages(); + m_Chars.clear(); + m_Kernings.clear(); + } + + void SsCharMap::clearPages() + { + m_Pages.clear(); + } + + void SsCharMap::decPages(SsProject* pProject) + { + m_Pages.dec(pProject); + } + +#if 1 + bool SsCharMap::read(SsProject* proj, SsString basefilename) + { + + SsString filename = proj->m_proj_filepath + basefilename; + m_Dir = path2dir(filename); + m_strFile = path2file(basefilename); + + std::fstream fs; + fs.open(filename, std::ios::in);//read + if (!fs.is_open()) + { + return false; + } + +// if (!input.open(QIODevice::ReadOnly)) { +// return false; +// } + + //QByteArray bytes; + SsString strLine; + SsString strColumn; + SsStringList listColumn; + SsStringList listParam; + + //QRegExp regExpOneSpace; + //QRegExp regExpZeroSpace; + + InfoParamProc infoParamProc(this); + CommonParamProc commonParamProc(this); + PagesParamProc pagesParamProc(this); + CharsParamProc charsParamProc(this); + KerningsParamProc kerningsParamProc(this); + std::map mapParamProc; + ParamProc* pParamProc; + + mapParamProc["info"] = &infoParamProc; + mapParamProc["common"] = &commonParamProc; + mapParamProc["page"] = &pagesParamProc; + mapParamProc["chars"] = &charsParamProc; + mapParamProc["char"] = &charsParamProc; + mapParamProc["kernings"] = &kerningsParamProc; + mapParamProc["kerning"] = &kerningsParamProc; + pParamProc = nullptr; + + //regExpOneSpace.setPattern("[ \\t]+"); + //regExpZeroSpace.setPattern("[ \\t]+[=,][ \\t]+"); + + std::string linestr; + while(std::getline(fs,linestr)){ + + //while (!input.atEnd()) { + // bytes = input.readLine(); + + //if (bytes.size() <= 0) { + // break; + //} + + if (linestr.size() <= 0) + { + break; + } + + //strLine = SsString::fromUtf8(bytes).trimmed(); + strLine = trim(linestr); + + //tab等をスペースへ 行を成型 + //strLine = strLine.replace(regExpOneSpace, " "); + //strLine = strLine.replace(regExpZeroSpace, ""); + + listColumn = splitString(strLine, ' ', '"', '"'); + + for (int i = 0; i < listColumn.size(); i++) { +// strColumn = listColumn[i].trimmed().toLower(); + strColumn = trim(listColumn[i]); + std::transform(strColumn.cbegin(), strColumn.cend(), strColumn.begin(), tolower); + + if (mapParamProc.count(strColumn)) { + if (pParamProc) { + pParamProc->exec(); + } + + pParamProc = mapParamProc[strColumn]; + + if (pParamProc) { + pParamProc->init(); + } + } + else { + if (pParamProc) { + pParamProc->push(listColumn[i]); + } + } + } + } + + if (pParamProc) { + pParamProc->exec(); + } + +// input.close(); + fs.close(); + + m_Chars.updateOffset(); + +#if 0 + std::string ret = this->dump(); + FILE* f = fopen( (filename + ".log").c_str(), "wt"); + + fprintf(f, "%s", ret.c_str()); + + fclose(f); +#endif + + + return true; + } +#endif + + +#if 0 + bool SsCharMap::loadFromFile(const SsString& path, const SsFileIoOption& option) + { + QFile file(path.c_str()); + bool bResult = false; + + if (file.exists()) { + m_Dir = QFileInfo(path.c_str()).absoluteDir(); + m_strFile = file.fileName(); + + bResult = read(file); + } + + return bResult; + } + +#ifndef SS_DISABLE_FILE_SAVE + // 保存可能 + bool SsCharMap::saveToFile(const SsString& path, const SsFileIoOption& option, bool cleanDirty) + { + SsSemaphore sem; + + if (sem.HasError()) { + return false; + } + + SsString* pPath = const_cast(&path); + // SsProject::saveToFileProc_ 経由だと値が渡ってくるため内容比較に変更した。 + if (path == s_defaultFilePath) + pPath = &filePath; + + QFileInfo info(m_strFile); + QFileInfo infoSrc(m_Dir, info.fileName()); + QFileInfo infoDst(pPath->c_str()); + + SsFile::copy(infoSrc.absoluteFilePath().toStdString(), infoDst.absoluteFilePath().toStdString(), false); + + QDir dir = infoDst.absoluteDir(); + + for (int i = 0; i < m_Pages.getCount(); i++) { + m_Pages.saveImage(i, dir); + } + + if (SsFileObject::setCleanDirtyCallbac_) + { + (SsFileObject::setCleanDirtyCallbac_)(this, cleanDirty); + } + + return true; + } +#endif + + bool + SsCharMap::reload(const SsFileIoOption* option) + { + SsAutoReverter rev(&isReloading_, true); + + SsProject* project = (SsProject*)parent; + + // カレントをセルマップ基準ディレクトリにする。 + SsCurrentDirectoryRestorer cdr; + project->setCurrentToBaseDir(SsBaseDirType::none); + + // テンポラリとしてロードする + std::unique_ptr cm(new SsCharMap()); + cm->filePath = filePath; + + // ファイルを読み込む + if (!cm->loadFromFile(filePath, *option)) + { + // 失敗 + // TODO? dialog + return false; + } + + return true; + } +#endif + + //add 7.1 SDK + const std::list SsCharMap::getCharMapPages() + { + std::list outlist; + + for (auto& i : m_Pages.getDic()) + { + outlist.push_back( i.second ); + } + + return outlist; + } + + #include + #include + #include + template + std::string format(const std::string& fmt, Args ... args) + { + size_t len = std::snprintf(nullptr, 0, fmt.c_str(), args ...); + std::vector buf(len + 1); + std::snprintf(&buf[0], len + 1, fmt.c_str(), args ...); + return std::string(&buf[0], &buf[0] + len); + } + + + std::string SsCharMapPage::dump() + { + std::string ret = ""; + + ret += format("SsCharMapPage \n"); + ret += format( "dir = %s \n" ,_dir.c_str() ); + + + ret +=("%s", _dir.c_str()); + + return ret; + } + + + std::string SsCharMap::Info::dump() + { + std::string ret = ""; + + ret += format("SsCharMap::Info \n"); + ret += format("Face = %s unicode = %d smooth =%d \n", m_strFace.c_str(), m_bUnicode , (m_bSmooth ? 0: 1) ); + + return ret; + } + + std::string SsCharMap::Common::dump() + { + std::string ret = ""; + + ret += format("SsCharMap::Common \n"); + ret += format("%d %d (%f,%f) %d \n", m_iLineHeight , m_iBase, m_Scale.width(), m_Scale.height(), m_iPages); + + return ret; + } + + std::string SsCharMap::Pages::dump() + { + std::string ret = ""; + + ret += format("SsCharMap::Pages \n"); + + for (auto item : m_mapPage) + { + int id = item.first; + ret += format("id = %d \n", id); + ret += item.second->dump(); + } + + return ret; + } + + std::string SsCharMap::Chars::dump() + { + std::string ret = ""; + + ret += format("SsCharMap::Chars \n"); + ret += format("(%f %f) \n" , m_Offset.x , m_Offset.y ); + + for (auto item : m_mapElem) + { + SsChar code = item.first; + ret += format("code = %d \n", code); + ret += item.second->dump(); + } + + return ret; + } + + std::string SsCharMap::Chars::Elem::dump() + { + std::string ret = ""; + + ret += format("SsCharMap::Chars::Elem \n"); +// ret += format("xy(%d,%d) wh(%d,%d) \n" , m_SrcRect.x , m_SrcRect.y , m_SrcRect.w , m_SrcRect.h); + ret += format("xy(%d,%d) wh(%d,%d) \n", m_SrcRect.x(), m_SrcRect.y(), m_SrcRect.width(), m_SrcRect.height()); + + return ret; + } + + std::string SsCharMap::Kernings::dump() + { + std::string ret = ""; + + ret += format("SsCharMap::Kernings \n"); + for (auto item : m_mapElem) + { + SsChar c = item.first; + + ret += format("Char = %d \n", c); + ret += item.second->dump(); + } + return ret; + } + + std::string SsCharMap::Kernings::Elem::dump() + { + std::string ret = ""; + + ret += format("SsCharMap::Kernings::Elem \n"); + ret += format("Next = %d Amount = %d \n", m_cNext, m_iAmount); + + return ret; + } + + + std::string SsCharMap::dump() + { + std::string ret = ""; + + ret +=("SsCharMap \n"); + ret +=("m_Dir = %s \n",m_Dir.c_str()); + ret +=("m_strFile = %s \n", m_strFile.c_str()); + + ret +=m_Info.dump(); + ret += m_Common.dump(); + ret += m_Pages.dump(); + ret += m_Chars.dump(); + ret += m_Kernings.dump(); + + + return ret; + } + + + bool SsCharMapPage::loadImage(SsProject* proj) { + return true; + } + +} // namespace SpriteStudio diff --git a/Common/Loader/sscharmap.h b/Common/Loader/sscharmap.h new file mode 100644 index 00000000..bf19f731 --- /dev/null +++ b/Common/Loader/sscharmap.h @@ -0,0 +1,293 @@ +#ifndef __SSCHARMAP__ +#define __SSCHARMAP__ + +#include "sstypes.h" +#include "../Helper/SsTextureFactory.h" + + +#define DEBUG_OUT + +#include +#include +#include + +namespace SpriteStudio +{ + class SsProject; + class SsRawImage; + + typedef uint16_t SsChar ; +// typedef SsString SsChar; + //typedef std::basic_string SsString; + + + class SsCharMapPage //ただのイメージファイル情報とした。別途FontTextureManagerで読み込みを行う + { + private: + SsString _dir; + SsString _file; + + public: + SsCharMapPage() : imagePtr(0) {} + virtual ~SsCharMapPage() {} + + void setFile(SsString& str) { _file = str; } + void setDir(const SsString& str) { _dir = str; } + + bool loadImage(SsProject* proj); + + SsString getFilenamePath() { + return _dir + _file; + } + + std::string dump(); + + //SSTextureLoader::DataHandle imagePtr; + SsRawImage* imagePtr; + }; + + + class SsCharMap + { + private: + class Info + { + public: + Info(); + ~Info(); + + void clear(); + + bool set(const SsString& strName, const SsString& strValue); + + const SsString& getFace(); + + std::string dump(); + + private: + SsString m_strFace; + bool m_bUnicode; + bool m_bSmooth; + }; + + class Common + { + public: + Common(); + ~Common(); + + void clear(); + + bool set(const SsString& strName, const SsString& strValue); + + int getLineHeight(); + + std::string dump(); + + private: + int m_iLineHeight; + int m_iBase; + SsSizeF m_Scale; + int m_iPages; + }; + + class Pages + { + public: + Pages(); + ~Pages(); + + void clear(); + void dec(SsProject* pProject); + + int getCount() const; + + bool set(int iId, const SsString& strName, const SsString& strValue); + bool setDir(int iId, const SsString& dir); + + bool loadImage(int iId, SsProject* pProject); + //bool saveImage(int iId, const QDir& dir); + //bool reload(); + + SsRawImage* getImage(int iId); + //SsOpenGLTexture* getTexture(int iId); + + std::string dump(); + + const std::map getDic() + { + return m_mapPage; + } + + private: + std::map m_mapPage; + }; + + class Chars + { + public: + Chars(); + ~Chars(); + + void clear(); + + void updateOffset(); + + + const SsPoint2* getOffset(); + + int getCount(); + void getKeys(std::list& list); + + bool set(int iId, const SsString& strName, const SsString& strValue); + + bool hasKey(SsChar cChar); + const SsIRect* getSrcRect(SsChar cChar); + const SsPoint2* getOffset(SsChar cChar); + int getAdvance(SsChar cChar); + int getPage(SsChar cChar); + + std::string dump(); + + private: + class Elem + { + public: + Elem(); + ~Elem(); + + void clear(); + + void setSrcX(int iX); + void setSrcY(int iY); + void setSrcWidth(int iWidth); + void setSrcHeight(int iHeight); + void setOffsetX(int iX); + void setOffsetY(int iY); + void setAdvance(int iAdvance); + void setPage(int iPage); + + const SsIRect* getSrcRect(); + const SsPoint2* getOffset(); + int getAdvance(); + int getPage(); + + std::string dump(); + + private: + SsIRect m_SrcRect; + SsPoint2 m_Offset; + int m_iAdvance; + int m_iPage; + }; + + SsPoint2 m_Offset; + + // + std::map m_mapElem; + }; + + class Kernings + { + public: + Kernings(); + ~Kernings(); + + void clear(); + + int getCount(); + + bool set(int iFirst, const SsString& strName, const SsString& strValue); + std::string dump(); + + private: + class Elem + { + public: + Elem(); + ~Elem(); + + void clear(); + + void setNext(SsChar cNext); + void setAmount(int iAmount); + + std::string dump(); + + private: + SsChar m_cNext; + int m_iAmount; + }; + + std::map m_mapElem; + }; + + public: + ///typedef std::list CharMapPageList; + typedef std::map CharMapPageDic; + typedef std::pair CharMapPageDicItem; + + + //typedef bool (*OnLoadFunc)(SsXmlIArchive& arc, const unsigned int version, bool* oContinue); + //SsString projRelPath() const; + //static SsString defaultFileExtension(); + //static SsString fileFilter(); + + /// ファイルを読み込んで生成する + //static SsCharMap* createFromFile(const SsString& path, const SsFileIoOption& option = s_defaultFileIoOption, OnLoadFunc = NULL); + + //SsCharMap(SsFileObject* pParent = nullptr); + SsCharMap(); + + ~SsCharMap(); + + const SsString& getDir(); + + Info& getInfo(); + Common& getCommon(); + Pages& getPages(); + Chars& getChars(); + Kernings& getKernings(); + + void clear(); + void clearPages(); + void decPages(SsProject* pProject); + + bool read( SsProject* proj , SsString filename ); + + + const std::list getCharMapPages() ; + std::string dump(); + +#if 0 + bool read(QIODevice& input); + + /** + ファイルを読み込み、各種補正処理、参照ページの読み込みも行う。 + */ + bool loadFromFile(const SsString& path = s_defaultFilePath, const SsFileIoOption& option = s_defaultFileIoOption) override; + + + /// リロードする。 + bool reload(const SsFileIoOption* option = NULL) override; +#endif + + + private: + SsString m_Dir; + SsString m_strFile; + + Info m_Info; + Common m_Common; + Pages m_Pages; + Chars m_Chars; + Kernings m_Kernings; + }; + + typedef std::pair SsCharMapDicItem; + + + +} // namespace SpriteStudio +#endif + diff --git a/Common/Loader/ssloader_ssae.cpp b/Common/Loader/ssloader_ssae.cpp index 1e52d19e..7b528695 100644 --- a/Common/Loader/ssloader_ssae.cpp +++ b/Common/Loader/ssloader_ssae.cpp @@ -1,7 +1,157 @@ #include "ssloader_ssae.h" -namespace spritestudio6 +//#include "partvalues/ssshape.h" +//#include "partvalues/sspartvalueshape.h" +//#include "partvalues/sspartvaluetext.h" + +namespace SpriteStudio { + //const SsString SsPartValueTextInfo::TAG = "text"; + //const SsString SsPartValueShapeInfo::TAG = "shape"; + //const SsString SsPartValueNineSliceInfo::TAG = "nines"; + + + ///シリアライズのための宣言です。 +// SPRITESTUDIO6SDK_SERIALIZE_BLOCK + void SsPart::__Serialize(ISsXmlArchiver* ar) + { + SPRITESTUDIO6SDK_SSAR_DECLARE(name); + SPRITESTUDIO6SDK_SSAR_DECLARE(arrayIndex); + SPRITESTUDIO6SDK_SSAR_DECLARE(parentIndex); + + SPRITESTUDIO6SDK_SSAR_DECLARE_ENUM(type); + SPRITESTUDIO6SDK_SSAR_DECLARE_ENUM(boundsType); + SPRITESTUDIO6SDK_SSAR_DECLARE_ENUM(inheritType); + SPRITESTUDIO6SDK_SSAR_DECLARE_ENUM(alphaBlendType); + SPRITESTUDIO6SDK_SSAR_DECLARE(show); + SPRITESTUDIO6SDK_SSAR_DECLARE(locked); + SPRITESTUDIO6SDK_SSAR_DECLARE(colorLabel); + SPRITESTUDIO6SDK_SSAR_DECLARE(maskInfluence); + + SPRITESTUDIO6SDK_SSAR_DECLARE(refAnimePack); + SPRITESTUDIO6SDK_SSAR_DECLARE(refAnime); + + SPRITESTUDIO6SDK_SSAR_DECLARE(refEffectName); + + SPRITESTUDIO6SDK_SSAR_DECLARE(boneLength); + SPRITESTUDIO6SDK_SSAR_DECLARE(bonePosition); + SPRITESTUDIO6SDK_SSAR_DECLARE(boneRotation); + SPRITESTUDIO6SDK_SSAR_DECLARE(weightPosition); + SPRITESTUDIO6SDK_SSAR_DECLARE(weightImpact); + SPRITESTUDIO6SDK_SSAR_DECLARE(meshWeightType); + SPRITESTUDIO6SDK_SSAR_DECLARE(meshWeightStrong); + SPRITESTUDIO6SDK_SSAR_DECLARE(IKDepth); + SPRITESTUDIO6SDK_SSAR_DECLARE_ENUM(IKRotationArrow); + + //継承率後に改良を実施 + if (ar->getType() == EnumSsArchiver::in) + { + libXML::XMLElement* e = ar->getxml()->FirstChildElement("ineheritRates"); + if (e) + { + libXML::XMLElement* ec = e->FirstChildElement(); + while (ec) + { + //継承設定の取得 + const char* tag = ec->Value(); + SsAttributeKind::_enum enumattr; + + __StringToEnum_(tag , enumattr); + inheritRates[(int)enumattr] = (float)atof(ec->GetText()); + ec = ec->NextSiblingElement(); + } + } + } + + if (type == SsPartType::shape) + { + SsPartValueShape* value = new SsPartValueShape(); + SsString shapeType; + bool shapeMask; + SPRITESTUDIO6SDK_SSAR_DECLARE_EX("shapeType" , shapeType); + SPRITESTUDIO6SDK_SSAR_DECLARE_EX("shapeMask" , shapeMask); + + value->setType(SsPartValueShape::toType(shapeType.c_str())); + value->setMask(shapeMask); + + m_pPartValueInfo.reset(value); + } + + //failed |= !SS_MAKE_NVP(ar, text); TODO when テキストパーツ実装時 + if (type == SsPartType::text) + { + bool textBitmap; + SsString textFamily; + SsString textCharMap; + int textSize; + float textSpace; + bool textSmooth; + bool textMask; + int textWidth; + int textHeight; + int eAnchor; + SsString text; + SsPartValueText* value = new SsPartValueText(); + + //value->text = text; + SPRITESTUDIO6SDK_SSAR_DECLARE_EX("text", text); + + SPRITESTUDIO6SDK_SSAR_DECLARE_EX( "textBitmap", textBitmap); + SPRITESTUDIO6SDK_SSAR_DECLARE_EX( "textFamily" , textFamily); + SPRITESTUDIO6SDK_SSAR_DECLARE_EX( "textCharMap" , textCharMap); + SPRITESTUDIO6SDK_SSAR_DECLARE_EX( "textSize" , textSize); + SPRITESTUDIO6SDK_SSAR_DECLARE_EX( "textSpace" , textSpace); + SPRITESTUDIO6SDK_SSAR_DECLARE_EX( "textSmooth" , textSmooth); + SPRITESTUDIO6SDK_SSAR_DECLARE_EX( "textMask" , textMask); + SPRITESTUDIO6SDK_SSAR_DECLARE_EX( "textWidth" , textWidth); + SPRITESTUDIO6SDK_SSAR_DECLARE_EX( "textHeight" , textHeight); + SPRITESTUDIO6SDK_SSAR_DECLARE_EX( "eAnchor" , eAnchor); + + value->setBitmap(textBitmap); + value->setFamily(textFamily.c_str()); + value->setCharMap(textCharMap.c_str()); + value->setSize(textSize); + value->setSpace(textSpace); + value->setSmooth(textSmooth); + value->setMask(textMask); + value->setWidth(textWidth); + value->setHeight(textHeight); + value->setAnchor((SsAnchorButton::Anchor)eAnchor); + value->setText(text); + //this->text = text; + + m_pPartValueInfo.reset(value); + + } + + + if (type == SsPartType::nines) + { + SsPartValueNines* value = new SsPartValueNines(); + int ninesMarginL; + int ninesMarginR; + int ninesMarginT; + int ninesMarginB; + int ninesFillMode; + bool ninesMask; + + SPRITESTUDIO6SDK_SSAR_DECLARE_EX( "ninesMarginL" , ninesMarginL); + SPRITESTUDIO6SDK_SSAR_DECLARE_EX( "ninesMarginR" , ninesMarginR); + SPRITESTUDIO6SDK_SSAR_DECLARE_EX( "ninesMarginT" , ninesMarginT); + SPRITESTUDIO6SDK_SSAR_DECLARE_EX( "ninesMarginB" , ninesMarginB); + SPRITESTUDIO6SDK_SSAR_DECLARE_EX( "ninesFillMode" , ninesFillMode); + SPRITESTUDIO6SDK_SSAR_DECLARE_EX( "ninesMask" , ninesMask); + + value->setMargin(SsMargins(ninesMarginL, ninesMarginT, ninesMarginR, ninesMarginB)); + value->setFillMode(ninesFillMode); + value->setMask(ninesMask); + + m_pPartValueInfo.reset(value); + } + + +} + SsAnimePack* ssloader_ssae::Load(const std::string& filename ) @@ -95,4 +245,4 @@ void SsMeshBindInfo::fromString(SsString str) } -} // namespace spritestudio6 +} // namespace SpriteStudio diff --git a/Common/Loader/ssloader_ssae.h b/Common/Loader/ssloader_ssae.h index b94445ba..96034e10 100644 --- a/Common/Loader/ssloader_ssae.h +++ b/Common/Loader/ssloader_ssae.h @@ -5,15 +5,101 @@ #include "ssarchiver.h" #include "ssattribute.h" + +#include "partvalues/sspartvalue.h" +#include "partvalues/sspartvaluenines.h" +#include "partvalues/sspartvalueshape.h" +#include "partvalues/sspartvaluetext.h" + #define SPRITESTUDIO6_SSAEVERSION "2.00.01" -namespace spritestudio6 +namespace SpriteStudio { class SsAnimation; +#if 0 +// SsPartValueXXX のデータ型 +class ISsPartValueInfo +{ +public: + ISsPartValueInfo() : m_strTag("unknown") {} + virtual ~ISsPartValueInfo() {} + + virtual SsString getTag() { + return m_strTag; + } + +protected: + SsString m_strTag; //!< タグ + +}; + + +// SsPartValueTextInfo のデータ型 XML名と一致させている +class SsPartValueTextInfo : public ISsPartValueInfo +{ +public: + static const SsString TAG; + + SsPartValueTextInfo() { + m_strTag = SsPartValueTextInfo::TAG; + } + virtual ~SsPartValueTextInfo() {} + + SsString text; + + bool textBitmap; + SsString textFamily; + SsString textCharMap; + int textSize; + float textSpace; + bool textSmooth; + bool textMask; + int textWidth; + int textHeight; + int eAnchor; +}; + + +// SsPartValueShapeInfo のデータ型 XML名と一致させている +class SsPartValueShapeInfo : public ISsPartValueInfo +{ +public: + static const SsString TAG; + + SsPartValueShapeInfo() { + m_strTag = SsPartValueShapeInfo::TAG; + } + virtual ~SsPartValueShapeInfo() {} + + SsString shapeType; + bool shapeMask; +}; + + +// SsPartValueNineSliceInfo のデータ型 XML名と一致させている +class SsPartValueNineSliceInfo : public ISsPartValueInfo +{ +public: + static const SsString TAG; + + SsPartValueNineSliceInfo() { + m_strTag = SsPartValueNineSliceInfo::TAG; + } + virtual ~SsPartValueNineSliceInfo() {} + + int ninesMarginL; + int ninesMarginR; + int ninesMarginT; + int ninesMarginB; + int ninesFillMode; + bool ninesMask; +}; +#endif + /// アニメーション再生設定情報です。 @@ -54,6 +140,7 @@ class SsAnimationSettings + //パーツ一つあたりの情報を保持するデータです。 class SsPart { @@ -107,6 +194,16 @@ class SsPart int IKDepth; //!< IK深度 SsIkRotationArrow::_enum IKRotationArrow;//!< 回転方向 + // テキストパーツ用パラメータ + //SsString text; ///< 表示テキスト [変数名変更禁止] + + //add SS7.1 拡張情報 + //std::unique_ptr m_pPartValueInfo; + //SsString text; + std::unique_ptr m_pPartValueInfo; + + + public: SsPart() : name("") , arrayIndex(0), parentIndex(0) , show(0) , locked(0) , maskInfluence(true) @@ -142,58 +239,9 @@ class SsPart } virtual ~SsPart(){} + void __Serialize(ISsXmlArchiver* ar); + - ///シリアライズのための宣言です。 - SPRITESTUDIO6SDK_SERIALIZE_BLOCK - { - SPRITESTUDIO6SDK_SSAR_DECLARE( name ); - SPRITESTUDIO6SDK_SSAR_DECLARE( arrayIndex ); - SPRITESTUDIO6SDK_SSAR_DECLARE( parentIndex ); - - SPRITESTUDIO6SDK_SSAR_DECLARE_ENUM( type ); - SPRITESTUDIO6SDK_SSAR_DECLARE_ENUM( boundsType ); - SPRITESTUDIO6SDK_SSAR_DECLARE_ENUM( inheritType ); - SPRITESTUDIO6SDK_SSAR_DECLARE_ENUM( alphaBlendType ); - SPRITESTUDIO6SDK_SSAR_DECLARE( show ); - SPRITESTUDIO6SDK_SSAR_DECLARE( locked ); - SPRITESTUDIO6SDK_SSAR_DECLARE( colorLabel ); - SPRITESTUDIO6SDK_SSAR_DECLARE( maskInfluence ); - - SPRITESTUDIO6SDK_SSAR_DECLARE( refAnimePack ); - SPRITESTUDIO6SDK_SSAR_DECLARE( refAnime ); - - SPRITESTUDIO6SDK_SSAR_DECLARE( refEffectName ); - - SPRITESTUDIO6SDK_SSAR_DECLARE( boneLength ); - SPRITESTUDIO6SDK_SSAR_DECLARE( bonePosition ); - SPRITESTUDIO6SDK_SSAR_DECLARE( boneRotation ); - SPRITESTUDIO6SDK_SSAR_DECLARE( weightPosition ); - SPRITESTUDIO6SDK_SSAR_DECLARE( weightImpact ); - SPRITESTUDIO6SDK_SSAR_DECLARE( meshWeightType ); - SPRITESTUDIO6SDK_SSAR_DECLARE( meshWeightStrong ); - SPRITESTUDIO6SDK_SSAR_DECLARE( IKDepth ); - SPRITESTUDIO6SDK_SSAR_DECLARE_ENUM( IKRotationArrow ); - - //継承率後に改良を実施 - if ( ar->getType() == EnumSsArchiver::in ) - { - libXML::XMLElement* e = ar->getxml()->FirstChildElement( "ineheritRates" ); - if ( e ) - { - libXML::XMLElement* ec = e->FirstChildElement(); - while(ec) - { - //継承設定の取得 - const char* tag = ec->Value(); - SsAttributeKind::_enum enumattr; - - __StringToEnum_( tag , enumattr ); - inheritRates[(int)enumattr] = (float)atof( ec->GetText() ); - ec = ec->NextSiblingElement(); - } - } - } - } }; enum @@ -433,7 +481,7 @@ class ssloader_ssae -} // namespace spritestudio6 +} // namespace SpriteStudio #endif diff --git a/Common/Loader/ssloader_ssce.cpp b/Common/Loader/ssloader_ssce.cpp index 4c1e2640..cc3f9b10 100644 --- a/Common/Loader/ssloader_ssce.cpp +++ b/Common/Loader/ssloader_ssce.cpp @@ -2,7 +2,7 @@ #include "ssstring_uty.h" -namespace spritestudio6 +namespace SpriteStudio { SsCellMap* ssloader_ssce::Load(const std::string& filename ) @@ -29,4 +29,4 @@ SsCellMap* ssloader_ssce::Load(const std::string& filename ) -} // namespace spritestudio6 +} // namespace SpriteStudio diff --git a/Common/Loader/ssloader_ssce.h b/Common/Loader/ssloader_ssce.h index a8419d4f..79095d1d 100644 --- a/Common/Loader/ssloader_ssce.h +++ b/Common/Loader/ssloader_ssce.h @@ -6,7 +6,7 @@ #define SPRITESTUDIO6_SSCEVERSION "2.00.00" -namespace spritestudio6 +namespace SpriteStudio { ///パーツに使用される画素の矩形範囲を示した構造です。 @@ -37,18 +37,20 @@ class SsCell int divw; int divh; - SsCell(){} - virtual ~SsCell() { -/* - for (std::vector::iterator itr = innerPoint.begin(); - itr != innerPoint.end(); itr++) delete (*itr); - for (std::vector::iterator itr = outerPoint.begin(); - itr != outerPoint.end(); itr++) delete (*itr); - for (std::vector::iterator itr = meshPointList.begin(); - itr != meshPointList.end(); itr++) delete (*itr); - for (std::vector::iterator itr = meshTriList.begin(); - itr != meshTriList.end(); itr++) delete (*itr); -*/ + SsCell() + : + name(""), + pos(SsPoint2(0, 0)), + size(SsPoint2(0, 0)), + pivot(SsPoint2(0, 0)), + rotated(false), + ismesh(false), + divtype(SsMeshDivType::unknown), + divw(0), + divh(0) + {} + virtual ~SsCell() + { } @@ -136,6 +138,6 @@ class ssloader_ssce }; -} // namespace spritestudio6 +} // namespace SpriteStudio #endif diff --git a/Common/Loader/ssloader_ssee.cpp b/Common/Loader/ssloader_ssee.cpp index f7055cc0..e5fd225f 100644 --- a/Common/Loader/ssloader_ssee.cpp +++ b/Common/Loader/ssloader_ssee.cpp @@ -6,7 +6,7 @@ #include "../Helper/DebugPrint.h" -namespace spritestudio6 +namespace SpriteStudio { @@ -64,4 +64,4 @@ void ssloader_ssee::loadPostProcessing( SsEffectFile* file , SsProject* pj ) } -} // namespace spritestudio6 +} // namespace SpriteStudio diff --git a/Common/Loader/ssloader_ssee.h b/Common/Loader/ssloader_ssee.h index 989bac11..a5a470e3 100644 --- a/Common/Loader/ssloader_ssee.h +++ b/Common/Loader/ssloader_ssee.h @@ -8,7 +8,7 @@ #define SPRITESTUDIO6_SSEEVERSION "2.00.00" -namespace spritestudio6 +namespace SpriteStudio { class SimpleTree @@ -222,6 +222,6 @@ class ssloader_ssee -} // namespace spritestudio6 +} // namespace SpriteStudio #endif diff --git a/Common/Loader/ssloader_sspj.cpp b/Common/Loader/ssloader_sspj.cpp index 0775d4d2..fde28b7d 100644 --- a/Common/Loader/ssloader_sspj.cpp +++ b/Common/Loader/ssloader_sspj.cpp @@ -8,7 +8,7 @@ #include "../Helper/DebugPrint.h" #include "sscharconverter.h" -namespace spritestudio6 +namespace SpriteStudio { @@ -143,6 +143,17 @@ SsSequence* SsProject::findSequence( SsString& sequencePackName , SsString& Seq } +SsCharMap* SsProject::findCharMap( SsString name) +{ + + if (charmapDic.count(name) > 0) + { + return charmapDic[name].get(); + } + + return 0; +} + SsProject* ssloader_sspj::Load(const std::string& filename ) { libXML::XMLDocument xml; @@ -262,6 +273,54 @@ SsProject* ssloader_sspj::Load(const std::string& filename ) } } + //add SS7.1 サウンドリストを追加 + for (size_t i = 0; i < proj->getAudioPackNum(); i++) + { + SsString path = SsCharConverter::convert_path_string(proj->getAudioPackFilePath(i)); + SsAudioPack* audio = ssloader_ssse::Load(path); + if ((audio) && (checkFileVersion(audio->version, SPRITESTUDIO6_SSSEVERSION) == true)) + { + proj->soundList.push_back(std::move(std::unique_ptr(audio))); + } + else { + //エラー + DEBUG_PRINTF("audio load error : %s", path.c_str()); + DEBUG_PRINTF("ssse old version"); + + if (audio) delete audio; + delete proj; + return 0; + } + } + //add SS7.1 bitmap font + for (auto item : proj->charmapNames) + { + //SsString path = nomarizeFilename(proj->m_proj_filepath + item); + //SsString path = item; + + SsCharMap* chamap = new SsCharMap(); + + if (chamap->read(proj , item)) + { + proj->charmapDic[item] = std::move(std::unique_ptr(chamap)); + //proj->charmapList.push_back(std::move(std::unique_ptr(chamap)) ); + + } + else { + //エラー + DEBUG_PRINTF("charmap load error : %s", item.c_str()); + DEBUG_PRINTF("ssse old version"); + + if (chamap) delete chamap; + delete proj; + return 0; + + } + + + } + + return proj; } @@ -288,4 +347,4 @@ SsCellMap* SsProject::findCellMap( SsString& str ) } -} // namespace spritestudio6 +} // namespace SpriteStudio diff --git a/Common/Loader/ssloader_sspj.h b/Common/Loader/ssloader_sspj.h index 639acee7..3a1f0464 100644 --- a/Common/Loader/ssloader_sspj.h +++ b/Common/Loader/ssloader_sspj.h @@ -11,15 +11,57 @@ #include "ssloader_ssce.h" #include "ssloader_ssee.h" #include "ssloader_ssqe.h" +#include "ssloader_ssse.h" // add SS7.1 +#include "sscharmap.h" #include #include #define SPRITESTUDIO6_SSPJVERSION "2.00.00" -namespace spritestudio6 +namespace SpriteStudio { + + // プロジェクトツリーで isMissing など透過的にアクセスできるよう SsFileObject 継承に変更 + class TextureInfo + { + public: + + SsString PathName;//metadataからの相対パス + int index; //再配置ずれ用 + int flags; //グループ化、パッキングするなどのフラグ用 + + TextureInfo() { } + virtual ~TextureInfo() { } + + SPRITESTUDIO6SDK_SERIALIZE_BLOCK + { + SPRITESTUDIO6SDK_SSAR_DECLARE(PathName); + SPRITESTUDIO6SDK_SSAR_DECLARE(index); + SPRITESTUDIO6SDK_SSAR_DECLARE(flags); + } + }; + + + class SsTextureList + { + public: + SsTextureList() {} + virtual ~SsTextureList() {} + + std::vector files; + + SPRITESTUDIO6SDK_SERIALIZE_BLOCK + { + SPRITESTUDIO6SDK_SSAR_DECLARE_LIST(files); + + } + + }; + + + /// プロジェクトファイルの設定が記載されているデータです。 /// 以下のタグはエディタ編集用のデータなので読み飛ばします。 // 編集時設定のためよまない @@ -89,6 +131,14 @@ typedef SsEffectFileList::iterator SsEffectFileListItr; typedef std::vector> SsSequencePackList; typedef SsSequencePackList::iterator SsSequencePackListItr; +typedef std::vector> SsAudioPackList; +typedef SsAudioPackList::iterator SsAudioPackListItr; + +typedef std::map> CharMapDic; +typedef std::vector> CharMapList; +//typedef CharMapDic::iterator CharMapDicItr; + + /// XMLドキュメントとなっているsspjファイルのデータ保持を提供するクラスです。 ///以下はエディタ情報のため読み飛ばします。 /// animeSettings デフォルトのアニメーション設定 @@ -106,10 +156,18 @@ class SsProject std::vector textureList; //!< セルマップから取得したテクスチャのリスト std::vector sequencepackNames; //!< シーケンスファイルのリスト + std::vector audiopackNames; //!< サウンドリストの文字列リスト + std::vector charmapNames; ///< キャラマップファイルパスのリスト + SsTextureList ExternalTextures; //!< 追加テクスチャの文字列リスト + + SsAnimePackList animeList; //!< アニメーションのリスト SsSsCellMapList cellmapList; //!< セルマップリスト SsEffectFileList effectfileList; //!< エフェクトのリスト SsSequencePackList sequenceList; //!< シーケンスのリスト + SsAudioPackList soundList; //!< サウンドリスト +// CharMapList charmapList; //!< キャラクターマップ(bitmap font) + CharMapDic charmapDic; //!< キャラクターマップ(bitmap font) //ロード時に作成されるワーク SsString m_proj_filepath; ///プロジェクトファイルのパス @@ -133,6 +191,10 @@ class SsProject ///シーケンスパックの数量を取得する const size_t getSequencePackNum(){ return sequencepackNames.size(); } + ///シーケンスパックの数量を取得する + const size_t getAudioPackNum() { return audiopackNames.size(); } + + ///アニメパックデータのコンテナを取得する SsAnimePackList& getAnimePackList(){ return animeList;} @@ -173,7 +235,8 @@ class SsProject SsSequencePack* findSequencePack( SsString& sequencePackName ); - + SsCharMap* findCharMap(SsString name); + SsCellMap* findCellMap( SsString& str ); @@ -188,6 +251,12 @@ class SsProject SPRITESTUDIO6SDK_SSAR_DECLARE( effectFileNames ); SPRITESTUDIO6SDK_SSAR_DECLARE( sequencepackNames ); + //add SS7.1 + SPRITESTUDIO6SDK_SSAR_DECLARE( charmapNames ); + SPRITESTUDIO6SDK_SSAR_DECLARE( audiopackNames); + SPRITESTUDIO6SDK_SSAR_STRUCT_DECLARE(ExternalTextures); + //ExternalTextures + } public: @@ -252,6 +321,11 @@ class SsProject return getSsqeBasepath() + sequencepackNames[index]; } + //add SS7.1 + SsString getAudioPackFilePath(size_t index) { + if (audiopackNames.size() <= index) return ""; + return m_proj_filepath + audiopackNames[index]; + } }; ///sspjのローダークラスです。 @@ -267,6 +341,6 @@ class ssloader_sspj }; -} // namespace spritestudio6 +} // namespace SpriteStudio #endif diff --git a/Common/Loader/ssloader_ssqe.cpp b/Common/Loader/ssloader_ssqe.cpp index efc72d6f..91788f74 100644 --- a/Common/Loader/ssloader_ssqe.cpp +++ b/Common/Loader/ssloader_ssqe.cpp @@ -1,6 +1,6 @@ #include "ssloader_ssqe.h" -namespace spritestudio6 +namespace SpriteStudio { @@ -37,4 +37,4 @@ SsSequence* SsSequencePack::findSequence(SsString& name) return 0; } -} // namespace spritestudio6 +} // namespace SpriteStudio diff --git a/Common/Loader/ssloader_ssqe.h b/Common/Loader/ssloader_ssqe.h index eec21cb1..da171627 100644 --- a/Common/Loader/ssloader_ssqe.h +++ b/Common/Loader/ssloader_ssqe.h @@ -6,7 +6,7 @@ #define SPRITESTUDIO6_SSQEVERSION "1.00.00" -namespace spritestudio6 +namespace SpriteStudio { class SsSequence; @@ -116,6 +116,6 @@ class ssloader_ssqe -} // namespace spritestudio6 +} // namespace SpriteStudio #endif diff --git a/Common/Loader/ssloader_ssse.cpp b/Common/Loader/ssloader_ssse.cpp new file mode 100644 index 00000000..ddb02a4c --- /dev/null +++ b/Common/Loader/ssloader_ssse.cpp @@ -0,0 +1,26 @@ +#include "ssloader_ssse.h" + +namespace SpriteStudio +{ + + + SsAudioPack* ssloader_ssse::Load(const std::string& filename ) +{ + + SsAudioPack* audioPack = new SsAudioPack(); + + libXML::XMLDocument xml; + if ( libXML::XML_SUCCESS == xml.LoadFile( filename.c_str() ) ) + { + SsXmlIArchiver ar( xml.GetDocument() , "SpriteStudioSoundList" ); + audioPack->__Serialize( &ar ); + }else{ + delete audioPack; + audioPack = 0; + } + + return audioPack; +} + + +} // namespace SpriteStudio diff --git a/Common/Loader/ssloader_ssse.h b/Common/Loader/ssloader_ssse.h new file mode 100644 index 00000000..1dda7c47 --- /dev/null +++ b/Common/Loader/ssloader_ssse.h @@ -0,0 +1,106 @@ +#ifndef __SSLOADER_SSSE__ +#define __SSLOADER_SSSE__ + +#include "sstypes.h" +#include "ssarchiver.h" + +#define SPRITESTUDIO6_SSSEVERSION "1.00.00" + +namespace SpriteStudio +{ + + +struct SsSoundFile +{ +public: + SsString Alias; + SsString filename; + int msec; + //int temp_index; + //bool exist; //ファイルが存在するかどうか + + + SsSoundFile() : msec(0) {} + + SPRITESTUDIO6SDK_SERIALIZE_BLOCK + { + SPRITESTUDIO6SDK_SSAR_DECLARE(Alias); + SPRITESTUDIO6SDK_SSAR_DECLARE(filename); + SPRITESTUDIO6SDK_SSAR_DECLARE(msec); + } + +}; + + +struct SsSoudFileList +{ +public: + int id; //どちらかというよUID + SsString Alias; + std::vector sounds; + + + SsSoudFileList() : id(0), Alias("") + { + } + + ~SsSoudFileList() { + for (auto i : sounds) + { + delete i; + } + sounds.clear(); + } + + SPRITESTUDIO6SDK_SERIALIZE_BLOCK + { + SPRITESTUDIO6SDK_SSAR_DECLARE(id); + SPRITESTUDIO6SDK_SSAR_DECLARE(Alias); + SPRITESTUDIO6SDK_SSAR_DECLARE_LIST(sounds); + } + +}; + + +class SsAudioPack +{ +public: + SsString version; + SsString name; + SsSoudFileList table; + + + + SPRITESTUDIO6SDK_SERIALIZE_BLOCK + { + SPRITESTUDIO6SDK_SSAR_DECLARE_ATTRIBUTE(version); + SPRITESTUDIO6SDK_SSAR_DECLARE(name); + SPRITESTUDIO6SDK_SSAR_STRUCT_DECLARE(table); + + } + +}; + + +/* +* @class ssloader_ssse +* @brief ssseファイルをロードするためのクラスです。 +*/ +class ssloader_ssse +{ +public: + ssloader_ssse(){} + virtual ~ssloader_ssse(){} + + ///ssseファイル名を指定しロードが成功したらそのSsSequencePackのポインタを返します。 + static SsAudioPack* Load(const std::string& filename ); + +}; + + + + + +} // namespace SpriteStudio + +#endif diff --git a/Common/Loader/ssstring_uty.cpp b/Common/Loader/ssstring_uty.cpp index 812dfb89..248e45b8 100644 --- a/Common/Loader/ssstring_uty.cpp +++ b/Common/Loader/ssstring_uty.cpp @@ -11,7 +11,7 @@ #endif -namespace spritestudio6 +namespace SpriteStudio { @@ -43,7 +43,7 @@ void split_string( const std::string &in_str , } - +//パスからフォルダのみにする std::string path2dir(const std::string &path) { // MEMO: find_last_ofが未発見時に-1を返すので、maxをsize_tで実体化したらダメ const std::string::size_type pos = std::max((signed)path.find_last_of('/'), (signed)path.find_last_of('\\')); @@ -186,4 +186,4 @@ bool checkFileVersion(std::string fileVersion, std::string nowVersion) } -} // namespace spritestudio6 +} // namespace SpriteStudio diff --git a/Common/Loader/ssstring_uty.h b/Common/Loader/ssstring_uty.h index e4777c15..7b4f0474 100644 --- a/Common/Loader/ssstring_uty.h +++ b/Common/Loader/ssstring_uty.h @@ -10,7 +10,7 @@ #include #include -namespace spritestudio6 +namespace SpriteStudio { /* @@ -121,6 +121,6 @@ class SsStringTokenizer }; -} // namespace spritestudio6 +} // namespace SpriteStudio #endif diff --git a/Common/Loader/sstypes.cpp b/Common/Loader/sstypes.cpp index 45060daa..cd2bd0ac 100644 --- a/Common/Loader/sstypes.cpp +++ b/Common/Loader/sstypes.cpp @@ -1,6 +1,6 @@ #include "sstypes.h" -namespace spritestudio6 +namespace SpriteStudio { //--------------------------------------------------------------- @@ -10,7 +10,10 @@ SsString __EnumToString_( SsPartType::_enum n ) if ( SsPartType::invalid == n ) return "invalid"; if ( SsPartType::null == n) return "null"; if ( SsPartType::normal == n) return "normal"; - if ( SsPartType::text == n) return "text"; + if ( SsPartType::shape == n) return "shape"; //add ss7.1 + if ( SsPartType::text == n) return "text"; + if ( SsPartType::nines == n) return "nines"; //add ss7.1 + if ( SsPartType::instance == n) return "instance"; if ( SsPartType::effect == n) return "effect"; @@ -23,6 +26,7 @@ SsString __EnumToString_( SsPartType::_enum n ) if (SsPartType::joint == n) return "joint"; if (SsPartType::bonepoint == n) return "bonepoint"; + if (SsPartType::audio == n) return "ssaudio"; //add ss7.1 return "invalid"; } @@ -33,7 +37,10 @@ void __StringToEnum_( SsString n , SsPartType::_enum& out) if ( n == "invalid") out = SsPartType::invalid; if ( n == "null") out = SsPartType::null; if ( n == "normal") out = SsPartType::normal; + if ( n == "shape") out = SsPartType::shape; //add ss7.1 if ( n == "text") out = SsPartType::text; + if ( n == "nines") out = SsPartType::nines; //add ss7.1 + if ( n == "instance") out = SsPartType::instance; if ( n == "effect") out = SsPartType::effect; @@ -46,6 +53,7 @@ void __StringToEnum_( SsString n , SsPartType::_enum& out) } if (n == "joint") out = SsPartType::joint; if (n == "bonepoint") out = SsPartType::bonepoint; + if (n == "ssaudio") out = SsPartType::audio; } @@ -95,7 +103,7 @@ void __StringToEnum_( SsString n , SsBoundsType::_enum &out ) //--------------------------------------------------------------- -//相互変換 SsBoundsType +//相互変換 SsInheritType SsString __EnumToString_( SsInheritType::_enum n ) { if ( SsInheritType::invalid == n) return "invalid"; @@ -159,6 +167,30 @@ SsString __EnumToString_( SsInterpolationType::_enum n ) if ( SsInterpolationType::acceleration == n) return "acceleration"; if ( SsInterpolationType::deceleration == n) return "deceleration"; + if (SsInterpolationType::easeIn == n) return "easeIn"; + if (SsInterpolationType::easeOut == n) return "easeOut"; + if (SsInterpolationType::easeInOut == n) return "easeInOut"; + + if (SsInterpolationType::easeExponentialIn == n) return "easeExponentialIn"; + if (SsInterpolationType::easeExponentialOut == n) return "easeExponentialOut"; + if (SsInterpolationType::easeExponentialInOut == n) return "easeExponentialInOut"; + + if (SsInterpolationType::easeSineIn == n) return "easeSineIn"; + if (SsInterpolationType::easeSineOut == n) return "easeSineOut"; + if (SsInterpolationType::easeSineInOut == n) return "easeSineInOut"; + + if (SsInterpolationType::easeElasticIn == n) return "easeElasticIn"; + if (SsInterpolationType::easeElasticOut == n) return "easeElasticOut"; + if (SsInterpolationType::easeElasticInOut == n) return "easeElasticInOut"; + + if (SsInterpolationType::easeBounceIn == n) return "easeBounceIn"; + if (SsInterpolationType::easeBounceOut == n) return "easeBounceOut"; + if (SsInterpolationType::easeBounceInOut == n) return "easeBounceInOut"; + + if (SsInterpolationType::easeBackIn == n) return "easeBackIn"; + if (SsInterpolationType::easeBackOut == n) return "easeBackOut"; + if (SsInterpolationType::easeBackInOut == n) return "easeBackInOut"; + return "none"; } @@ -172,6 +204,30 @@ void __StringToEnum_( SsString n , SsInterpolationType::_enum &out ) if ( n == "bezier") out = SsInterpolationType::bezier; if ( n == "acceleration") out = SsInterpolationType::acceleration; if ( n == "deceleration") out = SsInterpolationType::deceleration; + + if (n == "easeIn") out = SsInterpolationType::easeIn; + if (n == "easeOut") out = SsInterpolationType::easeOut; + if (n == "easeInOut") out = SsInterpolationType::easeInOut; + + if (n == "easeExponentialIn") out = SsInterpolationType::easeExponentialIn; + if (n == "easeExponentialOut") out = SsInterpolationType::easeExponentialOut; + if (n == "easeExponentialInOut") out = SsInterpolationType::easeExponentialInOut; + + if (n == "easeSineIn") out = SsInterpolationType::easeSineIn; + if (n == "easeSineOut") out = SsInterpolationType::easeSineOut; + if (n == "easeSineInOut") out = SsInterpolationType::easeSineInOut; + + if (n == "easeElasticIn") out = SsInterpolationType::easeElasticIn; + if (n == "easeElasticOut") out = SsInterpolationType::easeElasticOut; + if (n == "easeElasticInOut") out = SsInterpolationType::easeElasticInOut; + + if (n == "easeBounceIn") out = SsInterpolationType::easeBounceIn; + if (n == "easeBounceOut") out = SsInterpolationType::easeBounceOut; + if (n == "easeBounceInOut") out = SsInterpolationType::easeBounceInOut; + + if (n == "easeBackIn") out = SsInterpolationType::easeBackIn; + if (n == "easeBackOut") out = SsInterpolationType::easeBackOut; + if (n == "easeBackInOut") out = SsInterpolationType::easeBackInOut; } //--------------------------------------------------------------- @@ -283,6 +339,8 @@ SsString __EnumToString_( SsAttributeKind::_enum n ) if ( SsAttributeKind::mask == n) return "MASK"; if ( SsAttributeKind::deform == n) return "DEFM"; + if (SsAttributeKind::audio == n) return "ADIO"; //add SS7.1 + if (SsAttributeKind::texchange == n) return "TCHG"; //add SS7.1 return "invalid"; @@ -335,6 +393,8 @@ void __StringToEnum_( SsString n , SsAttributeKind::_enum &out ) if ( n == "MASK") out = SsAttributeKind::mask; if ( n == "DEFM") out = SsAttributeKind::deform; + if (n == "ADIO") out = SsAttributeKind::audio; + if (n == "TCHG") out = SsAttributeKind::texchange; } @@ -342,7 +402,7 @@ void __StringToEnum_( SsString n , SsAttributeKind::_enum &out ) SPRITESTUDIO6SDK_DECLARE_ENUM_STRING_DEF( SsEffectNodeType ); //--------------------------------------------------------------- -//相互変換 SsPartType +//相互変換 SsEffectNodeType SsString __EnumToString_( SsEffectNodeType::_enum n ) { if ( n == SsEffectNodeType::invalid ) return "invalid"; @@ -366,7 +426,7 @@ void __StringToEnum_( SsString n , SsEffectNodeType::_enum& out) SPRITESTUDIO6SDK_DECLARE_ENUM_STRING_DEF( SsRenderBlendType ); //--------------------------------------------------------------- -//相互変換 SsPartType +//相互変換 SsRenderBlendType SsString __EnumToString_( SsRenderBlendType::_enum n ) { if ( n == SsRenderBlendType::invalid ) return "invalid"; @@ -460,4 +520,4 @@ void __StringToEnum_(SsString n, SsSignalParamType::_enum& out) } -} // namespace spritestudio6 +} // namespace SpriteStudio diff --git a/Common/Loader/sstypes.h b/Common/Loader/sstypes.h index a59547d3..e0941e64 100644 --- a/Common/Loader/sstypes.h +++ b/Common/Loader/sstypes.h @@ -19,7 +19,7 @@ #define SPRITESTUDIO6SDK_NOUSE_ARGUMENT(_name_) ( void )( &_name_ ); #endif -namespace spritestudio6 +namespace SpriteStudio { //=============================================================== @@ -28,7 +28,7 @@ namespace spritestudio6 //文字列の設定 typedef std::string SsString; - +typedef std::vector SsStringList; ///2次元座標を表現するためのクラスです。 @@ -45,6 +45,10 @@ struct SsPoint2 } SsPoint2() : x(0) , y(0){} + + void setX(float v) { x = v; } + void setY(float v) { y = v; } + static float distance_sq(const SsPoint2 & l, const SsPoint2 & r) { float x = l.x - r.x; @@ -203,24 +207,375 @@ typedef unsigned char u8; +class SsVector4 +{ +public: + float x; + float y; + float z; + float w; +public: + SsVector4() : x(.0), y(.0), z(.0), w(.0f) + { + + } + + SsVector4(float _x, float _y, float _z, float _w) + { + x = _x; + y = _y; + z = _z; + w = _w; + } + + SsVector4& operator*=(float factor) + { + + this->x *= factor; + this->y *= factor; + this->z *= factor; + this->w *= factor; + + + return *this; +// return SsVector4(0, 0, 0, 0); + } + + SsVector4& operator+=(const SsVector4& vector) + { + x += vector.x; + y += vector.y; + z += vector.z; + w += vector.w; + return *this; + } +}; +inline const SsVector4 operator*(const SsVector4& vector, float factor) +{ + return SsVector4(vector.x * factor, vector.y * factor, vector.z * factor, vector.w * factor); +} + +inline const SsVector4 operator+(const SsVector4& v1, const SsVector4& v2) +{ + return SsVector4(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z, v1.w + v2.w); +} + +//typedef SsPoint2 SsSizeF; + +template +class SsSizeT +{ +public: + SsSizeT() : + wd(0), + ht(0) {} + + SsSizeT(T w , T h) : + wd(w), + ht(h) {} + + + virtual ~SsSizeT() {} + + T width() const { return wd; } + T height() const { return ht; } + + void setWidth(T v) { wd = v; } + void setHeight(T v) { ht = v; } + + + bool operator ==(const SsSizeT& v) const + { + if (v.wd == this->wd && v.ht == this->ht) + { + return true; + } + return false; + } + + bool operator !=(const SsSizeT& v) const + { + return !(*this == v); + } + +private: + T wd; + T ht; +}; + + +typedef SsSizeT SsSizeF; +typedef SsSizeT SsSize; + + /// 矩形 template class SsTRect { public: - T x, y, w, h; +// T x, y, w, h; + T x1, y1, x2, y2; + + SsTRect(): x1(0), y1(0), x2(0), y2(0) {} + + SsTRect(int aleft, int atop, int awidth, int aheight) + : x1(aleft), y1(atop), x2(aleft + awidth - 1), y2(atop + aheight - 1) {} + - SsTRect(): x(0), y(0), w(0), h(0) {} - SsTRect(T ax, T ay, T aw, T ah): x(ax), y(ay), w(aw), h(ah) {} - SsTRect(const SsTRect& r): x(r.x), y(r.y), w(r.w), h(r.h) {} + SsTRect(const SsTRect& r): + x1(r.x1), y1(r.y1), x2(r.x2), y2(r.y2) {} + + SsTRect(SsPoint2 p, SsSize size) + { + x1 = p.x; + y1 = p.y; + x2 = p.x + size.width(); + y2 = p.y + size.height(); + } - bool operator ==(const SsTRect& r) const {return x == r.x && y == r.y && w == r.w && h == r.h;} + bool operator ==(const SsTRect& r) const {return x1 == r.x1 && y1 == r.y1 && x2 == r.x2 && y2 == r.y2;} bool operator !=(const SsTRect& r) const {return !(*this == r);} + + SsPoint2 size() + { + return SsPoint2((width()), height()); + } + + void setRect(T _x, T _y, T _w, T _h) + { + setX(_x); + setY(_y); + setWidth(_w); + setHeight(_h); + } + inline void setCoords(int xp1, int yp1, int xp2, int yp2) noexcept + { + x1 = xp1; + y1 = yp1; + x2 = xp2; + y2 = yp2; + } + + T x() { return x1; } + T y() { return y1; } + T left() { return x1; } + T top() { return y1; } + + T right() { return x2; } + T bottom() { return y2; } + + T width() const { return x2 - x1 + 1; } + T height() const { return y2 - y1 + 1; } + + + inline void moveLeft(T pos) + { + x2 += (pos - x1); x1 = pos; + } + + inline void moveTop(T pos) + { + y2 += (pos - y1); y1 = pos; + } + + inline void moveRight(int pos) + { + x1 += (pos - x2); + x2 = pos; + } + inline void moveBottom(int pos) + { + y1 += (pos - y2); + y2 = pos; + } + + void setX(T x) + { + x1 = x; + } + + void setY(T y) + { + y1 = y; + } + + void setWidth(T w) + { x2 = (x1 + w - 1); } + + void setHeight(T h) + { y2 = (y1 + h - 1); } + + + + private: }; typedef SsTRect SsIRect; +typedef SsTRect SsRectI; +typedef SsTRect SsRectF; + + + + +class SsMargins +{ +public: + SsMargins() noexcept + :m_left(0), m_top(0) , m_right(0) , m_bottom(0) {} + + + SsMargins(int left, int top, int right, int bottom) noexcept + { + m_left = left; + m_top = top; + m_right = right; + m_bottom = bottom; + } + + bool isNull() const noexcept + { + return (m_left == 0 && m_top == 0 && m_right == 0 && m_bottom == 0); + } + + int left() const noexcept { + return m_left; + } + int top() const noexcept + { + return m_top; + } + + int right() const noexcept + { + return m_right; + } + int bottom() const noexcept + { + return m_bottom; + } + + void setLeft(int left) noexcept + { + m_left = left; + } + void setTop(int top) noexcept + { + m_top = top; + } + + void setRight(int right) noexcept + { + m_right = right; + } + void setBottom(int bottom) noexcept + { + m_bottom = bottom; + } + + SsMargins& operator+=(const SsMargins& margins) noexcept + { + m_left += margins.m_left; + m_top += margins.m_top; + m_right += margins.m_right; + m_bottom += margins.m_bottom; + + return *this; + } + + SsMargins& operator-=(const SsMargins& margins) noexcept + { + m_left -= margins.m_left; + m_top -= margins.m_top; + m_right -= margins.m_right; + m_bottom -= margins.m_bottom; + + return *this; + } + + + SsMargins& operator+=(int v) noexcept + { + m_left += v; + m_top += v; + m_right += v; + m_bottom += v; + + return *this; + } + + SsMargins& operator-=(int v) noexcept + { + m_left -= v; + m_top -= v; + m_right -= v; + m_bottom -= v; + + return *this; + } + + SsMargins& operator*=(int v) noexcept + { + m_left *= v; + m_top *= v; + m_right *= v; + m_bottom *= v; + + return *this; + } + + SsMargins& operator/=(int v) + { + m_left /= v; + m_top /= v; + m_right /= v; + m_bottom /= v; + + return *this; + } + + SsMargins& operator*=(float v) noexcept + { + m_left *= v; + m_top *= v; + m_right *= v; + m_bottom *= v; + + return *this; + } + + + SsMargins& operator/=(float v) + { + m_left /= v; + m_top /= v; + m_right /= v; + m_bottom /= v; + + return *this; + } + + bool operator ==(const SsMargins& r) const + { + return ( + m_left == r.m_left && + m_top == r.m_top && + m_right == r.m_right && + m_bottom == r.m_bottom); + + } + bool operator !=(const SsMargins& r) const { return !(*this == r); } + + +private: + int m_left; + int m_top; + int m_right; + int m_bottom; + +}; + ///カラー値を定義するテンプレートクラスです。 @@ -233,7 +588,7 @@ class SsTColor SsTColor(): r(0), g(0), b(0), a(0) {} SsTColor(T ar, T ag, T ab, T aa): r(ar), g(ag), b(ab), a(aa) {} SsTColor(const SsTColor& s): r(s.r), g(s.g), b(s.b), a(s.a) {} - + SsTColor(u32 color) { fromARGB(color); } void fromARGB(u32 c); void fromBGRA(u32 c); @@ -364,7 +719,10 @@ class SsCurve bool syncStartEnd; ///< [編集用パラメータ]カーブエディタでの編集時に始点・終点ハンドルを同期して動かすか? - SsCurve() : startTime(0.f), startValue(0.f), endTime(0.f), endValue(0.f), startKeyTime(0.f), endKeyTime(0.f){} + SsCurve() : startTime(0.f), startValue(0.f), endTime(0.f), endValue(0.f), startKeyTime(0.f), endKeyTime(0.f) + , syncStartEnd(0) + + {} ~SsCurve(){} }; @@ -392,18 +750,23 @@ namespace SsPartType enum _enum { invalid = -1, - null, ///< null。領域を持たずSRT情報のみ。ただし円形の当たり判定は設定可能。 - normal, ///< 通常パーツ。領域を持つ。画像は無くてもいい。 - text, ///< テキスト(予約 未実装) - instance, ///< インスタンス。他アニメ、パーツへの参照。シーン編集モードの代替になるもの - armature, ///< ボーンパーツ - effect, ///<エフェクト - mesh, ///< メッシュパーツ - movenode, ///< 動作起点 - constraint, ///<コンストレイント - mask, ///< マスク - joint, ///< メッシュとボーンの関連付けパーツ - bonepoint, ///< ボーンポイント + null, ///< null。領域を持たずSRT情報のみ。ただし円形の当たり判定は設定可能。 + normal, ///< 通常パーツ。領域を持つ。画像は無くてもいい。 + shape, ///< シェイプ + text, ///< テキスト + nines, ///< 9スライス + instance, ///< インスタンス。他アニメ、パーツへの参照。シーン編集モードの代替になるもの + armature, ///< ボーン (パーツとパーツの親子関係ではなく + effect, ///< パーティクルモード + mesh, ///< メッシュパーツ + movenode, ///< 動作起点 + constraint, + mask, + joint, ///< メッシュとボーンの関連付けパーツ + bonepoint, ///< ボーンポイント + transform_constraint, ///トランスフォームコンストレイント + camera, + audio, num }; @@ -490,6 +853,30 @@ namespace SsInterpolationType bezier, ///< ベジェ acceleration, ///< 加速度 deceleration, ///< 減速度 + + easeIn, + easeOut, + easeInOut, + + easeExponentialIn, + easeExponentialOut, + easeExponentialInOut, + + easeSineIn, + easeSineOut, + easeSineInOut, + + easeElasticIn, + easeElasticOut, + easeElasticInOut, + + easeBounceIn, + easeBounceOut, + easeBounceInOut, + + easeBackIn, + easeBackOut, + easeBackInOut, num, }; }; @@ -574,6 +961,8 @@ namespace SsAttributeKind instance, ///< [IPRM]インスタンスパーツパラメータ effect, ///< [EFCT]エフェクトパラメータ deform, ///< [DEFM]デフォーム用パラメータ + audio, ///< sound用パラメータ + texchange, /// < テクスチャー変更 num, }; }; @@ -583,6 +972,7 @@ SPRITESTUDIO6SDK_DECLARE_ENUM_STRING_DEF(SsAttributeKind); namespace SsKeyValueType { +/* enum _enum { _unkown = -1, @@ -596,13 +986,29 @@ namespace SsKeyValueType _userData, _instance, }; +*/ + enum _enum{ + _unkown = -1, + boolean, ///< u8 + integer, ///< s32 + decimal, ///< f32 + cell, ///< セル + partsColor, ///< パーツカラー + color, ///< カラーブレンド + shader, ///< シェーダー + vertex, ///< 頂点変形 + user, ///< ユーザー + signal, ///< シグナル + instance, ///< インスタンス + effect, ///< エフェクト + deform, ///< デフォーム + audio, ///< audio + texchange, ///< テクスチャ変更 + num + }; }; - - - - ///カラーブレンドキーのカラー値 struct SsColorBlendValue { @@ -806,6 +1212,7 @@ class SsUserDataAnime SsString string; ///< 文字列 SsUserDataAnime() : + integer(0), useInteger(false), usePoint(false), useRect(false), @@ -904,6 +1311,7 @@ class SsInstanceAttr }; + //インスタンスアトリビュートのループフラグ enum { INSTANCE_LOOP_FLAG_INFINITY = 1 << 0, @@ -991,6 +1399,123 @@ class SsDeformAttr }; -} // namespace spritestudio6 + +//add SS7.1 追加アトリビュート + +class SsAudioAttr +{ +private: + +public: + int SoundListID; + SsString SoundName; + int LoopNum; + + SsAudioAttr() + : SoundListID(0), + SoundName(""), + LoopNum(1) + { + } + + SsAudioAttr(const SsAudioAttr& r) + : SoundListID(r.SoundListID) + , SoundName(r.SoundName) + , LoopNum(r.LoopNum) + { + } +}; + +class SsTexChangeAttr +{ +private: + +public: + SsString TextureName; + //SsImage* image; + + SsTexChangeAttr() : TextureName("") + { + } +}; + + + +class SsAnchorButton +{ +public: + enum Anchor + { + NO = 0xFF, + + LT = 0x00, + LC = 0x01, + LB = 0x02, + CT = 0x10, + CC = 0x11, + CB = 0x12, + RT = 0x20, + RC = 0x21, + RB = 0x22, + }; + + enum Alignment + { + AlignLeft = 0x0001, + AlignRight = 0x0002, + AlignTop = 0x0020, + AlignBottom = 0x0040, + AlignVCenter = 0x0080, + AlignHCenter = 0x0004, + }; + + static inline int toAlignment(Anchor eAnchor) + { + int flag = AlignLeft | AlignTop; + + switch (eAnchor) { + case LT: + flag = AlignLeft | AlignTop; + break; + case LC: + flag = AlignLeft | AlignVCenter; + break; + case LB: + flag = AlignLeft | AlignBottom; + break; + case CT: + flag = AlignHCenter | AlignTop; + break; + case CC: + flag = AlignHCenter | AlignVCenter; + break; + case CB: + flag = AlignHCenter | AlignBottom; + break; + case RT: + flag = AlignRight | AlignTop; + break; + case RC: + flag = AlignRight | AlignVCenter; + break; + case RB: + flag = AlignRight | AlignBottom; + break; + default: + break; + } + + return flag; + } +}; + + +// add SS7.1ここまで + +} // namespace SpriteStudio + + + + #endif diff --git a/Common/Loader/ssvalue.cpp b/Common/Loader/ssvalue.cpp index d18c5fec..485813cb 100644 --- a/Common/Loader/ssvalue.cpp +++ b/Common/Loader/ssvalue.cpp @@ -4,7 +4,7 @@ #include "sscharconverter.h" -namespace spritestudio6 +namespace SpriteStudio { //SsValue用のシリアライザ @@ -78,4 +78,4 @@ void SsValueSeriarizer( ISsXmlArchiver* ar , SsValue& v , const std::string key) } -} // namespace spritestudio6 +} // namespace SpriteStudio diff --git a/Common/Loader/ssvalue.h b/Common/Loader/ssvalue.h index db2abc3f..0156f300 100644 --- a/Common/Loader/ssvalue.h +++ b/Common/Loader/ssvalue.h @@ -7,12 +7,12 @@ #include #include -namespace spritestudio6 +namespace SpriteStudio { class SsValue; -typedef wchar_t SsChar; +//typedef wchar_t SsChar; typedef std::vector SsArray; typedef std::map SsHash; @@ -51,15 +51,40 @@ class SsValue{ bool _bool_temp; - SsValue() : type(unkown) , _str(0){} - - explicit SsValue(bool b ) : type(boolean_type) { _bool = b; } - explicit SsValue(int n, char* org = 0) : type(int_type) { + SsValue() : + type(unkown) , + _str(0), + _int_temp(0), + _float_temp(0), + _bool_temp(0) + {} + + explicit SsValue(bool b ) : + type(boolean_type) , + _str(0), + _int_temp(0), + _float_temp(0), + _bool_temp(0) + { _bool = b; } + + + explicit SsValue(int n, char* org = 0) : + type(int_type), + _str(0), + _int_temp(0), + _float_temp(0), + _bool_temp(0) + { _int = n; if (org) org_txt = SsString(org); } - explicit SsValue(float n, char* org = 0) : type(float_type) + explicit SsValue(float n, char* org = 0) : + type(float_type), + _str(0), + _int_temp(0), + _float_temp(0), + _bool_temp(0) { _float = n; if (org) @@ -334,6 +359,6 @@ inline static SsValue SsValueSeriarizer__MakeValue( const char* v ) -} // namespace spritestudio6 +} // namespace SpriteStudio #endif diff --git a/Common/Loader/text/ssfontdesc.cpp b/Common/Loader/text/ssfontdesc.cpp new file mode 100644 index 00000000..1f790382 --- /dev/null +++ b/Common/Loader/text/ssfontdesc.cpp @@ -0,0 +1,211 @@ +/*! + * \file ssfontdesc.cpp + * \author CRI Middleware Co., Ltd. +*/ +#include "ssfontdesc.h" +namespace SpriteStudio +{ + const bool SsFontDesc::DEFAULT_BITMAP = false; //!< デフォルトビットマップ + const SsString SsFontDesc::DEFAULT_FAMILY = "Arial"; //!< デフォルトファミリ + const SsString SsFontDesc::DEFAULT_CHAR_MAP = ""; //!< デフォルトキャラマップ + const int SsFontDesc::DEFAULT_SIZE = 16; //!< デフォルトサイズ + const float SsFontDesc::DEFAULT_SPACE = 0.0f; //!< デフォルトスペース + const SsAnchorButton::Anchor SsFontDesc::DEFAULT_ANCHOR = SsAnchorButton::LT; //!< デフォルトアンカー + + //! コンストラクタ + SsFontDesc::SsFontDesc() + { + setBitmap(DEFAULT_BITMAP); + setFamily(DEFAULT_FAMILY); + setCharMap(DEFAULT_CHAR_MAP); + setSize(DEFAULT_SIZE); + setSpace(DEFAULT_SPACE); + setAnchor(DEFAULT_ANCHOR); + + m_bUpdate = true; + } + + //! デストラクタ + SsFontDesc::~SsFontDesc() + { + } + + SsFontDesc& SsFontDesc::operator =(const SsFontDesc& right) + { + setBitmap(right.isBitmap()); + setFamily(right.getFamily()); + setCharMap(right.getCharMap()); + setSize(right.getSize()); + setSpace(right.getSpace()); + setAnchor(right.getAnchor()); + + return *this; + } + + bool SsFontDesc::operator ==(const SsFontDesc& right) const + { + if ( + (isBitmap() == right.isBitmap()) && + (getFamily() == right.getFamily()) && + (getCharMap() == right.getCharMap()) && + (getSize() == right.getSize()) && + (getSpace() == right.getSpace()) && + (getAnchor() == right.getAnchor()) + ) { + return true; + } + + return false; + } + + bool SsFontDesc::operator !=(const SsFontDesc& right) const + { + return !(*this == right); + } + + bool SsFontDesc::operator <(const SsFontDesc& right) const + { + if (isBitmap() < right.isBitmap()) return true; + if (isBitmap() > right.isBitmap()) return false; + + if (getFamily() < right.getFamily()) return true; + if (getFamily() > right.getFamily()) return false; + + if (getCharMap() < right.getCharMap()) return true; + if (getCharMap() > right.getCharMap()) return false; + + if (getSize() < right.getSize()) return true; + if (getSize() > right.getSize()) return false; + + if (getSpace() < right.getSpace()) return true; + if (getSpace() > right.getSpace()) return false; + + if (getAnchor() < right.getAnchor()) return true; + if (getAnchor() > right.getAnchor()) return false; + + return false; + } + + bool SsFontDesc::operator >(const SsFontDesc& right) const + { + if (isBitmap() > right.isBitmap()) return true; + if (isBitmap() < right.isBitmap()) return false; + + if (getFamily() > right.getFamily()) return true; + if (getFamily() < right.getFamily()) return false; + + if (getCharMap() > right.getCharMap()) return true; + if (getCharMap() < right.getCharMap()) return false; + + if (getSize() > right.getSize()) return true; + if (getSize() < right.getSize()) return false; + + if (getSpace() > right.getSpace()) return true; + if (getSpace() < right.getSpace()) return false; + + if (getAnchor() > right.getAnchor()) return true; + if (getAnchor() < right.getAnchor()) return false; + + return false; + } + + //! ビットマップを設定 + void SsFontDesc::setBitmap(bool bBitmap) + { + if (m_bBitmap != bBitmap) { + m_bBitmap = bBitmap; + m_bUpdate = true; + } + } + + //! ファミリを設定 + void SsFontDesc::setFamily(const SsString& strFamily) + { + if (m_strFamily != strFamily) { + m_strFamily = strFamily; + m_bUpdate = true; + } + } + + //! キャラマップを設定 + void SsFontDesc::setCharMap(const SsString& strCharMap) + { + if (m_strCharMap != strCharMap) { + m_strCharMap = strCharMap; + m_bUpdate = true; + } + } + + //! サイズを設定 + void SsFontDesc::setSize(int iSize) + { + if (m_iSize != iSize) { + m_iSize = iSize; + m_bUpdate = true; + } + } + + //! スペースを設定 + void SsFontDesc::setSpace(float fSpace) + { + if (m_fSpace != fSpace) { + m_fSpace = fSpace; + m_bUpdate = true; + } + } + + //! アンカーを設定 + void SsFontDesc::setAnchor(SsAnchorButton::Anchor eAnchor) + { + if (m_eAnchor != eAnchor) { + m_eAnchor = eAnchor; + m_bUpdate = true; + } + } + + //! ビットマップを取得 + bool SsFontDesc::isBitmap() const + { + return m_bBitmap; + } + + //! ファミリを取得 + SsString SsFontDesc::getFamily() const + { + return m_strFamily; + } + + //! キャラマップを取得 + SsString SsFontDesc::getCharMap() const + { + return m_strCharMap; + } + + //! サイズを取得 + int SsFontDesc::getSize() const + { + return m_iSize; + } + + //! スペースを取得 + float SsFontDesc::getSpace() const + { + return m_fSpace; + } + + //! アンカーを取得 + SsAnchorButton::Anchor SsFontDesc::getAnchor() const + { + return m_eAnchor; + } + + //! 更新が必要かどうかを取得 + bool SsFontDesc::takeUpdate() + { + bool bUpdate = m_bUpdate; + + m_bUpdate = false; + + return bUpdate; + } +}; diff --git a/Common/Loader/text/ssfontdesc.h b/Common/Loader/text/ssfontdesc.h new file mode 100644 index 00000000..831c7887 --- /dev/null +++ b/Common/Loader/text/ssfontdesc.h @@ -0,0 +1,130 @@ +/*! + * \file ssfontdesc.h + * \author CRI Middleware Co., Ltd. +*/ +#ifndef SSFONTDESC_H +#define SSFONTDESC_H + +#include "../sstypes.h" + +namespace SpriteStudio +{ + + + /*! + * \class SsFontDesc + * \brief フォント設定 + */ + class SsFontDesc + { + public: + static const bool DEFAULT_BITMAP; //!< デフォルトビットマップ + static const SsString DEFAULT_FAMILY; //!< デフォルトファミリ + static const SsString DEFAULT_CHAR_MAP; //!< デフォルトキャラマップ + static const int DEFAULT_SIZE; //!< デフォルトサイズ + static const float DEFAULT_SPACE; //!< デフォルトスペース + static const SsAnchorButton::Anchor DEFAULT_ANCHOR; //!< デフォルトアンカー + + //! コンストラクタ + SsFontDesc(); + + //! デストラクタ + ~SsFontDesc(); + + SsFontDesc& operator =(const SsFontDesc& right); + bool operator ==(const SsFontDesc& right) const; + bool operator !=(const SsFontDesc& right) const; + bool operator <(const SsFontDesc& right) const; + bool operator >(const SsFontDesc& right) const; + + //! ビットマップを設定 + /*! + * \param bBitmap ビットマップ + */ + void setBitmap(bool bBitmap); + + //! ファミリを設定 + /*! + * \param strFamily ファミリ + */ + void setFamily(const SsString& strFamily); + + //! キャラマップを設定 + /*! + * \param strCharMap キャラマップ + */ + void setCharMap(const SsString& strCharMap); + + //! サイズを設定 + /*! + * \param iSize サイズ + */ + void setSize(int iSize); + + //! スペースを設定 + /*! + * \param fSpace スペース + */ + void setSpace(float fSpace); + + //! アンカーを設定 + /*! + * \param eAnchor アンカー + */ + void setAnchor(SsAnchorButton::Anchor eAnchor); + + //! ビットマップを取得 + /*! + * \return ビットマップ + */ + bool isBitmap() const; + + //! ファミリを取得 + /*! + * \return ファミリ + */ + SsString getFamily() const; + + //! キャラマップを取得 + /*! + * \return キャラマップ + */ + SsString getCharMap() const; + + //! サイズを取得 + /*! + * \return サイズ + */ + int getSize() const; + + //! スペースを取得 + /*! + * \return スペース + */ + float getSpace() const; + + //! アンカーを取得 + /*! + * \return アンカー + */ + SsAnchorButton::Anchor getAnchor() const; + + //! 更新が必要かどうかを取得 + /*! + * \return 更新が必要な場合に true + */ + bool takeUpdate(); + + private: + bool m_bBitmap; ///< ビットマップ + SsString m_strFamily; ///< ファミリ + SsString m_strCharMap; ///< キャラマップ + int m_iSize; ///< サイズ + float m_fSpace; ///< スペース + SsAnchorButton::Anchor m_eAnchor; ///< アンカー + + bool m_bUpdate; ///< 更新が必要かどうか + }; + +}; +#endif // SSFONTDESC_H diff --git a/cmake/initialize.cmake b/cmake/initialize.cmake index 7bb610bd..9ab1c97d 100644 --- a/cmake/initialize.cmake +++ b/cmake/initialize.cmake @@ -27,6 +27,7 @@ macro(PREPARE) if((CMAKE_BUILD_TYPE STREQUAL "Release") AND (NOT CMAKE_OSX_ARCHITECTURES)) set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64" CACHE STRING "" FORCE) endif() + set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15") elseif(CMAKE_COMPILER_IS_GNUCXX) add_definitions(-std=gnu++14) endif()