From 2aed8fb0db3b220126ed34a655e85ebcdb336ff4 Mon Sep 17 00:00:00 2001 From: ito Date: Thu, 13 May 2021 11:56:06 +0900 Subject: [PATCH 1/2] [Beta version] Update to Cubism 4 SDK for Native R3 Beta1 --- CHANGELOG.md | 14 + LICENSE.md | 7 + README.md | 6 +- src/Math/CubismMath.cpp | 90 + src/Math/CubismMath.hpp | 26 + src/Math/CubismModelMatrix.cpp | 2 +- src/Motion/CubismMotion.cpp | 117 +- src/Motion/CubismMotionJson.cpp | 11 + src/Motion/CubismMotionJson.hpp | 20 + src/Rendering/CMakeLists.txt | 4 +- src/Rendering/Cocos2d/CMakeLists.txt | 9 + .../Cocos2d/CubismCommandBuffer_Cocos2dx.cpp | 262 +++ .../Cocos2d/CubismCommandBuffer_Cocos2dx.hpp | 162 ++ .../CubismOffscreenSurface_Cocos2dx.cpp | 173 ++ .../CubismOffscreenSurface_Cocos2dx.hpp | 127 ++ .../Cocos2d/CubismRenderer_Cocos2dx.cpp | 1838 +++++++++++++++++ .../Cocos2d/CubismRenderer_Cocos2dx.hpp | 555 +++++ src/Rendering/D3D11/CubismRenderer_D3D11.cpp | 96 +- src/Rendering/D3D11/CubismRenderer_D3D11.hpp | 23 +- src/Rendering/D3D9/CubismRenderState_D3D9.cpp | 78 +- src/Rendering/D3D9/CubismRenderState_D3D9.hpp | 41 +- src/Rendering/D3D9/CubismRenderer_D3D9.cpp | 109 +- src/Rendering/D3D9/CubismRenderer_D3D9.hpp | 19 +- .../OpenGL/CubismRenderer_OpenGLES2.cpp | 90 +- .../OpenGL/CubismRenderer_OpenGLES2.hpp | 18 +- 25 files changed, 3743 insertions(+), 154 deletions(-) create mode 100644 src/Rendering/Cocos2d/CMakeLists.txt create mode 100644 src/Rendering/Cocos2d/CubismCommandBuffer_Cocos2dx.cpp create mode 100644 src/Rendering/Cocos2d/CubismCommandBuffer_Cocos2dx.hpp create mode 100644 src/Rendering/Cocos2d/CubismOffscreenSurface_Cocos2dx.cpp create mode 100644 src/Rendering/Cocos2d/CubismOffscreenSurface_Cocos2dx.hpp create mode 100644 src/Rendering/Cocos2d/CubismRenderer_Cocos2dx.cpp create mode 100644 src/Rendering/Cocos2d/CubismRenderer_Cocos2dx.hpp diff --git a/CHANGELOG.md b/CHANGELOG.md index a21aa8f..19005f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,19 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). +## [4-r.3-beta.1] - 2021-05-13 + +### Added + +* Add a Renderer for Cocos2d-x v4.0. +* Implement a function to get the correct value when the time axis of the Bezier handle cannot be linear. +* Add an argument to the function `SetClippingMaskBufferSize` to set the height and width of the clipping mask buffer. + +### Changed + +* Improve the quality of Clipping Mask on high precision masking. + + ## [4-r.2] - 2021-02-17 ### Added @@ -85,6 +98,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). * Fix invalid expressions of `CubismCdiJson`. +[4-r.3-beta.1]: https://github.com/Live2D/CubismNativeFramework/compare/4-r.2...4-r.3-beta.1 [4-r.2]: https://github.com/Live2D/CubismNativeFramework/compare/4-r.1...4-r.2 [4-r.1]: https://github.com/Live2D/CubismNativeFramework/compare/4-beta.2...4-r.1 [4-beta.2]: https://github.com/Live2D/CubismNativeFramework/compare/4-beta.1...4-beta.2 diff --git a/LICENSE.md b/LICENSE.md index 64c2ca6..3c7bb93 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -6,6 +6,7 @@ Cubism Native Framework is included in Live2D Cubism Components. Cubism Native Framework は Live2D Cubism Components に含まれます。 +Cubism Native Framework 包括在 Live2D Cubism Components 中。 ## Cubism SDK Release License @@ -17,6 +18,10 @@ Cubism Native Framework は Live2D Cubism Components に含まれます。 * [Cubism SDK リリースライセンス](https://www.live2d.com/ja/download/cubism-sdk/release-license/) +如果您的企业在最近一个会计年度的销售额达到或超过1000万日元,您必须得到Cubism SDK的出版授权许可(出版许可协议)。 + +* [Cubism SDK发行许可证](https://www.live2d.com/zh-CHS/download/cubism-sdk/release-license/) + ## Live2D Open Software License @@ -24,6 +29,7 @@ Live2D Cubism Components is available under Live2D Open Software License. * [Live2D Open Software License Agreement](https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html) * [Live2D Open Software 使用許諾契約書](https://www.live2d.com/eula/live2d-open-software-license-agreement_jp.html) +* [Live2D Open Software 使用授权协议](https://www.live2d.com/eula/live2d-open-software-license-agreement_cn.html) ## Live2D Proprietary Software License @@ -32,6 +38,7 @@ Live2D Cubism Core is available under Live2D Proprietary Software License. * [Live2D Proprietary Software License Agreement](https://www.live2d.com/eula/live2d-proprietary-software-license-agreement_en.html) * [Live2D Proprietary Software 使用許諾契約書](https://www.live2d.com/eula/live2d-proprietary-software-license-agreement_jp.html) +* [Live2D Proprietary Software 使用授权协议](https://www.live2d.com/eula/live2d-proprietary-software-license-agreement_cn.html) --- diff --git a/README.md b/README.md index e1fb571..7d2d742 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,14 @@ -# Cubism Native Framework +# \[Beta Version\] Cubism Native Framework Live2D Cubism 4 Editor で出力したモデルをアプリケーションで利用するためのフレームワークです。 モデルを表示、操作するための各種機能を提供します。 モデルをロードするには Cubism Core ライブラリと組み合わせて使用します。 +**本 SDK は、 Beta バージョンとなります。先行して新機能を取り込んでいるため、不安定な挙動を示す場合がございます。安定した製品をお求めの方は、公式サイトから配布されている正式版のパッケージ又は `develop` `master` ブランチをご利用ください。** + +**\[Beta Version\] の SDK の不具合、各種ご意見等に関しましては、 Live2D コミュニティ にてご連絡ください。直接のコードに対する指摘、修正等は、直接 Pull requests としてご投稿ください。** + ## ライセンス diff --git a/src/Math/CubismMath.cpp b/src/Math/CubismMath.cpp index 513fc2c..edcf138 100644 --- a/src/Math/CubismMath.cpp +++ b/src/Math/CubismMath.cpp @@ -10,6 +10,7 @@ namespace Live2D {namespace Cubism {namespace Framework { const csmFloat32 CubismMath::Pi = 3.1415926535897932384626433832795f; +const csmFloat32 CubismMath::Epsilon = 0.00001f; csmFloat32 CubismMath::DegreesToRadian(csmFloat32 degrees) { @@ -71,4 +72,93 @@ CubismVector2 CubismMath::RadianToDirection(csmFloat32 totalAngle) return ret; } +csmFloat32 CubismMath::QuadraticEquation(csmFloat32 a, csmFloat32 b, csmFloat32 c) +{ + if (CubismMath::AbsF(a) < CubismMath::Epsilon) + { + if (CubismMath::AbsF(b) < CubismMath::Epsilon) + { + return -c; + } + return -c / b; + } + + return -(b + CubismMath::SqrtF(b * b - 4.0f * a * c)) / (2.0f * a); +} + +csmFloat32 CubismMath::CardanoAlgorithmForBezier(csmFloat32 a, csmFloat32 b, csmFloat32 c, csmFloat32 d) +{ + if ( CubismMath::AbsF( a ) < CubismMath::Epsilon ) + { + return CubismMath::RangeF( QuadraticEquation(b, c, d), 0.0f, 1.0f); + } + + csmFloat32 ba = b / a; + csmFloat32 ca = c / a; + csmFloat32 da = d / a; + + + csmFloat32 p = (3.0f * ca - ba*ba) / 3.0f; + csmFloat32 p3 = p / 3.0f; + csmFloat32 q = (2.0f * ba*ba*ba - 9.0f * ba*ca + 27.0f * da) / 27.0f; + csmFloat32 q2 = q / 2.0f; + csmFloat32 discriminant = q2*q2 + p3*p3*p3; + + const csmFloat32 center = 0.5f; + const csmFloat32 threshold = center + 0.01f; + + if (discriminant < 0.0f) { + csmFloat32 mp3 = -p / 3.0f; + csmFloat32 mp33 = mp3*mp3*mp3; + csmFloat32 r = CubismMath::SqrtF(mp33); + csmFloat32 t = -q / (2.0f * r); + csmFloat32 cosphi = RangeF(t, -1.0f, 1.0f); + csmFloat32 phi = acos(cosphi); + csmFloat32 crtr = cbrt(r); + csmFloat32 t1 = 2.0f * crtr; + + csmFloat32 root1 = t1 * CubismMath::CosF(phi / 3.0f) - ba / 3.0f; + if ( abs( root1 - center) < threshold) + { + return RangeF( root1, 0.0f, 1.0f); + } + + csmFloat32 root2 = t1 * CubismMath::CosF((phi + 2.0f * CubismMath::Pi) / 3.0f) - ba / 3.0f; + if (abs(root2 - center) < threshold) + { + return RangeF(root2, 0.0f, 1.0f); + } + + csmFloat32 root3 = t1 * CubismMath::CosF((phi + 4.0f * CubismMath::Pi) / 3.0f) - ba / 3.0f; + return RangeF(root3, 0.0f, 1.0f); + } + + if (discriminant == 0.0f) { + csmFloat32 u1; + if (q2 < 0.0f) + { + u1 = cbrt(-q2); + } + else + { + u1 = -cbrt(q2); + } + + csmFloat32 root1 = 2.0f * u1 - ba / 3.0f; + if (abs(root1 - center) < threshold) + { + return RangeF(root1, 0.0f, 1.0f); + } + + csmFloat32 root2 = -u1 - ba / 3.0f; + return RangeF(root2, 0.0f, 1.0f); + } + + csmFloat32 sd = CubismMath::SqrtF(discriminant); + csmFloat32 u1 = cbrt(sd - q2); + csmFloat32 v1 = cbrt(sd + q2); + csmFloat32 root1 = u1 - v1 - ba / 3.0f; + return RangeF(root1, 0.0f, 1.0f); +} + }}} diff --git a/src/Math/CubismMath.hpp b/src/Math/CubismMath.hpp index ca43e1a..186c52b 100644 --- a/src/Math/CubismMath.hpp +++ b/src/Math/CubismMath.hpp @@ -22,6 +22,7 @@ class CubismMath { public: static const csmFloat32 Pi; + static const csmFloat32 Epsilon; /** *@brief 第一引数の値を最小値と最大値の範囲に収めた値を返す @@ -163,6 +164,31 @@ class CubismMath */ static CubismVector2 RadianToDirection(csmFloat32 totalAngle); + /** + * @brief 三次方程式の三次項の係数が0になったときに補欠的に二次方程式の解をもとめる。 + * a * x^2 + b * x + c = 0 + * + * @param a -> 二次項の係数値 + * @param b -> 一次項の係数値 + * @param c -> 定数項の値 + * @return 二次方程式の解 + */ + static csmFloat32 QuadraticEquation(csmFloat32 a, csmFloat32 b, csmFloat32 c); + + /** + * @brief カルダノの公式によってベジェのt値に該当する3次方程式の解を求める。 + * 重解になったときには0.0~1.0の値になる解を返す。 + * + * a * x^3 + b * x^2 + c * x + d = 0 + * + * @param a -> 三次項の係数値 + * @param b -> 二次項の係数値 + * @param c -> 一次項の係数値 + * @param d -> 定数項の値 + * @return 0.0~1.0の間にある解 + */ + static csmFloat32 CardanoAlgorithmForBezier(csmFloat32 a, csmFloat32 b, csmFloat32 c, csmFloat32 d); + private: /** *@brief privateコンストラクタ diff --git a/src/Math/CubismModelMatrix.cpp b/src/Math/CubismModelMatrix.cpp index 3d878e1..b437312 100644 --- a/src/Math/CubismModelMatrix.cpp +++ b/src/Math/CubismModelMatrix.cpp @@ -1,4 +1,4 @@ -/** +/** * Copyright(c) Live2D Inc. All rights reserved. * * Use of this source code is governed by the Live2D Open Software license diff --git a/src/Motion/CubismMotion.cpp b/src/Motion/CubismMotion.cpp index 912f829..6f73fed 100644 --- a/src/Motion/CubismMotion.cpp +++ b/src/Motion/CubismMotion.cpp @@ -26,6 +26,11 @@ const csmChar* TargetNameModel = "Model"; const csmChar* TargetNameParameter = "Parameter"; const csmChar* TargetNamePartOpacity = "PartOpacity"; +/** +* Cubism SDK R2 以前のモーションを再現させるなら true 、アニメータのモーションを正しく再現するなら false 。 +*/ +const csmBool UseOldBeziersCurveMotion = false; + CubismMotionPoint LerpPoints(const CubismMotionPoint a, const CubismMotionPoint b, const csmFloat32 t) { CubismMotionPoint result; @@ -67,6 +72,108 @@ csmFloat32 BezierEvaluate(const CubismMotionPoint* points, const csmFloat32 time return LerpPoints(p012, p123, t).Value; } +csmFloat32 BezierEvaluateBinarySearch(const CubismMotionPoint* points, const csmFloat32 time) +{ + const csmFloat32 x_error = 0.01f; + + const csmFloat32 x = time; + csmFloat32 x1 = points[0].Time; + csmFloat32 x2 = points[3].Time; + csmFloat32 cx1 = points[1].Time; + csmFloat32 cx2 = points[2].Time; + + csmFloat32 ta = 0.0f; + csmFloat32 tb = 1.0f; + csmFloat32 t = 0.0f; + int i = 0; + + for (csmBool var33 = true; i < 20; ++i) { + if (x < x1 + x_error) { + t = ta; + break; + } + + if (x2 - x_error < x) { + t = tb; + break; + } + + csmFloat32 centerx = (cx1 + cx2) * 0.5f; + cx1 = (x1 + cx1) * 0.5f; + cx2 = (x2 + cx2) * 0.5f; + csmFloat32 ctrlx12 = (cx1 + centerx) * 0.5f; + csmFloat32 ctrlx21 = (cx2 + centerx) * 0.5f; + centerx = (ctrlx12 + ctrlx21) * 0.5f; + if (x < centerx) { + tb = (ta + tb) * 0.5f; + if (centerx - x_error < x) { + t = tb; + break; + } + + x2 = centerx; + cx2 = ctrlx12; + } + else { + ta = (ta + tb) * 0.5f; + if (x < centerx + x_error) { + t = ta; + break; + } + + x1 = centerx; + cx1 = ctrlx21; + } + } + + if (i == 20) { + t = (ta + tb) * 0.5f; + } + + if (t < 0.0f) + { + t = 0.0f; + } + if (t > 1.0f) + { + t = 1.0f; + } + + const CubismMotionPoint p01 = LerpPoints(points[0], points[1], t); + const CubismMotionPoint p12 = LerpPoints(points[1], points[2], t); + const CubismMotionPoint p23 = LerpPoints(points[2], points[3], t); + + const CubismMotionPoint p012 = LerpPoints(p01, p12, t); + const CubismMotionPoint p123 = LerpPoints(p12, p23, t); + + return LerpPoints(p012, p123, t).Value; +} + +csmFloat32 BezierEvaluateCardanoInterpretation(const CubismMotionPoint* points, const csmFloat32 time) +{ + const csmFloat32 x = time; + csmFloat32 x1 = points[0].Time; + csmFloat32 x2 = points[3].Time; + csmFloat32 cx1 = points[1].Time; + csmFloat32 cx2 = points[2].Time; + + csmFloat32 a = x2 - 3.0f * cx2 + 3.0f * cx1 - x1; + csmFloat32 b = 3.0f * cx2 - 6.0f * cx1 + 3.0f * x1; + csmFloat32 c = 3.0f * cx1 - 3.0f * x1; + csmFloat32 d = x1 - x; + + csmFloat32 t = CubismMath::CardanoAlgorithmForBezier(a, b, c, d); + + const CubismMotionPoint p01 = LerpPoints(points[0], points[1], t); + const CubismMotionPoint p12 = LerpPoints(points[1], points[2], t); + const CubismMotionPoint p23 = LerpPoints(points[2], points[3], t); + + const CubismMotionPoint p012 = LerpPoints(p01, p12, t); + const CubismMotionPoint p123 = LerpPoints(p12, p23, t); + + return LerpPoints(p012, p123, t).Value; +} + csmFloat32 SteppedEvaluate(const CubismMotionPoint* points, const csmFloat32 time) { return points[0].Value; @@ -409,6 +516,8 @@ void CubismMotion::Parse(const csmByte* motionJson, const csmSizeInt size) _motionData->Fps = json->GetMotionFps(); _motionData->EventCount = json->GetEventCount(); + csmBool areBeziersRestructed = json->GetEvaluationOptionFlag( EvaluationOptionFlag_AreBeziersRistricted ); + if (json->IsExistMotionFadeInTime()) { _fadeInSeconds = (json->GetMotionFadeInTime() < 0.0f) @@ -504,7 +613,13 @@ void CubismMotion::Parse(const csmByte* motionJson, const csmSizeInt size) } case CubismMotionSegmentType_Bezier: { _motionData->Segments[totalSegmentCount].SegmentType = CubismMotionSegmentType_Bezier; - _motionData->Segments[totalSegmentCount].Evaluate = BezierEvaluate; + if (areBeziersRestructed || UseOldBeziersCurveMotion) { + _motionData->Segments[totalSegmentCount].Evaluate = BezierEvaluate; + } + else + { + _motionData->Segments[totalSegmentCount].Evaluate = BezierEvaluateCardanoInterpretation; + } _motionData->Points[totalPointCount].Time = json->GetMotionCurveSegment(curveCount, (segmentPosition + 1)); _motionData->Points[totalPointCount].Value = json->GetMotionCurveSegment(curveCount, (segmentPosition + 2)); diff --git a/src/Motion/CubismMotionJson.cpp b/src/Motion/CubismMotionJson.cpp index 60753bc..362b1ea 100644 --- a/src/Motion/CubismMotionJson.cpp +++ b/src/Motion/CubismMotionJson.cpp @@ -16,6 +16,7 @@ namespace { const csmChar* Meta = "Meta"; const csmChar* Duration = "Duration"; const csmChar* Loop = "Loop"; +const csmChar* AreBeziersRestricted = "AreBeziersRestricted"; const csmChar* CurveCount = "CurveCount"; const csmChar* Fps = "Fps"; const csmChar* TotalSegmentCount = "TotalSegmentCount"; @@ -53,6 +54,16 @@ csmBool CubismMotionJson::IsMotionLoop() const return _json->GetRoot()[Meta][Loop].ToBoolean(); } +csmBool CubismMotionJson::GetEvaluationOptionFlag(const csmInt32 flagType) const +{ + if (EvaluationOptionFlag_AreBeziersRistricted == flagType) + { + return _json->GetRoot()[Meta][AreBeziersRestricted].ToBoolean(); + } + + return false; +} + csmInt32 CubismMotionJson::GetMotionCurveCount() const { return _json->GetRoot()[Meta][CurveCount].ToInt(); diff --git a/src/Motion/CubismMotionJson.hpp b/src/Motion/CubismMotionJson.hpp index 915e746..8ced59f 100644 --- a/src/Motion/CubismMotionJson.hpp +++ b/src/Motion/CubismMotionJson.hpp @@ -13,6 +13,14 @@ namespace Live2D { namespace Cubism { namespace Framework { +/** +* @brief ベジェカーブの解釈方法のフラグタイプ +*/ +enum EvaluationOptionFlag +{ + EvaluationOptionFlag_AreBeziersRistricted = 0, ///< ベジェハンドルの規制状態 +}; + /** * @brief motion3.jsonのコンテナ。 * @@ -57,6 +65,18 @@ class CubismMotionJson */ csmBool IsMotionLoop() const; + /** + * @brief モーションのベジェカーブの解釈方式のフラグ取得 + * + * モーション内のベジェカーブハンドルの解釈フラグの状態を取得する。 + * + * @param[in] flagType EvaluationOptionFlagで指定されるフラグタイプ + * + * @retval true フラグあり + * @retval false フラグなし + */ + csmBool GetEvaluationOptionFlag(csmInt32 flagType) const; + /** * @brief モーションカーブの個数の取得 * diff --git a/src/Rendering/CMakeLists.txt b/src/Rendering/CMakeLists.txt index b358268..02cd628 100644 --- a/src/Rendering/CMakeLists.txt +++ b/src/Rendering/CMakeLists.txt @@ -6,9 +6,9 @@ target_sources(${LIB_NAME} if(NOT DEFINED FRAMEWORK_SOURCE) message(WARNING - "[${LIB_NAME}] Set 'FRAMEWORK_SOURCE' variable to 'OpenGL' when using OpenGL rendering." + "[${LIB_NAME}] Set 'FRAMEWORK_SOURCE' variable to 'Cocos2dx' when using Cocos2d-x rendering." ) - set(FRAMEWORK_SOURCE OpenGL) + set(FRAMEWORK_SOURCE Cocos2d) endif() # Add specified rendering directory. diff --git a/src/Rendering/Cocos2d/CMakeLists.txt b/src/Rendering/Cocos2d/CMakeLists.txt new file mode 100644 index 0000000..96cef45 --- /dev/null +++ b/src/Rendering/Cocos2d/CMakeLists.txt @@ -0,0 +1,9 @@ +target_sources(${LIB_NAME} + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/CubismOffscreenSurface_Cocos2dx.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/CubismOffscreenSurface_Cocos2dx.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/CubismRenderer_Cocos2dx.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/CubismRenderer_Cocos2dx.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/CubismCommandBuffer_Cocos2dx.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/CubismCommandBuffer_Cocos2dx.hpp +) diff --git a/src/Rendering/Cocos2d/CubismCommandBuffer_Cocos2dx.cpp b/src/Rendering/Cocos2d/CubismCommandBuffer_Cocos2dx.cpp new file mode 100644 index 0000000..7354032 --- /dev/null +++ b/src/Rendering/Cocos2d/CubismCommandBuffer_Cocos2dx.cpp @@ -0,0 +1,262 @@ +/** + * Copyright(c) Live2D Inc. All rights reserved. + * + * Use of this source code is governed by the Live2D Open Software license + * that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +#include "CubismCommandBuffer_Cocos2dx.hpp" +#include "CubismFramework.hpp" + +//------------ LIVE2D NAMESPACE ------------ +namespace Live2D { namespace Cubism { namespace Framework { namespace Rendering { +CubismCommandBuffer_Cocos2dx::DrawCommandBuffer::DrawCommand::DrawCommand() +{ + _command.init(0.0); +} + +CubismCommandBuffer_Cocos2dx::DrawCommandBuffer::DrawCommand::~DrawCommand() +{ +} + +cocos2d::backend::BlendDescriptor* CubismCommandBuffer_Cocos2dx::DrawCommandBuffer::DrawCommand::GetBlendDescriptor() +{ + return &_command.getPipelineDescriptor().blendDescriptor; +} + +cocos2d::PipelineDescriptor* CubismCommandBuffer_Cocos2dx::DrawCommandBuffer::DrawCommand::GetPipelineDescriptor() +{ + return &_command.getPipelineDescriptor(); +} + +cocos2d::CustomCommand* CubismCommandBuffer_Cocos2dx::DrawCommandBuffer::DrawCommand::GetCommand() +{ + return &_command; +} + +CubismCommandBuffer_Cocos2dx::DrawCommandBuffer::DrawCommandBuffer() + : _vbStride(0) + , _vbCount(0) + , _ibCount(0) +{ +} + +CubismCommandBuffer_Cocos2dx::DrawCommandBuffer::~DrawCommandBuffer() +{ + CSM_FREE(_drawBuffer); +} + +void CubismCommandBuffer_Cocos2dx::DrawCommandBuffer::CreateVertexBuffer(csmSizeInt stride, csmSizeInt count) +{ + _vbStride = stride; + _vbCount = count; + _drawBuffer = static_cast(CSM_MALLOC(stride * count)); + _drawCommandDraw.GetCommand()->createVertexBuffer(stride, count, cocos2d::CustomCommand::BufferUsage::DYNAMIC); +} + +void CubismCommandBuffer_Cocos2dx::DrawCommandBuffer::CreateIndexBuffer(csmSizeInt count) +{ + _ibCount = count; + _drawCommandDraw.GetCommand()->createIndexBuffer(cocos2d::backend::IndexFormat::U_SHORT, count, cocos2d::CustomCommand::BufferUsage::DYNAMIC); +} + +void CubismCommandBuffer_Cocos2dx::DrawCommandBuffer::UpdateVertexBuffer(void* data, void* uvData, csmSizeInt count) +{ + csmSizeInt length = count * _vbStride; + csmFloat32* dest = reinterpret_cast(_drawBuffer); + csmFloat32* sourceVertices = reinterpret_cast(data); + csmFloat32* sourceUvs = reinterpret_cast(uvData); + + for (csmUint32 i = 0, j = 0; i < count; ++i) + { + *dest = *sourceVertices; + dest++; + sourceVertices++; + *dest = *sourceVertices; + dest++; + sourceVertices++; + + *dest = *sourceUvs; + dest++; + sourceUvs++; + *dest = *sourceUvs; + dest++; + sourceUvs++; + } +} + +void CubismCommandBuffer_Cocos2dx::DrawCommandBuffer::UpdateIndexBuffer(void* data, csmSizeInt count) +{ + csmSizeInt length = count * sizeof(csmInt16); + + _drawCommandDraw.GetCommand()->updateIndexBuffer(data, length); +} + +void CubismCommandBuffer_Cocos2dx::DrawCommandBuffer::CommitVertexBuffer() { + + csmSizeInt count = _vbCount * _vbStride; + + _drawCommandDraw.GetCommand()->updateVertexBuffer(_drawBuffer, count); +} + +CubismCommandBuffer_Cocos2dx::DrawCommandBuffer::DrawCommand* CubismCommandBuffer_Cocos2dx::DrawCommandBuffer::GetCommandDraw() +{ + return &_drawCommandDraw; +} + +CubismCommandBuffer_Cocos2dx::CubismCommandBuffer_Cocos2dx() + :_currentColorBuffer(NULL) +{ + _groupCommand.init(0.0); +} + +CubismCommandBuffer_Cocos2dx::~CubismCommandBuffer_Cocos2dx() +{ +} + +void CubismCommandBuffer_Cocos2dx::PushCommandGroup() +{ + GetCocos2dRenderer()->addCommand(&_groupCommand); + GetCocos2dRenderer()->pushGroup(_groupCommand.getRenderQueueID()); +} + +void CubismCommandBuffer_Cocos2dx::PopCommandGroup() +{ + GetCocos2dRenderer()->popGroup(); +} + +void CubismCommandBuffer_Cocos2dx::SetOperationEnable(OperationType operationType, csmBool enabled) +{ + _operationStateArray[operationType].Enabled = enabled; + + + AddCommand + ( + [=]() -> void + { + switch (operationType) + { + case OperationType_ScissorTest: + GetCocos2dRenderer()->setScissorTest(enabled); + break; + case OperationType_DepthTest: + GetCocos2dRenderer()->setDepthTest(enabled); + break; + case OperationType_StencilTest: + GetCocos2dRenderer()->setStencilTest(enabled); + break; + case OperationType_Culling: + if (!enabled) + { + GetCocos2dRenderer()->setCullMode(cocos2d::CullMode::NONE); + } + else + { + switch (_operationStateArray[operationType].Arg0.i32) + { + case CullType_Front: + GetCocos2dRenderer()->setCullMode(cocos2d::CullMode::FRONT); + break; + case CullType_Back: + GetCocos2dRenderer()->setCullMode(cocos2d::CullMode::BACK); + break; + } + } + break; + + } + } + ); +} + +csmBool CubismCommandBuffer_Cocos2dx::GetOperationEnabled(OperationType operationType) +{ + return _operationStateArray[operationType].Enabled; +} + +void CubismCommandBuffer_Cocos2dx::SetCullMode(CullType cullType) +{ + _operationStateArray[OperationType_Culling].Arg0.i32 = cullType; + + + SetOperationEnable(OperationType_Culling, _operationStateArray[OperationType_Culling].Enabled); +} + +void CubismCommandBuffer_Cocos2dx::SetWindingMode(WindingType windingType) +{ + _operationStateArray[OperationType_Winding].Arg0.i32 = windingType; + + + AddCommand + ( + [=] () -> void + { + switch (_operationStateArray[OperationType_Winding].Arg0.i32) + { + case WindingType_ClockWise: + GetCocos2dRenderer()->setWinding(cocos2d::Winding::CLOCK_WISE); + break; + + case WindingType_CounterClockWise: + GetCocos2dRenderer()->setWinding(cocos2d::Winding::COUNTER_CLOCK_WISE); + break; + } + } + ); +} + +void CubismCommandBuffer_Cocos2dx::Clear(csmFloat32 r, csmFloat32 g, csmFloat32 b, csmFloat32 a) +{ + // Add the callback command internally. + GetCocos2dRenderer()->clear(cocos2d::ClearFlag::COLOR, cocos2d::Color4F(r, g, b, a), 0.0f, 0, 0.0f); +} + +void CubismCommandBuffer_Cocos2dx::Viewport(csmFloat32 x, csmFloat32 y, csmFloat32 w, csmFloat32 h) +{ + AddCommand + ( + [=] () -> void + { + GetCocos2dRenderer()->setViewPort(x, y, w, h); + } + ); +} + +void CubismCommandBuffer_Cocos2dx::SetColorBuffer(cocos2d::Texture2D* colorBuffer) +{ + _currentColorBuffer = colorBuffer; + + AddCommand + ( + [=] () -> void + { + GetCocos2dRenderer()->setRenderTarget(cocos2d::RenderTargetFlag::COLOR, colorBuffer, NULL, NULL); + } + ); +} + +cocos2d::Texture2D* CubismCommandBuffer_Cocos2dx::GetColorBuffer() +{ + return _currentColorBuffer; +} + +void CubismCommandBuffer_Cocos2dx::AddDrawCommand(DrawCommandBuffer::DrawCommand* drawCommand) +{ + GetCocos2dRenderer()->addCommand(drawCommand->GetCommand()); +} + +void CubismCommandBuffer_Cocos2dx::AddCommand(const std::function& fn) +{ + cocos2d::CallbackCommand* command = CSM_NEW cocos2d::CallbackCommand(); + + command->init(0.0f); + command->func = [=] () -> void + { + fn(); + delete command; + }; + + GetCocos2dRenderer()->addCommand(command); +} + +}}}} diff --git a/src/Rendering/Cocos2d/CubismCommandBuffer_Cocos2dx.hpp b/src/Rendering/Cocos2d/CubismCommandBuffer_Cocos2dx.hpp new file mode 100644 index 0000000..be94d39 --- /dev/null +++ b/src/Rendering/Cocos2d/CubismCommandBuffer_Cocos2dx.hpp @@ -0,0 +1,162 @@ +/** + * Copyright(c) Live2D Inc. All rights reserved. + * + * Use of this source code is governed by the Live2D Open Software license + * that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +#pragma once + +#include "CubismFramework.hpp" +#include "cocos2d.h" + +#ifdef CSM_TARGET_ANDROID_ES2 +#include +#include +#include +#include +#endif + +#ifdef CSM_TARGET_IPHONE_ES2 +#include +#include +#endif + +#if defined(CSM_TARGET_WIN_GL) || defined(CSM_TARGET_LINUX_GL) +//#include +//#include +#endif + +#ifdef CSM_TARGET_MAC_GL +#ifndef CSM_TARGET_COCOS +#include +#endif +#include +#endif + +namespace Live2D { namespace Cubism { namespace Framework { namespace Rendering { + +static inline cocos2d::Renderer* GetCocos2dRenderer() +{ + return cocos2d::Director::getInstance()->getRenderer(); +} + +class CubismCommandBuffer_Cocos2dx +{ +public: + class DrawCommandBuffer + { + public: + class DrawCommand + { + public: + DrawCommand(); + virtual ~DrawCommand(); + + cocos2d::backend::BlendDescriptor* GetBlendDescriptor(); + cocos2d::PipelineDescriptor* GetPipelineDescriptor(); + cocos2d::CustomCommand* GetCommand(); + + private: + DrawCommand& operator=(const DrawCommand&); + cocos2d::CustomCommand _command; + }; + + DrawCommandBuffer(); + virtual ~DrawCommandBuffer(); + + + void CreateVertexBuffer(csmSizeInt stride, csmSizeInt count); + void CreateIndexBuffer(csmSizeInt count); + void UpdateVertexBuffer(void* data, void* uvData, csmSizeInt count); + void UpdateIndexBuffer(void* data, csmSizeInt count); + void CommitVertexBuffer(); + + DrawCommand* GetCommandDraw(); + + private: + DrawCommand _drawCommandDraw; + csmSizeInt _vbStride; + csmSizeInt _vbCount; + csmSizeInt _ibCount; + csmUint8* _drawBuffer; + }; + + union OperationStateDataArgument + { + csmBool bl; + csmInt32 i32; + csmUint32 u32; + csmFloat32 f32; + }; + + struct OperationStateData + { + OperationStateData() + : Enabled(false) + { + Arg0.i32 = 0; + Arg1.i32 = 0; + Arg2.i32 = 0; + Arg3.i32 = 0; + } + + csmBool Enabled; + OperationStateDataArgument Arg0; + OperationStateDataArgument Arg1; + OperationStateDataArgument Arg2; + OperationStateDataArgument Arg3; + }; + + enum OperationType + { + OperationType_ScissorTest = 0, + OperationType_DepthTest, + OperationType_StencilTest, + OperationType_Culling, + OperationType_Winding, + OperationType_TypeMax, + }; + + enum CullType + { + CullType_Front, + CullType_Back, + }; + + enum WindingType + { + WindingType_ClockWise, + WindingType_CounterClockWise, + }; + + CubismCommandBuffer_Cocos2dx(); + virtual ~CubismCommandBuffer_Cocos2dx(); + + void PushCommandGroup(); + void PopCommandGroup(); + + void SetOperationEnable(OperationType operationType, csmBool enabled); + csmBool GetOperationEnabled(OperationType operationType); + + void SetCullMode(CullType cullType); + void SetWindingMode(WindingType windingType); + + void Clear(csmFloat32 r, csmFloat32 g, csmFloat32 b, csmFloat32 a); + + void Viewport(csmFloat32 x, csmFloat32 y, csmFloat32 w, csmFloat32 h); + + void SetColorBuffer(cocos2d::Texture2D* colorBuffer); + cocos2d::Texture2D* GetColorBuffer(); + + void AddDrawCommand(DrawCommandBuffer::DrawCommand* drawCommand); + +private: + void AddCommand(const std::function& fn); + + cocos2d::Texture2D* _currentColorBuffer; + OperationStateData _operationStateArray[OperationType_TypeMax]; + cocos2d::GroupCommand _groupCommand; +}; + +}}}} diff --git a/src/Rendering/Cocos2d/CubismOffscreenSurface_Cocos2dx.cpp b/src/Rendering/Cocos2d/CubismOffscreenSurface_Cocos2dx.cpp new file mode 100644 index 0000000..5cbc97d --- /dev/null +++ b/src/Rendering/Cocos2d/CubismOffscreenSurface_Cocos2dx.cpp @@ -0,0 +1,173 @@ +/** + * Copyright(c) Live2D Inc. All rights reserved. + * + * Use of this source code is governed by the Live2D Open Software license + * that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +#include "CubismOffscreenSurface_Cocos2dx.hpp" + +//------------ LIVE2D NAMESPACE ------------ +namespace Live2D { namespace Cubism { namespace Framework { namespace Rendering { + +CubismOffscreenFrame_Cocos2dx::CubismOffscreenFrame_Cocos2dx() + : _renderTexture(NULL) + , _colorBuffer(NULL) + , _isInheritedRenderTexture(false) + , _previousColorBuffer(NULL) + , _bufferWidth(0) + , _bufferHeight(0) +{ +} + + +void CubismOffscreenFrame_Cocos2dx::BeginDraw(CubismCommandBuffer_Cocos2dx* commandBuffer, cocos2d::Texture2D* colorBufferOnFinishDrawing) +{ + if (!IsValid()) + { + return; + } + + // バックバッファのサーフェイスを記憶しておく + if (colorBufferOnFinishDrawing == NULL) + { + _previousColorBuffer = commandBuffer->GetColorBuffer(); + if (_previousColorBuffer == NULL) + { + _previousColorBuffer = GetCocos2dRenderer()->getColorAttachment(); + } + } + else + { + _previousColorBuffer = colorBufferOnFinishDrawing; + } + + // マスク用RenderTextureをactiveにセット + commandBuffer->SetColorBuffer(_renderTexture->getSprite()->getTexture()); +} + +void CubismOffscreenFrame_Cocos2dx::EndDraw(CubismCommandBuffer_Cocos2dx* commandBuffer) +{ + if (!IsValid()) + { + return; + } + + // 描画対象を戻す + commandBuffer->SetColorBuffer(_previousColorBuffer); +} + +void CubismOffscreenFrame_Cocos2dx::Clear(CubismCommandBuffer_Cocos2dx* commandBuffer, float r, float g, float b, float a) +{ + // マスクをクリアする + commandBuffer->Clear(r, g, b, a); +} + +csmBool CubismOffscreenFrame_Cocos2dx::CreateOffscreenFrame(csmUint32 displayBufferWidth, csmUint32 displayBufferHeight, cocos2d::Texture2D* colorBuffer) +{ + // 一旦削除 + DestroyOffscreenFrame(); + + do + { + if (colorBuffer == 0) + { + // The inherited RenderTexture is nothing. + // Make a RenderTexture. + + + csmBool initResult = false; + + + _renderTexture = cocos2d::RenderTexture::create(displayBufferWidth, displayBufferHeight); + + if (!_renderTexture) + { + break; + } + + _renderTexture->retain(); + + + _renderTexture->getSprite()->getTexture()->setTexParameters( + cocos2d::Texture2D::TexParams( + cocos2d::backend::SamplerFilter::LINEAR, // MagFilter + cocos2d::backend::SamplerFilter::LINEAR, // MinFilter + cocos2d::backend::SamplerAddressMode::CLAMP_TO_EDGE, // AddressingMode S + cocos2d::backend::SamplerAddressMode::CLAMP_TO_EDGE // AddressingMode T + ) + ); + + _colorBuffer = _renderTexture->getSprite()->getTexture(); + _isInheritedRenderTexture = false; + } + else + { + // Use the inherited RenderTexture. + _colorBuffer = colorBuffer; + + + _isInheritedRenderTexture = true; + } + + if (_colorBuffer) + { + _viewPortSize = csmRectF(0.0f, 0.0f, _colorBuffer->getContentSizeInPixels().width, _colorBuffer->getContentSizeInPixels().height); + } + else + { + _viewPortSize = csmRectF(0.0f, 0.0f, _bufferWidth, _bufferHeight); + } + + _bufferWidth = displayBufferWidth; + _bufferHeight = displayBufferHeight; + + + // 成功 + return true; + + } while (0); + + // 失敗したので削除 + DestroyOffscreenFrame(); + + return false; +} + +void CubismOffscreenFrame_Cocos2dx::DestroyOffscreenFrame() +{ + if ((_renderTexture != NULL) && !_isInheritedRenderTexture) + { + CC_SAFE_RELEASE_NULL(_renderTexture); + _colorBuffer = NULL; + } +} + +cocos2d::Texture2D* CubismOffscreenFrame_Cocos2dx::GetColorBuffer() const +{ + return _renderTexture->getSprite()->getTexture(); +} + +csmUint32 CubismOffscreenFrame_Cocos2dx::GetBufferWidth() const +{ + return _bufferWidth; +} + +csmUint32 CubismOffscreenFrame_Cocos2dx::GetBufferHeight() const +{ + return _bufferHeight; +} + +csmRectF CubismOffscreenFrame_Cocos2dx::GetViewPortSize() const +{ + return _viewPortSize; +} + +csmBool CubismOffscreenFrame_Cocos2dx::IsValid() const +{ + return _renderTexture != NULL; +} + +}}}} + +//------------ LIVE2D NAMESPACE ------------ diff --git a/src/Rendering/Cocos2d/CubismOffscreenSurface_Cocos2dx.hpp b/src/Rendering/Cocos2d/CubismOffscreenSurface_Cocos2dx.hpp new file mode 100644 index 0000000..eaff6a6 --- /dev/null +++ b/src/Rendering/Cocos2d/CubismOffscreenSurface_Cocos2dx.hpp @@ -0,0 +1,127 @@ +/** + * Copyright(c) Live2D Inc. All rights reserved. + * + * Use of this source code is governed by the Live2D Open Software license + * that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +#pragma once + +#include "CubismFramework.hpp" +#include "CubismCommandBuffer_Cocos2dx.hpp" +#include "Type/csmVector.hpp" +#include "Type/csmRectF.hpp" +#include "Type/csmMap.hpp" +#include + +#ifdef CSM_TARGET_ANDROID_ES2 +#include +#include +#include +#include +#endif + +#ifdef CSM_TARGET_IPHONE_ES2 +#include +#include +#endif + +#if defined(CSM_TARGET_WIN_GL) || defined(CSM_TARGET_LINUX_GL) +#include +#include +#endif + +#ifdef CSM_TARGET_MAC_GL +#ifndef CSM_TARGET_COCOS +#include +#endif +#include +#endif + +//------------ LIVE2D NAMESPACE ------------ +namespace Live2D { namespace Cubism { namespace Framework { namespace Rendering { + + +/** + * @brief オフスクリーン描画用構造体 + */ +class CubismOffscreenFrame_Cocos2dx +{ +public: + + CubismOffscreenFrame_Cocos2dx(); + + /** + * @brief 指定の描画ターゲットに向けて描画開始 + * + */ + void BeginDraw(CubismCommandBuffer_Cocos2dx* commandBuffer, cocos2d::Texture2D* colorBufferOnFinishDrawing); + + /** + * @brief 描画終了 + * + */ + void EndDraw(CubismCommandBuffer_Cocos2dx* commandBuffer); + + /** + * @brief レンダリングターゲットのクリア + * 呼ぶ場合はBeginDrawの後で呼ぶこと + * @param r 赤(0.0~1.0) + * @param g 緑(0.0~1.0) + * @param b 青(0.0~1.0) + * @param a α(0.0~1.0) + */ + void Clear(CubismCommandBuffer_Cocos2dx* commandBuffer, float r, float g, float b, float a); + + /** + * @brief CubismOffscreenFrame作成 + * @param displayBufferWidth 作成するバッファ幅 + * @param displayBufferHeight 作成するバッファ高さ + * @param colorBuffer 0以外の場合、ピクセル格納領域としてcolorBufferを使用する + */ + csmBool CreateOffscreenFrame(csmUint32 displayBufferWidth, csmUint32 displayBufferHeight, cocos2d::Texture2D* colorBuffer = NULL); + + /** + * @brief CubismOffscreenFrameの削除 + */ + void DestroyOffscreenFrame(); + + /** + * @brief カラーバッファメンバーへのアクセッサ + */ + cocos2d::Texture2D* GetColorBuffer() const; + + /** + * @brief バッファ幅取得 + */ + csmUint32 GetBufferWidth() const; + + /** + * @brief バッファ高さ取得 + */ + csmUint32 GetBufferHeight() const; + + csmRectF GetViewPortSize() const; + + /** + * @brief 現在有効かどうか + */ + csmBool IsValid() const; + +private: + cocos2d::RenderTexture* _renderTexture; ///< レンダリングターゲットとしてのアドレス + cocos2d::Texture2D* _colorBuffer; + csmBool _isInheritedRenderTexture; + + cocos2d::Texture2D* _previousColorBuffer; ///< 旧フレームバッファ + + csmUint32 _bufferWidth; ///< Create時に指定された幅 + csmUint32 _bufferHeight; ///< Create時に指定された高さ + + csmRectF _viewPortSize; +}; + + +}}}} + +//------------ LIVE2D NAMESPACE ------------ diff --git a/src/Rendering/Cocos2d/CubismRenderer_Cocos2dx.cpp b/src/Rendering/Cocos2d/CubismRenderer_Cocos2dx.cpp new file mode 100644 index 0000000..5950f39 --- /dev/null +++ b/src/Rendering/Cocos2d/CubismRenderer_Cocos2dx.cpp @@ -0,0 +1,1838 @@ +/** + * Copyright(c) Live2D Inc. All rights reserved. + * + * Use of this source code is governed by the Live2D Open Software license + * that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +#include "CubismRenderer_Cocos2dx.hpp" +#include "Math/CubismMatrix44.hpp" +#include "Type/csmVector.hpp" +#include "Model/CubismModel.hpp" +#include +#include "renderer/backend/Device.h" + +#ifdef CSM_TARGET_WIN_GL +#include +#endif + +//------------ LIVE2D NAMESPACE ------------ +namespace Live2D { namespace Cubism { namespace Framework { namespace Rendering { + +/********************************************************************************************************************* +* CubismClippingManager_Cocos2dx +********************************************************************************************************************/ +///< ファイルスコープの変数宣言 +namespace { +const csmInt32 ColorChannelCount = 4; ///< 実験時に1チャンネルの場合は1、RGBだけの場合は3、アルファも含める場合は4 +} + +CubismClippingManager_Cocos2dx::CubismClippingManager_Cocos2dx() : + _currentFrameNo(0) + , _clippingMaskBufferSize(256) +{ + CubismRenderer::CubismTextureColor* tmp; + tmp = CSM_NEW CubismRenderer::CubismTextureColor(); + tmp->R = 1.0f; + tmp->G = 0.0f; + tmp->B = 0.0f; + tmp->A = 0.0f; + _channelColors.PushBack(tmp); + tmp = CSM_NEW CubismRenderer::CubismTextureColor(); + tmp->R = 0.0f; + tmp->G = 1.0f; + tmp->B = 0.0f; + tmp->A = 0.0f; + _channelColors.PushBack(tmp); + tmp = CSM_NEW CubismRenderer::CubismTextureColor(); + tmp->R = 0.0f; + tmp->G = 0.0f; + tmp->B = 1.0f; + tmp->A = 0.0f; + _channelColors.PushBack(tmp); + tmp = CSM_NEW CubismRenderer::CubismTextureColor(); + tmp->R = 0.0f; + tmp->G = 0.0f; + tmp->B = 0.0f; + tmp->A = 1.0f; + _channelColors.PushBack(tmp); + +} + +CubismClippingManager_Cocos2dx::~CubismClippingManager_Cocos2dx() +{ + for (csmUint32 i = 0; i < _clippingContextListForMask.GetSize(); i++) + { + if (_clippingContextListForMask[i]) CSM_DELETE_SELF(CubismClippingContext, _clippingContextListForMask[i]); + _clippingContextListForMask[i] = NULL; + } + + // _clippingContextListForDrawは_clippingContextListForMaskにあるインスタンスを指している。上記の処理により要素ごとのDELETEは不要。 + for (csmUint32 i = 0; i < _clippingContextListForDraw.GetSize(); i++) + { + _clippingContextListForDraw[i] = NULL; + } + + for (csmUint32 i = 0; i < _channelColors.GetSize(); i++) + { + if (_channelColors[i]) CSM_DELETE(_channelColors[i]); + _channelColors[i] = NULL; + } +} + +void CubismClippingManager_Cocos2dx::Initialize(CubismModel& model, csmInt32 drawableCount, const csmInt32** drawableMasks, const csmInt32* drawableMaskCounts) +{ + //クリッピングマスクを使う描画オブジェクトを全て登録する + //クリッピングマスクは、通常数個程度に限定して使うものとする + for (csmInt32 i = 0; i < drawableCount; i++) + { + if (drawableMaskCounts[i] <= 0) + { + //クリッピングマスクが使用されていないアートメッシュ(多くの場合使用しない) + _clippingContextListForDraw.PushBack(NULL); + continue; + } + + // 既にあるClipContextと同じかチェックする + CubismClippingContext* cc = FindSameClip(drawableMasks[i], drawableMaskCounts[i]); + if (cc == NULL) + { + // 同一のマスクが存在していない場合は生成する + cc = CSM_NEW CubismClippingContext(this, model, drawableMasks[i], drawableMaskCounts[i]); + _clippingContextListForMask.PushBack(cc); + } + + cc->AddClippedDrawable(i); + + _clippingContextListForDraw.PushBack(cc); + + } +} + +CubismClippingContext* CubismClippingManager_Cocos2dx::FindSameClip(const csmInt32* drawableMasks, csmInt32 drawableMaskCounts) const +{ + // 作成済みClippingContextと一致するか確認 + for (csmUint32 i = 0; i < _clippingContextListForMask.GetSize(); i++) + { + CubismClippingContext* cc = _clippingContextListForMask[i]; + const csmInt32 count = cc->_clippingIdCount; + if (count != drawableMaskCounts) continue; //個数が違う場合は別物 + csmInt32 samecount = 0; + + // 同じIDを持つか確認。配列の数が同じなので、一致した個数が同じなら同じ物を持つとする。 + for (csmInt32 j = 0; j < count; j++) + { + const csmInt32 clipId = cc->_clippingIdList[j]; + for (csmInt32 k = 0; k < count; k++) + { + if (drawableMasks[k] == clipId) + { + samecount++; + break; + } + } + } + if (samecount == count) + { + return cc; + } + } + return NULL; //見つからなかった +} + +void CubismClippingManager_Cocos2dx::SetupClippingContext(CubismModel& model, CubismRenderer_Cocos2dx* renderer, cocos2d::Texture2D* lastColorBuffer, csmRectF lastViewport) +{ + _currentFrameNo++; + + // 全てのクリッピングを用意する + // 同じクリップ(複数の場合はまとめて1つのクリップ)を使う場合は1度だけ設定する + csmInt32 usingClipCount = 0; + for (csmUint32 clipIndex = 0; clipIndex < _clippingContextListForMask.GetSize(); clipIndex++) + { + // 1つのクリッピングマスクに関して + CubismClippingContext* cc = _clippingContextListForMask[clipIndex]; + + // このクリップを利用する描画オブジェクト群全体を囲む矩形を計算 + CalcClippedDrawTotalBounds(model, cc); + + if (cc->_isUsing) + { + usingClipCount++; //使用中としてカウント + } + } + + // マスク作成処理 + if (usingClipCount > 0) + { + if (!renderer->IsUsingHighPrecisionMask()) + { + // 生成したFrameBufferと同じサイズでビューポートを設定 + renderer->GetCommandBuffer()->Viewport(0, 0, renderer->_offscreenFrameBuffer.GetViewPortSize().Width, renderer->_offscreenFrameBuffer.GetViewPortSize().Height); + + // モデル描画時にDrawMeshNowに渡される変換(モデルtoワールド座標変換) + CubismMatrix44 modelToWorldF = renderer->GetMvpMatrix(); + + renderer->PreDraw(); // バッファをクリアする + + // _offscreenFrameBufferへ切り替え + renderer->_offscreenFrameBuffer.BeginDraw(renderer->GetCommandBuffer(), lastColorBuffer); + + // マスクをクリアする + // 1が無効(描かれない)領域、0が有効(描かれる)領域。(シェーダで Cd*Csで0に近い値をかけてマスクを作る。1をかけると何も起こらない) + renderer->_offscreenFrameBuffer.Clear(renderer->GetCommandBuffer(), 1.0f, 1.0f, 1.0f, 1.0f); + } + + // 各マスクのレイアウトを決定していく + SetupLayoutBounds(renderer->IsUsingHighPrecisionMask() ? 0 : usingClipCount); + + // 実際にマスクを生成する + // 全てのマスクをどの様にレイアウトして描くかを決定し、ClipContext , ClippedDrawContext に記憶する + for (csmUint32 clipIndex = 0; clipIndex < _clippingContextListForMask.GetSize(); clipIndex++) + { + // --- 実際に1つのマスクを描く --- + CubismClippingContext* clipContext = _clippingContextListForMask[clipIndex]; + csmRectF* allClippedDrawRect = clipContext->_allClippedDrawRect; //このマスクを使う、全ての描画オブジェクトの論理座標上の囲み矩形 + csmRectF* layoutBoundsOnTex01 = clipContext->_layoutBounds; //この中にマスクを収める + + // モデル座標上の矩形を、適宜マージンを付けて使う + const csmFloat32 MARGIN = 0.05f; + _tmpBoundsOnModel.SetRect(allClippedDrawRect); + _tmpBoundsOnModel.Expand(allClippedDrawRect->Width * MARGIN, allClippedDrawRect->Height * MARGIN); + //########## 本来は割り当てられた領域の全体を使わず必要最低限のサイズがよい + + // シェーダ用の計算式を求める。回転を考慮しない場合は以下のとおり + // movePeriod' = movePeriod * scaleX + offX [[ movePeriod' = (movePeriod - tmpBoundsOnModel.movePeriod)*scale + layoutBoundsOnTex01.movePeriod ]] + const csmFloat32 scaleX = layoutBoundsOnTex01->Width / _tmpBoundsOnModel.Width; + const csmFloat32 scaleY = layoutBoundsOnTex01->Height / _tmpBoundsOnModel.Height; + + // マスク生成時に使う行列を求める + { + // シェーダに渡す行列を求める <<<<<<<<<<<<<<<<<<<<<<<< 要最適化(逆順に計算すればシンプルにできる) + _tmpMatrix.LoadIdentity(); + { + // Layout0..1 を -1..1に変換 + _tmpMatrix.TranslateRelative(-1.0f, -1.0f); + _tmpMatrix.ScaleRelative(2.0f, 2.0f); + } + { + // view to Layout0..1 + _tmpMatrix.TranslateRelative(layoutBoundsOnTex01->X, layoutBoundsOnTex01->Y); //new = [translate] + _tmpMatrix.ScaleRelative(scaleX, scaleY); //new = [translate][scale] + _tmpMatrix.TranslateRelative(-_tmpBoundsOnModel.X, -_tmpBoundsOnModel.Y); + //new = [translate][scale][translate] + } + // tmpMatrixForMask が計算結果 + _tmpMatrixForMask.SetMatrix(_tmpMatrix.GetArray()); + } + + //--------- draw時の mask 参照用行列を計算 + { + // シェーダに渡す行列を求める <<<<<<<<<<<<<<<<<<<<<<<< 要最適化(逆順に計算すればシンプルにできる) + _tmpMatrix.LoadIdentity(); + { + _tmpMatrix.TranslateRelative(layoutBoundsOnTex01->X, layoutBoundsOnTex01->Y); //new = [translate] + _tmpMatrix.ScaleRelative(scaleX, scaleY); //new = [translate][scale] + _tmpMatrix.TranslateRelative(-_tmpBoundsOnModel.X, -_tmpBoundsOnModel.Y); + //new = [translate][scale][translate] + } + + _tmpMatrixForDraw.SetMatrix(_tmpMatrix.GetArray()); + } + + clipContext->_matrixForMask.SetMatrix(_tmpMatrixForMask.GetArray()); + + clipContext->_matrixForDraw.SetMatrix(_tmpMatrixForDraw.GetArray()); + + if (!renderer->IsUsingHighPrecisionMask()) + { + const csmInt32 clipDrawCount = clipContext->_clippingIdCount; + for (csmInt32 i = 0; i < clipDrawCount; i++) + { + const csmInt32 clipDrawIndex = clipContext->_clippingIdList[i]; + CubismCommandBuffer_Cocos2dx::DrawCommandBuffer* drawCommandBufferData = clipContext->_clippingCommandBufferList->At(i);// [i]; + + + // 頂点情報が更新されておらず、信頼性がない場合は描画をパスする + if (!model.GetDrawableDynamicFlagVertexPositionsDidChange(clipDrawIndex)) + { + continue; + } + + { + // Update Vertex / Index buffer. + { + csmFloat32* vertices = const_cast(model.GetDrawableVertices(clipDrawIndex)); + Core::csmVector2* uvs = const_cast(model.GetDrawableVertexUvs(clipDrawIndex)); + csmUint16* vertexIndices = const_cast(model.GetDrawableVertexIndices(clipDrawIndex)); + const csmUint32 vertexCount = model.GetDrawableVertexCount(clipDrawIndex); + const csmUint32 vertexIndexCount = model.GetDrawableVertexIndexCount(clipDrawIndex); + + drawCommandBufferData->UpdateVertexBuffer(vertices, uvs, vertexCount); + drawCommandBufferData->CommitVertexBuffer(); + if (vertexIndexCount > 0) + { + drawCommandBufferData->UpdateIndexBuffer(vertexIndices, vertexIndexCount); + } + + if (vertexCount <= 0) + { + continue; + } + + } + } + + + renderer->IsCulling(model.GetDrawableCulling(clipDrawIndex) != 0); + + // 今回専用の変換を適用して描く + // チャンネルも切り替える必要がある(A,R,G,B) + renderer->SetClippingContextBufferForMask(clipContext); + + + + renderer->DrawMeshCocos2d( + drawCommandBufferData->GetCommandDraw(), + model.GetDrawableTextureIndices(clipDrawIndex), + model.GetDrawableVertexIndexCount(clipDrawIndex), + model.GetDrawableVertexCount(clipDrawIndex), + const_cast(model.GetDrawableVertexIndices(clipDrawIndex)), + const_cast(model.GetDrawableVertices(clipDrawIndex)), + reinterpret_cast(const_cast(model.GetDrawableVertexUvs(clipDrawIndex))), + model.GetDrawableOpacity(clipDrawIndex), + CubismRenderer::CubismBlendMode_Normal, //クリッピングは通常描画を強制 + false // マスク生成時はクリッピングの反転使用は全く関係がない + ); + } + } + } + + if (!renderer->IsUsingHighPrecisionMask()) + { + // --- 後処理 --- + renderer->_offscreenFrameBuffer.EndDraw(renderer->GetCommandBuffer()); // 描画対象を戻す + renderer->SetClippingContextBufferForMask(NULL); + renderer->GetCommandBuffer()->Viewport(lastViewport.X, lastViewport.Y, lastViewport.Width, lastViewport.Height); + } + } +} + +void CubismClippingManager_Cocos2dx::CalcClippedDrawTotalBounds(CubismModel& model, CubismClippingContext* clippingContext) +{ + // 被クリッピングマスク(マスクされる描画オブジェクト)の全体の矩形 + csmFloat32 clippedDrawTotalMinX = FLT_MAX, clippedDrawTotalMinY = FLT_MAX; + csmFloat32 clippedDrawTotalMaxX = FLT_MIN, clippedDrawTotalMaxY = FLT_MIN; + + // このマスクが実際に必要か判定する + // このクリッピングを利用する「描画オブジェクト」がひとつでも使用可能であればマスクを生成する必要がある + + const csmInt32 clippedDrawCount = clippingContext->_clippedDrawableIndexList->GetSize(); + for (csmInt32 clippedDrawableIndex = 0; clippedDrawableIndex < clippedDrawCount; clippedDrawableIndex++) + { + // マスクを使用する描画オブジェクトの描画される矩形を求める + const csmInt32 drawableIndex = (*clippingContext->_clippedDrawableIndexList)[clippedDrawableIndex]; + + const csmInt32 drawableVertexCount = model.GetDrawableVertexCount(drawableIndex); + csmFloat32* drawableVertexes = const_cast(model.GetDrawableVertices(drawableIndex)); + + csmFloat32 minX = FLT_MAX, minY = FLT_MAX; + csmFloat32 maxX = FLT_MIN, maxY = FLT_MIN; + + csmInt32 loop = drawableVertexCount * Constant::VertexStep; + for (csmInt32 pi = Constant::VertexOffset; pi < loop; pi += Constant::VertexStep) + { + csmFloat32 x = drawableVertexes[pi]; + csmFloat32 y = drawableVertexes[pi + 1]; + if (x < minX) minX = x; + if (x > maxX) maxX = x; + if (y < minY) minY = y; + if (y > maxY) maxY = y; + } + + // + if (minX == FLT_MAX) continue; //有効な点がひとつも取れなかったのでスキップする + + // 全体の矩形に反映 + if (minX < clippedDrawTotalMinX) clippedDrawTotalMinX = minX; + if (minY < clippedDrawTotalMinY) clippedDrawTotalMinY = minY; + if (maxX > clippedDrawTotalMaxX) clippedDrawTotalMaxX = maxX; + if (maxY > clippedDrawTotalMaxY) clippedDrawTotalMaxY = maxY; + } + if (clippedDrawTotalMinX == FLT_MAX) + { + clippingContext->_allClippedDrawRect->X = 0.0f; + clippingContext->_allClippedDrawRect->Y = 0.0f; + clippingContext->_allClippedDrawRect->Width = 0.0f; + clippingContext->_allClippedDrawRect->Height = 0.0f; + clippingContext->_isUsing = false; + } + else + { + clippingContext->_isUsing = true; + csmFloat32 w = clippedDrawTotalMaxX - clippedDrawTotalMinX; + csmFloat32 h = clippedDrawTotalMaxY - clippedDrawTotalMinY; + clippingContext->_allClippedDrawRect->X = clippedDrawTotalMinX; + clippingContext->_allClippedDrawRect->Y = clippedDrawTotalMinY; + clippingContext->_allClippedDrawRect->Width = w; + clippingContext->_allClippedDrawRect->Height = h; + } +} + +void CubismClippingManager_Cocos2dx::SetupLayoutBounds(csmInt32 usingClipCount) const +{ + if (usingClipCount <= 0) + {// この場合は一つのマスクターゲットを毎回クリアして使用する + for (csmUint32 index = 0; index < _clippingContextListForMask.GetSize(); index++) + { + CubismClippingContext* cc = _clippingContextListForMask[index]; + cc->_layoutChannelNo = 0; // どうせ毎回消すので固定で良い + cc->_layoutBounds->X = 0.0f; + cc->_layoutBounds->Y = 0.0f; + cc->_layoutBounds->Width = 1.0f; + cc->_layoutBounds->Height = 1.0f; + } + return; + } + + // ひとつのRenderTextureを極力いっぱいに使ってマスクをレイアウトする + // マスクグループの数が4以下ならRGBA各チャンネルに1つずつマスクを配置し、5以上6以下ならRGBAを2,2,1,1と配置する + + // RGBAを順番に使っていく。 + const csmInt32 div = usingClipCount / ColorChannelCount; //1チャンネルに配置する基本のマスク個数 + const csmInt32 mod = usingClipCount % ColorChannelCount; //余り、この番号のチャンネルまでに1つずつ配分する + + // RGBAそれぞれのチャンネルを用意していく(0:R , 1:G , 2:B, 3:A, ) + csmInt32 curClipIndex = 0; //順番に設定していく + + for (csmInt32 channelNo = 0; channelNo < ColorChannelCount; channelNo++) + { + // このチャンネルにレイアウトする数 + const csmInt32 layoutCount = div + (channelNo < mod ? 1 : 0); + + // 分割方法を決定する + if (layoutCount == 0) + { + // 何もしない + } + else if (layoutCount == 1) + { + //全てをそのまま使う + CubismClippingContext* cc = _clippingContextListForMask[curClipIndex++]; + cc->_layoutChannelNo = channelNo; + cc->_layoutBounds->X = 0.0f; + cc->_layoutBounds->Y = 0.0f; + cc->_layoutBounds->Width = 1.0f; + cc->_layoutBounds->Height = 1.0f; + } + else if (layoutCount == 2) + { + for (csmInt32 i = 0; i < layoutCount; i++) + { + const csmInt32 xpos = i % 2; + + CubismClippingContext* cc = _clippingContextListForMask[curClipIndex++]; + cc->_layoutChannelNo = channelNo; + + cc->_layoutBounds->X = xpos * 0.5f; + cc->_layoutBounds->Y = 0.0f; + cc->_layoutBounds->Width = 0.5f; + cc->_layoutBounds->Height = 1.0f; + //UVを2つに分解して使う + } + } + else if (layoutCount <= 4) + { + //4分割して使う + for (csmInt32 i = 0; i < layoutCount; i++) + { + const csmInt32 xpos = i % 2; + const csmInt32 ypos = i / 2; + + CubismClippingContext* cc = _clippingContextListForMask[curClipIndex++]; + cc->_layoutChannelNo = channelNo; + + cc->_layoutBounds->X = xpos * 0.5f; + cc->_layoutBounds->Y = ypos * 0.5f; + cc->_layoutBounds->Width = 0.5f; + cc->_layoutBounds->Height = 0.5f; + } + } + else if (layoutCount <= 9) + { + //9分割して使う + for (csmInt32 i = 0; i < layoutCount; i++) + { + const csmInt32 xpos = i % 3; + const csmInt32 ypos = i / 3; + + CubismClippingContext* cc = _clippingContextListForMask[curClipIndex++]; + cc->_layoutChannelNo = channelNo; + + cc->_layoutBounds->X = xpos / 3.0f; + cc->_layoutBounds->Y = ypos / 3.0f; + cc->_layoutBounds->Width = 1.0f / 3.0f; + cc->_layoutBounds->Height = 1.0f / 3.0f; + } + } + else + { + CubismLogError("not supported mask count : %d", layoutCount); + + // 開発モードの場合は停止させる + CSM_ASSERT(0); + + // 引き続き実行する場合、 SetupShaderProgramでオーバーアクセスが発生するので仕方なく適当に入れておく + // もちろん描画結果はろくなことにならない + for (csmInt32 i = 0; i < layoutCount; i++) + { + CubismClippingContext* cc = _clippingContextListForMask[curClipIndex++]; + cc->_layoutChannelNo = 0; + cc->_layoutBounds->X = 0.0f; + cc->_layoutBounds->Y = 0.0f; + cc->_layoutBounds->Width = 1.0f; + cc->_layoutBounds->Height = 1.0f; + } + } + } +} + +CubismRenderer::CubismTextureColor* CubismClippingManager_Cocos2dx::GetChannelFlagAsColor(csmInt32 channelNo) +{ + return _channelColors[channelNo]; +} + +csmVector* CubismClippingManager_Cocos2dx::GetClippingContextListForDraw() +{ + return &_clippingContextListForDraw; +} + +void CubismClippingManager_Cocos2dx::SetClippingMaskBufferSize(csmInt32 size) +{ + _clippingMaskBufferSize = size; +} + +csmInt32 CubismClippingManager_Cocos2dx::GetClippingMaskBufferSize() const +{ + return _clippingMaskBufferSize; +} + +/********************************************************************************************************************* +* CubismClippingContext +********************************************************************************************************************/ +CubismClippingContext::CubismClippingContext(CubismClippingManager_Cocos2dx* manager, CubismModel& model, const csmInt32* clippingDrawableIndices, csmInt32 clipCount) +{ + _owner = manager; + + // クリップしている(=マスク用の)Drawableのインデックスリスト + _clippingIdList = clippingDrawableIndices; + + // マスクの数 + _clippingIdCount = clipCount; + + _layoutChannelNo = 0; + + _allClippedDrawRect = CSM_NEW csmRectF(); + _layoutBounds = CSM_NEW csmRectF(); + + _clippedDrawableIndexList = CSM_NEW csmVector(); + _clippingCommandBufferList = CSM_NEW csmVector; + + + for (csmUint32 i = 0; i < _clippingIdCount; ++i) + { + const csmInt32 clippingId = _clippingIdList[i]; + CubismCommandBuffer_Cocos2dx::DrawCommandBuffer* drawCommandBuffer = NULL; + const csmInt32 drawableVertexCount = model.GetDrawableVertexCount(clippingId); + const csmInt32 drawableVertexIndexCount = model.GetDrawableVertexIndexCount(clippingId); + const csmSizeInt vertexSize = sizeof(csmFloat32) * 2; + + + drawCommandBuffer = CSM_NEW CubismCommandBuffer_Cocos2dx::DrawCommandBuffer(); + drawCommandBuffer->GetCommandDraw()->GetCommand()->setDrawType(cocos2d::CustomCommand::DrawType::ELEMENT); + drawCommandBuffer->GetCommandDraw()->GetCommand()->setPrimitiveType(cocos2d::backend::PrimitiveType::TRIANGLE); + drawCommandBuffer->CreateVertexBuffer(vertexSize, drawableVertexCount * 2); // Vertices + UVs + drawCommandBuffer->CreateIndexBuffer(drawableVertexIndexCount); + + + _clippingCommandBufferList->PushBack(drawCommandBuffer); + } +} + +CubismClippingContext::~CubismClippingContext() +{ + if (_layoutBounds != NULL) + { + CSM_DELETE(_layoutBounds); + _layoutBounds = NULL; + } + + if (_allClippedDrawRect != NULL) + { + CSM_DELETE(_allClippedDrawRect); + _allClippedDrawRect = NULL; + } + + if (_clippedDrawableIndexList != NULL) + { + CSM_DELETE(_clippedDrawableIndexList); + _clippedDrawableIndexList = NULL; + } + + if (_clippingCommandBufferList != NULL) + { + for (csmUint32 i = 0; i < _clippingCommandBufferList->GetSize(); ++i) + { + CSM_DELETE(_clippingCommandBufferList->At(i)); + _clippingCommandBufferList->At(i) = NULL; + } + + CSM_DELETE(_clippingCommandBufferList); + _clippingCommandBufferList = NULL; + } +} + +void CubismClippingContext::AddClippedDrawable(csmInt32 drawableIndex) +{ + + _clippedDrawableIndexList->PushBack(drawableIndex); +} + +CubismClippingManager_Cocos2dx* CubismClippingContext::GetClippingManager() +{ + return _owner; +} + + + +/********************************************************************************************************************* +* CubismDrawProfile_OpenGL +********************************************************************************************************************/ +void CubismRendererProfile_Cocos2dx::Save() +{ + //-- push state -- + _lastScissorTest = GetCocos2dRenderer()->getScissorTest(); + _lastStencilTest = GetCocos2dRenderer()->getStencilTest(); + _lastDepthTest = GetCocos2dRenderer()->getDepthTest(); + _lastCullFace = GetCocos2dRenderer()->getCullMode(); + _lastWinding = GetCocos2dRenderer()->getWinding(); + + + // モデル描画直前のFBOとビューポートを保存 + _lastColorBuffer = GetCocos2dRenderer()->getColorAttachment(); + _lastDepthBuffer = GetCocos2dRenderer()->getDepthAttachment(); + _lastStencilBuffer = GetCocos2dRenderer()->getStencilAttachment(); + _lastRenderTargetFlag = GetCocos2dRenderer()->getRenderTargetFlag(); + _lastViewport = csmRectF(GetCocos2dRenderer()->getViewport().x, GetCocos2dRenderer()->getViewport().y, GetCocos2dRenderer()->getViewport().w, GetCocos2dRenderer()->getViewport().h); +} + +void CubismRendererProfile_Cocos2dx::Restore() +{ + GetCocos2dRenderer()->setScissorTest(_lastScissorTest); + GetCocos2dRenderer()->setStencilTest(_lastStencilTest); + GetCocos2dRenderer()->setDepthTest(_lastDepthTest); + GetCocos2dRenderer()->setCullMode(_lastCullFace); + GetCocos2dRenderer()->setWinding(_lastWinding); + + GetCocos2dRenderer()->setRenderTarget(_lastRenderTargetFlag, _lastColorBuffer, _lastDepthBuffer, _lastStencilBuffer); + GetCocos2dRenderer()->setViewPort(_lastViewport.X, _lastViewport.Y, _lastViewport.Width, _lastViewport.Height); +} + + +/********************************************************************************************************************* +* CubismShader_Cocos2dx +********************************************************************************************************************/ +namespace { + const csmInt32 ShaderCount = 19; ///< シェーダの数 = マスク生成用 + (通常 + 加算 + 乗算) * (マスク無 + マスク有 + マスク有反転 + マスク無の乗算済アルファ対応版 + マスク有の乗算済アルファ対応版 + マスク有反転の乗算済アルファ対応版) + CubismShader_Cocos2dx* s_instance; +} + +enum ShaderNames +{ + // SetupMask + ShaderNames_SetupMask, + + //Normal + ShaderNames_Normal, + ShaderNames_NormalMasked, + ShaderNames_NormalMaskedInverted, + ShaderNames_NormalPremultipliedAlpha, + ShaderNames_NormalMaskedPremultipliedAlpha, + ShaderNames_NormalMaskedInvertedPremultipliedAlpha, + + //Add + ShaderNames_Add, + ShaderNames_AddMasked, + ShaderNames_AddMaskedInverted, + ShaderNames_AddPremultipliedAlpha, + ShaderNames_AddMaskedPremultipliedAlpha, + ShaderNames_AddMaskedPremultipliedAlphaInverted, + + //Mult + ShaderNames_Mult, + ShaderNames_MultMasked, + ShaderNames_MultMaskedInverted, + ShaderNames_MultPremultipliedAlpha, + ShaderNames_MultMaskedPremultipliedAlpha, + ShaderNames_MultMaskedPremultipliedAlphaInverted, +}; + +void CubismShader_Cocos2dx::ReleaseShaderProgram() +{ + for (csmUint32 i = 0; i < _shaderSets.GetSize(); i++) + { + if (_shaderSets[i]->ShaderProgram) + { + CSM_DELETE(_shaderSets[i]); + } + } +} + +// SetupMask +static const csmChar* VertShaderSrcSetupMask = +#if defined(CC_PLATFORM_MOBILE) +#else + "#version 120\n" +#endif + "attribute vec2 a_position;" + "attribute vec2 a_texCoord;" + "varying vec2 v_texCoord;" + "varying vec4 v_myPos;" + "uniform mat4 u_clipMatrix;" + "void main()" + "{" + "vec4 pos = vec4(a_position.x, a_position.y, 0.0, 1.0);" + "gl_Position = u_clipMatrix * pos;" + "v_myPos = u_clipMatrix * pos;" + "v_texCoord = a_texCoord;" + "v_texCoord.y = 1.0 - v_texCoord.y;" + "}"; +static const csmChar* FragShaderSrcSetupMask = +#if defined(CC_PLATFORM_MOBILE) +#else +#endif + "varying vec2 v_texCoord;" + "varying vec4 v_myPos;" + "uniform sampler2D s_texture0;" + "uniform vec4 u_channelFlag;" + "uniform vec4 u_baseColor;" + "void main()" + "{" + "float isInside = " + " step(u_baseColor.x, v_myPos.x/v_myPos.w)" + "* step(u_baseColor.y, v_myPos.y/v_myPos.w)" + "* step(v_myPos.x/v_myPos.w, u_baseColor.z)" + "* step(v_myPos.y/v_myPos.w, u_baseColor.w);" + + "gl_FragColor = u_channelFlag * texture2D(s_texture0 , v_texCoord).a * isInside;" + "}"; +#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID +static const csmChar* FragShaderSrcSetupMaskTegra = + "#extension GL_NV_shader_framebuffer_fetch : enable\n" + "precision mediump float;" + "varying vec2 v_texCoord;" + "varying vec4 v_myPos;" + "uniform sampler2D s_texture0;" + "uniform vec4 u_channelFlag;" + "uniform vec4 u_baseColor;" + "void main()" + "{" + "float isInside = " + " step(u_baseColor.x, v_myPos.x/v_myPos.w)" + "* step(u_baseColor.y, v_myPos.y/v_myPos.w)" + "* step(v_myPos.x/v_myPos.w, u_baseColor.z)" + "* step(v_myPos.y/v_myPos.w, u_baseColor.w);" + + "gl_FragColor = u_channelFlag * texture2D(s_texture0 , v_texCoord).a * isInside;" + "}"; +#endif + +//----- バーテックスシェーダプログラム ----- +// Normal & Add & Mult 共通 +static const csmChar* VertShaderSrc = +#if defined(CC_PLATFORM_MOBILE) +#else + "#version 120\n" +#endif + "attribute vec2 a_position;" //v.vertex + "attribute vec2 a_texCoord;" //v.texcoord + "varying vec2 v_texCoord;" //v2f.texcoord + "uniform mat4 u_matrix;" + "void main()" + "{" + "vec4 pos = vec4(a_position.x, a_position.y, 0.0, 1.0);" + "gl_Position = u_matrix * pos;" + "v_texCoord = a_texCoord;" + "v_texCoord.y = 1.0 - v_texCoord.y;" + "}"; + +// Normal & Add & Mult 共通(クリッピングされたものの描画用) +static const csmChar* VertShaderSrcMasked = +#if defined(CC_PLATFORM_MOBILE) +#else + "#version 120\n" +#endif + "attribute vec2 a_position;" + "attribute vec2 a_texCoord;" + "varying vec2 v_texCoord;" + "varying vec4 v_clipPos;" + "uniform mat4 u_matrix;" + "uniform mat4 u_clipMatrix;" + "void main()" + "{" + "vec4 pos = vec4(a_position.x, a_position.y, 0.0, 1.0);" + "gl_Position = u_matrix * pos;" + "v_clipPos = u_clipMatrix * pos;" +#if defined(CC_USE_METAL) + "v_clipPos = vec4(v_clipPos.x, 1.0 - v_clipPos.y, v_clipPos.zw);" +#endif + "v_texCoord = a_texCoord;" + "v_texCoord.y = 1.0 - v_texCoord.y;" + "}"; + +//----- フラグメントシェーダプログラム ----- +// Normal & Add & Mult 共通 +static const csmChar* FragShaderSrc = +#if defined(CC_PLATFORM_MOBILE) +#else +#endif + "varying vec2 v_texCoord;" //v2f.texcoord + "uniform sampler2D s_texture0;" //_MainTex + "uniform vec4 u_baseColor;" //v2f.color + "void main()" + "{" + "vec4 color = texture2D(s_texture0 , v_texCoord) * u_baseColor;" + "gl_FragColor = vec4(color.rgb * color.a, color.a);" + "}"; +#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID +static const csmChar* FragShaderSrcTegra = + "#extension GL_NV_shader_framebuffer_fetch : enable\n" + "precision mediump float;" + "varying vec2 v_texCoord;" //v2f.texcoord + "uniform sampler2D s_texture0;" //_MainTex + "uniform vec4 u_baseColor;" //v2f.color + "void main()" + "{" + "vec4 color = texture2D(s_texture0 , v_texCoord) * u_baseColor;" + "gl_FragColor = vec4(color.rgb * color.a, color.a);" + "}"; +#endif + +// Normal & Add & Mult 共通 (PremultipliedAlpha) +static const csmChar* FragShaderSrcPremultipliedAlpha = +#if defined(CC_PLATFORM_MOBILE) +#else +#endif + "varying vec2 v_texCoord;" //v2f.texcoord + "uniform sampler2D s_texture0;" //_MainTex + "uniform vec4 u_baseColor;" //v2f.color + "void main()" + "{" + "gl_FragColor = texture2D(s_texture0 , v_texCoord) * u_baseColor;" + "}"; +#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID +static const csmChar* FragShaderSrcPremultipliedAlphaTegra = + "#extension GL_NV_shader_framebuffer_fetch : enable\n" + "precision mediump float;" + "varying vec2 v_texCoord;" //v2f.texcoord + "uniform sampler2D s_texture0;" //_MainTex + "uniform vec4 u_baseColor;" //v2f.color + "void main()" + "{" + "gl_FragColor = texture2D(s_texture0 , v_texCoord) * u_baseColor;" + "}"; +#endif + +// Normal & Add & Mult 共通(クリッピングされたものの描画用) +static const csmChar* FragShaderSrcMask = +#if defined(CC_PLATFORM_MOBILE) +#else +#endif + "varying vec2 v_texCoord;" + "varying vec4 v_clipPos;" + "uniform sampler2D s_texture0;" + "uniform sampler2D s_texture1;" + "uniform vec4 u_channelFlag;" + "uniform vec4 u_baseColor;" + "void main()" + "{" + "vec4 col_formask = texture2D(s_texture0 , v_texCoord) * u_baseColor;" + "col_formask.rgb = col_formask.rgb * col_formask.a ;" + "vec4 clipMask = (1.0 - texture2D(s_texture1, v_clipPos.xy / v_clipPos.w)) * u_channelFlag;" + "float maskVal = clipMask.r + clipMask.g + clipMask.b + clipMask.a;" + "col_formask = col_formask * maskVal;" + "gl_FragColor = col_formask;" + "}"; +#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID +static const csmChar* FragShaderSrcMaskTegra = + "#extension GL_NV_shader_framebuffer_fetch : enable\n" + "precision mediump float;" + "varying vec2 v_texCoord;" + "varying vec4 v_clipPos;" + "uniform sampler2D s_texture0;" + "uniform sampler2D s_texture1;" + "uniform vec4 u_channelFlag;" + "uniform vec4 u_baseColor;" + "void main()" + "{" + "vec4 col_formask = texture2D(s_texture0 , v_texCoord) * u_baseColor;" + "col_formask.rgb = col_formask.rgb * col_formask.a ;" + "vec4 clipMask = (1.0 - texture2D(s_texture1, v_clipPos.xy / v_clipPos.w)) * u_channelFlag;" + "float maskVal = clipMask.r + clipMask.g + clipMask.b + clipMask.a;" + "col_formask = col_formask * maskVal;" + "gl_FragColor = col_formask;" + "}"; +#endif + +// Normal & Add & Mult 共通(クリッピングされて反転使用の描画用) +static const csmChar* FragShaderSrcMaskInverted = +#if defined(CC_PLATFORM_MOBILE) +#else +#endif + "varying vec2 v_texCoord;" + "varying vec4 v_clipPos;" + "uniform sampler2D s_texture0;" + "uniform sampler2D s_texture1;" + "uniform vec4 u_channelFlag;" + "uniform vec4 u_baseColor;" + "void main()" + "{" + "vec4 col_formask = texture2D(s_texture0 , v_texCoord) * u_baseColor;" + "col_formask.rgb = col_formask.rgb * col_formask.a ;" + "vec4 clipMask = (1.0 - texture2D(s_texture1, v_clipPos.xy / v_clipPos.w)) * u_channelFlag;" + "float maskVal = clipMask.r + clipMask.g + clipMask.b + clipMask.a;" + "col_formask = col_formask * (1.0 - maskVal);" + "gl_FragColor = col_formask;" + "}"; +#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID +static const csmChar* FragShaderSrcMaskInvertedTegra = + "#extension GL_NV_shader_framebuffer_fetch : enable\n" + "precision mediump float;" + "varying vec2 v_texCoord;" + "varying vec4 v_clipPos;" + "uniform sampler2D s_texture0;" + "uniform sampler2D s_texture1;" + "uniform vec4 u_channelFlag;" + "uniform vec4 u_baseColor;" + "void main()" + "{" + "vec4 col_formask = texture2D(s_texture0 , v_texCoord) * u_baseColor;" + "col_formask.rgb = col_formask.rgb * col_formask.a ;" + "vec4 clipMask = (1.0 - texture2D(s_texture1, v_clipPos.xy / v_clipPos.w)) * u_channelFlag;" + "float maskVal = clipMask.r + clipMask.g + clipMask.b + clipMask.a;" + "col_formask = col_formask * (1.0 - maskVal);" + "gl_FragColor = col_formask;" + "}"; +#endif + +// Normal & Add & Mult 共通(クリッピングされたものの描画用、PremultipliedAlphaの場合) +static const csmChar* FragShaderSrcMaskPremultipliedAlpha = +#if defined(CC_PLATFORM_MOBILE) +#else +#endif + "varying vec2 v_texCoord;" + "varying vec4 v_clipPos;" + "uniform sampler2D s_texture0;" + "uniform sampler2D s_texture1;" + "uniform vec4 u_channelFlag;" + "uniform vec4 u_baseColor;" + "void main()" + "{" + "vec4 col_formask = texture2D(s_texture0 , v_texCoord) * u_baseColor;" + "vec4 clipMask = (1.0 - texture2D(s_texture1, v_clipPos.xy / v_clipPos.w)) * u_channelFlag;" + "float maskVal = clipMask.r + clipMask.g + clipMask.b + clipMask.a;" + "col_formask = col_formask * maskVal;" + "gl_FragColor = col_formask;" + "}"; +#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID +static const csmChar* FragShaderSrcMaskPremultipliedAlphaTegra = + "#extension GL_NV_shader_framebuffer_fetch : enable\n" + "precision mediump float;" + "varying vec2 v_texCoord;" + "varying vec4 v_clipPos;" + "uniform sampler2D s_texture0;" + "uniform sampler2D s_texture1;" + "uniform vec4 u_channelFlag;" + "uniform vec4 u_baseColor;" + "void main()" + "{" + "vec4 col_formask = texture2D(s_texture0 , v_texCoord) * u_baseColor;" + "vec4 clipMask = (1.0 - texture2D(s_texture1, v_clipPos.xy / v_clipPos.w)) * u_channelFlag;" + "float maskVal = clipMask.r + clipMask.g + clipMask.b + clipMask.a;" + "col_formask = col_formask * maskVal;" + "gl_FragColor = col_formask;" + "}"; +#endif + +// Normal & Add & Mult 共通(クリッピングされて反転使用の描画用、PremultipliedAlphaの場合) +static const csmChar* FragShaderSrcMaskInvertedPremultipliedAlpha = +#if defined(CC_PLATFORM_MOBILE) +#else +#endif + "varying vec2 v_texCoord;" + "varying vec4 v_clipPos;" + "uniform sampler2D s_texture0;" + "uniform sampler2D s_texture1;" + "uniform vec4 u_channelFlag;" + "uniform vec4 u_baseColor;" + "void main()" + "{" + "vec4 col_formask = texture2D(s_texture0 , v_texCoord) * u_baseColor;" + "vec4 clipMask = (1.0 - texture2D(s_texture1, v_clipPos.xy / v_clipPos.w)) * u_channelFlag;" + "float maskVal = clipMask.r + clipMask.g + clipMask.b + clipMask.a;" + "col_formask = col_formask * (1.0 - maskVal);" + "gl_FragColor = col_formask;" + "}"; +#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID +static const csmChar* FragShaderSrcMaskInvertedPremultipliedAlphaTegra = + "#extension GL_NV_shader_framebuffer_fetch : enable\n" + "precision mediump float;" + "varying vec2 v_texCoord;" + "varying vec4 v_clipPos;" + "uniform sampler2D s_texture0;" + "uniform sampler2D s_texture1;" + "uniform vec4 u_channelFlag;" + "uniform vec4 u_baseColor;" + "void main()" + "{" + "vec4 col_formask = texture2D(s_texture0 , v_texCoord) * u_baseColor;" + "vec4 clipMask = (1.0 - texture2D(s_texture1, v_clipPos.xy / v_clipPos.w)) * u_channelFlag;" + "float maskVal = clipMask.r + clipMask.g + clipMask.b + clipMask.a;" + "col_formask = col_formask * (1.0 - maskVal);" + "gl_FragColor = col_formask;" + "}"; +#endif + +CubismShader_Cocos2dx::CubismShader_Cocos2dx() +{ } + +CubismShader_Cocos2dx::~CubismShader_Cocos2dx() +{ + ReleaseShaderProgram(); +} + +CubismShader_Cocos2dx* CubismShader_Cocos2dx::GetInstance() +{ + if (s_instance == NULL) + { + s_instance = CSM_NEW CubismShader_Cocos2dx(); + } + return s_instance; +} + +void CubismShader_Cocos2dx::DeleteInstance() +{ + if (s_instance) + { + CSM_DELETE_SELF(CubismShader_Cocos2dx, s_instance); + s_instance = NULL; + } +} + +#ifdef CSM_TARGET_ANDROID_ES2 +csmBool CubismShader_Cocos2dx::s_extMode = false; +csmBool CubismShader_Cocos2dx::s_extPAMode = false; +void CubismShader_Cocos2dx::SetExtShaderMode(csmBool extMode, csmBool extPAMode) { + s_extMode = extMode; + s_extPAMode = extPAMode; +} +#endif + +void CubismShader_Cocos2dx::GenerateShaders() +{ + for (csmInt32 i = 0; i < ShaderCount; i++) + { + _shaderSets.PushBack(CSM_NEW CubismShaderSet()); + } + +#ifdef CSM_TARGET_ANDROID_ES2 + if (s_extMode) + { + _shaderSets[0]->ShaderProgram = LoadShaderProgram(VertShaderSrcSetupMask, FragShaderSrcSetupMaskTegra); + + _shaderSets[1]->ShaderProgram = LoadShaderProgram(VertShaderSrc, FragShaderSrcTegra); + _shaderSets[2]->ShaderProgram = LoadShaderProgram(VertShaderSrcMasked, FragShaderSrcMaskTegra); + _shaderSets[3]->ShaderProgram = LoadShaderProgram(VertShaderSrcMasked, FragShaderSrcMaskInvertedTegra); + _shaderSets[4]->ShaderProgram = LoadShaderProgram(VertShaderSrc, FragShaderSrcPremultipliedAlphaTegra); + _shaderSets[5]->ShaderProgram = LoadShaderProgram(VertShaderSrcMasked, FragShaderSrcMaskPremultipliedAlphaTegra); + _shaderSets[6]->ShaderProgram = LoadShaderProgram(VertShaderSrcMasked, FragShaderSrcMaskInvertedPremultipliedAlphaTegra); + } + else + { + _shaderSets[0]->ShaderProgram = LoadShaderProgram(VertShaderSrcSetupMask, FragShaderSrcSetupMask); + + _shaderSets[1]->ShaderProgram = LoadShaderProgram(VertShaderSrc, FragShaderSrc); + _shaderSets[2]->ShaderProgram = LoadShaderProgram(VertShaderSrcMasked, FragShaderSrcMask); + _shaderSets[3]->ShaderProgram = LoadShaderProgram(VertShaderSrcMasked, FragShaderSrcMaskInverted); + _shaderSets[4]->ShaderProgram = LoadShaderProgram(VertShaderSrc, FragShaderSrcPremultipliedAlpha); + _shaderSets[5]->ShaderProgram = LoadShaderProgram(VertShaderSrcMasked, FragShaderSrcMaskPremultipliedAlpha); + _shaderSets[6]->ShaderProgram = LoadShaderProgram(VertShaderSrcMasked, FragShaderSrcMaskInvertedPremultipliedAlpha); + } + + // 加算も通常と同じシェーダーを利用する + _shaderSets[7]->ShaderProgram = _shaderSets[1]->ShaderProgram; + _shaderSets[8]->ShaderProgram = _shaderSets[2]->ShaderProgram; + _shaderSets[9]->ShaderProgram = _shaderSets[3]->ShaderProgram; + _shaderSets[10]->ShaderProgram = _shaderSets[4]->ShaderProgram; + _shaderSets[11]->ShaderProgram = _shaderSets[5]->ShaderProgram; + _shaderSets[12]->ShaderProgram = _shaderSets[6]->ShaderProgram; + + // 乗算も通常と同じシェーダーを利用する + _shaderSets[13]->ShaderProgram = _shaderSets[1]->ShaderProgram; + _shaderSets[14]->ShaderProgram = _shaderSets[2]->ShaderProgram; + _shaderSets[15]->ShaderProgram = _shaderSets[3]->ShaderProgram; + _shaderSets[16]->ShaderProgram = _shaderSets[4]->ShaderProgram; + _shaderSets[17]->ShaderProgram = _shaderSets[5]->ShaderProgram; + _shaderSets[18]->ShaderProgram = _shaderSets[6]->ShaderProgram; + +#else + + _shaderSets[0]->ShaderProgram = LoadShaderProgram(VertShaderSrcSetupMask, FragShaderSrcSetupMask); + + _shaderSets[1]->ShaderProgram = LoadShaderProgram(VertShaderSrc, FragShaderSrc); + _shaderSets[2]->ShaderProgram = LoadShaderProgram(VertShaderSrcMasked, FragShaderSrcMask); + _shaderSets[3]->ShaderProgram = LoadShaderProgram(VertShaderSrcMasked, FragShaderSrcMaskInverted); + _shaderSets[4]->ShaderProgram = LoadShaderProgram(VertShaderSrc, FragShaderSrcPremultipliedAlpha); + _shaderSets[5]->ShaderProgram = LoadShaderProgram(VertShaderSrcMasked, FragShaderSrcMaskPremultipliedAlpha); + _shaderSets[6]->ShaderProgram = LoadShaderProgram(VertShaderSrcMasked, FragShaderSrcMaskInvertedPremultipliedAlpha); + + + + // 加算も通常と同じシェーダーを利用する + _shaderSets[7]->ShaderProgram = _shaderSets[1]->ShaderProgram; + _shaderSets[8]->ShaderProgram = _shaderSets[2]->ShaderProgram; + _shaderSets[9]->ShaderProgram = _shaderSets[3]->ShaderProgram; + _shaderSets[10]->ShaderProgram = _shaderSets[4]->ShaderProgram; + _shaderSets[11]->ShaderProgram = _shaderSets[5]->ShaderProgram; + _shaderSets[12]->ShaderProgram = _shaderSets[6]->ShaderProgram; + + + // 乗算も通常と同じシェーダーを利用する + _shaderSets[13]->ShaderProgram = _shaderSets[1]->ShaderProgram; + _shaderSets[14]->ShaderProgram = _shaderSets[2]->ShaderProgram; + _shaderSets[15]->ShaderProgram = _shaderSets[3]->ShaderProgram; + _shaderSets[16]->ShaderProgram = _shaderSets[4]->ShaderProgram; + _shaderSets[17]->ShaderProgram = _shaderSets[5]->ShaderProgram; + _shaderSets[18]->ShaderProgram = _shaderSets[6]->ShaderProgram; +#endif + + // SetupMask + _shaderSets[0]->AttributePositionLocation = _shaderSets[0]->ShaderProgram->getAttributeLocation("a_position"); + _shaderSets[0]->AttributeTexCoordLocation = _shaderSets[0]->ShaderProgram->getAttributeLocation("a_texCoord"); + _shaderSets[0]->SamplerTexture0Location = _shaderSets[0]->ShaderProgram->getUniformLocation("s_texture0"); + _shaderSets[0]->UniformClipMatrixLocation = _shaderSets[0]->ShaderProgram->getUniformLocation("u_clipMatrix"); + _shaderSets[0]->UnifromChannelFlagLocation = _shaderSets[0]->ShaderProgram->getUniformLocation("u_channelFlag"); + _shaderSets[0]->UniformBaseColorLocation = _shaderSets[0]->ShaderProgram->getUniformLocation("u_baseColor"); + + // 通常 + _shaderSets[1]->AttributePositionLocation = _shaderSets[1]->ShaderProgram->getAttributeLocation("a_position"); + _shaderSets[1]->AttributeTexCoordLocation = _shaderSets[1]->ShaderProgram->getAttributeLocation("a_texCoord"); + _shaderSets[1]->SamplerTexture0Location = _shaderSets[1]->ShaderProgram->getUniformLocation("s_texture0"); + _shaderSets[1]->UniformMatrixLocation = _shaderSets[1]->ShaderProgram->getUniformLocation("u_matrix"); + _shaderSets[1]->UniformBaseColorLocation = _shaderSets[1]->ShaderProgram->getUniformLocation("u_baseColor"); + + // 通常(クリッピング) + _shaderSets[2]->AttributePositionLocation = _shaderSets[2]->ShaderProgram->getAttributeLocation("a_position"); + _shaderSets[2]->AttributeTexCoordLocation = _shaderSets[2]->ShaderProgram->getAttributeLocation("a_texCoord"); + _shaderSets[2]->SamplerTexture0Location = _shaderSets[2]->ShaderProgram->getUniformLocation("s_texture0"); + _shaderSets[2]->SamplerTexture1Location = _shaderSets[2]->ShaderProgram->getUniformLocation("s_texture1"); + _shaderSets[2]->UniformMatrixLocation = _shaderSets[2]->ShaderProgram->getUniformLocation("u_matrix"); + _shaderSets[2]->UniformClipMatrixLocation = _shaderSets[2]->ShaderProgram->getUniformLocation("u_clipMatrix"); + _shaderSets[2]->UnifromChannelFlagLocation = _shaderSets[2]->ShaderProgram->getUniformLocation("u_channelFlag"); + _shaderSets[2]->UniformBaseColorLocation = _shaderSets[2]->ShaderProgram->getUniformLocation("u_baseColor"); + + // 通常(クリッピング・反転) + _shaderSets[3]->AttributePositionLocation = _shaderSets[3]->ShaderProgram->getAttributeLocation("a_position"); + _shaderSets[3]->AttributeTexCoordLocation = _shaderSets[3]->ShaderProgram->getAttributeLocation("a_texCoord"); + _shaderSets[3]->SamplerTexture0Location = _shaderSets[3]->ShaderProgram->getUniformLocation("s_texture0"); + _shaderSets[3]->SamplerTexture1Location = _shaderSets[3]->ShaderProgram->getUniformLocation("s_texture1"); + _shaderSets[3]->UniformMatrixLocation = _shaderSets[3]->ShaderProgram->getUniformLocation("u_matrix"); + _shaderSets[3]->UniformClipMatrixLocation = _shaderSets[3]->ShaderProgram->getUniformLocation("u_clipMatrix"); + _shaderSets[3]->UnifromChannelFlagLocation = _shaderSets[3]->ShaderProgram->getUniformLocation("u_channelFlag"); + _shaderSets[3]->UniformBaseColorLocation = _shaderSets[3]->ShaderProgram->getUniformLocation("u_baseColor"); + + // 通常(PremultipliedAlpha) + _shaderSets[4]->AttributePositionLocation = _shaderSets[4]->ShaderProgram->getAttributeLocation("a_position"); + _shaderSets[4]->AttributeTexCoordLocation = _shaderSets[4]->ShaderProgram->getAttributeLocation("a_texCoord"); + _shaderSets[4]->SamplerTexture0Location = _shaderSets[4]->ShaderProgram->getUniformLocation("s_texture0"); + _shaderSets[4]->UniformMatrixLocation = _shaderSets[4]->ShaderProgram->getUniformLocation("u_matrix"); + _shaderSets[4]->UniformBaseColorLocation = _shaderSets[4]->ShaderProgram->getUniformLocation("u_baseColor"); + + // 通常(クリッピング、PremultipliedAlpha) + _shaderSets[5]->AttributePositionLocation = _shaderSets[5]->ShaderProgram->getAttributeLocation("a_position"); + _shaderSets[5]->AttributeTexCoordLocation = _shaderSets[5]->ShaderProgram->getAttributeLocation("a_texCoord"); + _shaderSets[5]->SamplerTexture0Location = _shaderSets[5]->ShaderProgram->getUniformLocation("s_texture0"); + _shaderSets[5]->SamplerTexture1Location = _shaderSets[5]->ShaderProgram->getUniformLocation("s_texture1"); + _shaderSets[5]->UniformMatrixLocation = _shaderSets[5]->ShaderProgram->getUniformLocation("u_matrix"); + _shaderSets[5]->UniformClipMatrixLocation = _shaderSets[5]->ShaderProgram->getUniformLocation("u_clipMatrix"); + _shaderSets[5]->UnifromChannelFlagLocation = _shaderSets[5]->ShaderProgram->getUniformLocation("u_channelFlag"); + _shaderSets[5]->UniformBaseColorLocation = _shaderSets[5]->ShaderProgram->getUniformLocation("u_baseColor"); + + // 通常(クリッピング・反転、PremultipliedAlpha) + _shaderSets[6]->AttributePositionLocation = _shaderSets[6]->ShaderProgram->getAttributeLocation("a_position"); + _shaderSets[6]->AttributeTexCoordLocation = _shaderSets[6]->ShaderProgram->getAttributeLocation("a_texCoord"); + _shaderSets[6]->SamplerTexture0Location = _shaderSets[6]->ShaderProgram->getUniformLocation("s_texture0"); + _shaderSets[6]->SamplerTexture1Location = _shaderSets[6]->ShaderProgram->getUniformLocation("s_texture1"); + _shaderSets[6]->UniformMatrixLocation = _shaderSets[6]->ShaderProgram->getUniformLocation("u_matrix"); + _shaderSets[6]->UniformClipMatrixLocation = _shaderSets[6]->ShaderProgram->getUniformLocation("u_clipMatrix"); + _shaderSets[6]->UnifromChannelFlagLocation = _shaderSets[6]->ShaderProgram->getUniformLocation("u_channelFlag"); + _shaderSets[6]->UniformBaseColorLocation = _shaderSets[6]->ShaderProgram->getUniformLocation("u_baseColor"); + + // 加算 + _shaderSets[7]->AttributePositionLocation = _shaderSets[7]->ShaderProgram->getAttributeLocation("a_position"); + _shaderSets[7]->AttributeTexCoordLocation = _shaderSets[7]->ShaderProgram->getAttributeLocation("a_texCoord"); + _shaderSets[7]->SamplerTexture0Location = _shaderSets[7]->ShaderProgram->getUniformLocation("s_texture0"); + _shaderSets[7]->UniformMatrixLocation = _shaderSets[7]->ShaderProgram->getUniformLocation("u_matrix"); + _shaderSets[7]->UniformBaseColorLocation = _shaderSets[7]->ShaderProgram->getUniformLocation("u_baseColor"); + + // 加算(クリッピング) + _shaderSets[8]->AttributePositionLocation = _shaderSets[8]->ShaderProgram->getAttributeLocation("a_position"); + _shaderSets[8]->AttributeTexCoordLocation = _shaderSets[8]->ShaderProgram->getAttributeLocation("a_texCoord"); + _shaderSets[8]->SamplerTexture0Location = _shaderSets[8]->ShaderProgram->getUniformLocation("s_texture0"); + _shaderSets[8]->SamplerTexture1Location = _shaderSets[8]->ShaderProgram->getUniformLocation("s_texture1"); + _shaderSets[8]->UniformMatrixLocation = _shaderSets[8]->ShaderProgram->getUniformLocation("u_matrix"); + _shaderSets[8]->UniformClipMatrixLocation = _shaderSets[8]->ShaderProgram->getUniformLocation("u_clipMatrix"); + _shaderSets[8]->UnifromChannelFlagLocation = _shaderSets[8]->ShaderProgram->getUniformLocation("u_channelFlag"); + _shaderSets[8]->UniformBaseColorLocation = _shaderSets[8]->ShaderProgram->getUniformLocation("u_baseColor"); + + // 加算(クリッピング・反転) + _shaderSets[9]->AttributePositionLocation = _shaderSets[9]->ShaderProgram->getAttributeLocation("a_position"); + _shaderSets[9]->AttributeTexCoordLocation = _shaderSets[9]->ShaderProgram->getAttributeLocation("a_texCoord"); + _shaderSets[9]->SamplerTexture0Location = _shaderSets[9]->ShaderProgram->getUniformLocation("s_texture0"); + _shaderSets[9]->SamplerTexture1Location = _shaderSets[9]->ShaderProgram->getUniformLocation("s_texture1"); + _shaderSets[9]->UniformMatrixLocation = _shaderSets[9]->ShaderProgram->getUniformLocation("u_matrix"); + _shaderSets[9]->UniformClipMatrixLocation = _shaderSets[9]->ShaderProgram->getUniformLocation("u_clipMatrix"); + _shaderSets[9]->UnifromChannelFlagLocation = _shaderSets[9]->ShaderProgram->getUniformLocation("u_channelFlag"); + _shaderSets[9]->UniformBaseColorLocation = _shaderSets[9]->ShaderProgram->getUniformLocation("u_baseColor"); + + // 加算(PremultipliedAlpha) + _shaderSets[10]->AttributePositionLocation = _shaderSets[10]->ShaderProgram->getAttributeLocation("a_position"); + _shaderSets[10]->AttributeTexCoordLocation = _shaderSets[10]->ShaderProgram->getAttributeLocation("a_texCoord"); + _shaderSets[10]->SamplerTexture0Location = _shaderSets[10]->ShaderProgram->getUniformLocation("s_texture0"); + _shaderSets[10]->UniformMatrixLocation = _shaderSets[10]->ShaderProgram->getUniformLocation("u_matrix"); + _shaderSets[10]->UniformBaseColorLocation = _shaderSets[10]->ShaderProgram->getUniformLocation("u_baseColor"); + + // 加算(クリッピング、PremultipliedAlpha) + _shaderSets[11]->AttributePositionLocation = _shaderSets[11]->ShaderProgram->getAttributeLocation("a_position"); + _shaderSets[11]->AttributeTexCoordLocation = _shaderSets[11]->ShaderProgram->getAttributeLocation("a_texCoord"); + _shaderSets[11]->SamplerTexture0Location = _shaderSets[11]->ShaderProgram->getUniformLocation("s_texture0"); + _shaderSets[11]->SamplerTexture1Location = _shaderSets[11]->ShaderProgram->getUniformLocation("s_texture1"); + _shaderSets[11]->UniformMatrixLocation = _shaderSets[11]->ShaderProgram->getUniformLocation("u_matrix"); + _shaderSets[11]->UniformClipMatrixLocation = _shaderSets[11]->ShaderProgram->getUniformLocation("u_clipMatrix"); + _shaderSets[11]->UnifromChannelFlagLocation = _shaderSets[11]->ShaderProgram->getUniformLocation("u_channelFlag"); + _shaderSets[11]->UniformBaseColorLocation = _shaderSets[11]->ShaderProgram->getUniformLocation("u_baseColor"); + + // 加算(クリッピング・反転、PremultipliedAlpha) + _shaderSets[12]->AttributePositionLocation = _shaderSets[12]->ShaderProgram->getAttributeLocation("a_position"); + _shaderSets[12]->AttributeTexCoordLocation = _shaderSets[12]->ShaderProgram->getAttributeLocation("a_texCoord"); + _shaderSets[12]->SamplerTexture0Location = _shaderSets[12]->ShaderProgram->getUniformLocation("s_texture0"); + _shaderSets[12]->SamplerTexture1Location = _shaderSets[12]->ShaderProgram->getUniformLocation("s_texture1"); + _shaderSets[12]->UniformMatrixLocation = _shaderSets[12]->ShaderProgram->getUniformLocation("u_matrix"); + _shaderSets[12]->UniformClipMatrixLocation = _shaderSets[12]->ShaderProgram->getUniformLocation("u_clipMatrix"); + _shaderSets[12]->UnifromChannelFlagLocation = _shaderSets[12]->ShaderProgram->getUniformLocation("u_channelFlag"); + _shaderSets[12]->UniformBaseColorLocation = _shaderSets[12]->ShaderProgram->getUniformLocation("u_baseColor"); + + // 乗算 + _shaderSets[13]->AttributePositionLocation = _shaderSets[13]->ShaderProgram->getAttributeLocation("a_position"); + _shaderSets[13]->AttributeTexCoordLocation = _shaderSets[13]->ShaderProgram->getAttributeLocation("a_texCoord"); + _shaderSets[13]->SamplerTexture0Location = _shaderSets[13]->ShaderProgram->getUniformLocation("s_texture0"); + _shaderSets[13]->UniformMatrixLocation = _shaderSets[13]->ShaderProgram->getUniformLocation("u_matrix"); + _shaderSets[13]->UniformBaseColorLocation = _shaderSets[13]->ShaderProgram->getUniformLocation("u_baseColor"); + + // 乗算(クリッピング) + _shaderSets[14]->AttributePositionLocation = _shaderSets[14]->ShaderProgram->getAttributeLocation("a_position"); + _shaderSets[14]->AttributeTexCoordLocation = _shaderSets[14]->ShaderProgram->getAttributeLocation("a_texCoord"); + _shaderSets[14]->SamplerTexture0Location = _shaderSets[14]->ShaderProgram->getUniformLocation("s_texture0"); + _shaderSets[14]->SamplerTexture1Location = _shaderSets[14]->ShaderProgram->getUniformLocation("s_texture1"); + _shaderSets[14]->UniformMatrixLocation = _shaderSets[14]->ShaderProgram->getUniformLocation("u_matrix"); + _shaderSets[14]->UniformClipMatrixLocation = _shaderSets[14]->ShaderProgram->getUniformLocation("u_clipMatrix"); + _shaderSets[14]->UnifromChannelFlagLocation = _shaderSets[14]->ShaderProgram->getUniformLocation("u_channelFlag"); + _shaderSets[14]->UniformBaseColorLocation = _shaderSets[14]->ShaderProgram->getUniformLocation("u_baseColor"); + + // 乗算(クリッピング・反転) + _shaderSets[15]->AttributePositionLocation = _shaderSets[15]->ShaderProgram->getAttributeLocation("a_position"); + _shaderSets[15]->AttributeTexCoordLocation = _shaderSets[15]->ShaderProgram->getAttributeLocation("a_texCoord"); + _shaderSets[15]->SamplerTexture0Location = _shaderSets[15]->ShaderProgram->getUniformLocation("s_texture0"); + _shaderSets[15]->SamplerTexture1Location = _shaderSets[15]->ShaderProgram->getUniformLocation("s_texture1"); + _shaderSets[15]->UniformMatrixLocation = _shaderSets[15]->ShaderProgram->getUniformLocation("u_matrix"); + _shaderSets[15]->UniformClipMatrixLocation = _shaderSets[15]->ShaderProgram->getUniformLocation("u_clipMatrix"); + _shaderSets[15]->UnifromChannelFlagLocation = _shaderSets[15]->ShaderProgram->getUniformLocation("u_channelFlag"); + _shaderSets[15]->UniformBaseColorLocation = _shaderSets[15]->ShaderProgram->getUniformLocation("u_baseColor"); + + // 乗算(PremultipliedAlpha) + _shaderSets[16]->AttributePositionLocation = _shaderSets[16]->ShaderProgram->getAttributeLocation( "a_position"); + _shaderSets[16]->AttributeTexCoordLocation = _shaderSets[16]->ShaderProgram->getAttributeLocation("a_texCoord"); + _shaderSets[16]->SamplerTexture0Location = _shaderSets[16]->ShaderProgram->getUniformLocation("s_texture0"); + _shaderSets[16]->UniformMatrixLocation = _shaderSets[16]->ShaderProgram->getUniformLocation("u_matrix"); + _shaderSets[16]->UniformBaseColorLocation = _shaderSets[16]->ShaderProgram->getUniformLocation("u_baseColor"); + + // 乗算(クリッピング、PremultipliedAlpha) + _shaderSets[17]->AttributePositionLocation = _shaderSets[17]->ShaderProgram->getAttributeLocation("a_position"); + _shaderSets[17]->AttributeTexCoordLocation = _shaderSets[17]->ShaderProgram->getAttributeLocation("a_texCoord"); + _shaderSets[17]->SamplerTexture0Location = _shaderSets[17]->ShaderProgram->getUniformLocation("s_texture0"); + _shaderSets[17]->SamplerTexture1Location = _shaderSets[17]->ShaderProgram->getUniformLocation("s_texture1"); + _shaderSets[17]->UniformMatrixLocation = _shaderSets[17]->ShaderProgram->getUniformLocation("u_matrix"); + _shaderSets[17]->UniformClipMatrixLocation = _shaderSets[17]->ShaderProgram->getUniformLocation("u_clipMatrix"); + _shaderSets[17]->UnifromChannelFlagLocation = _shaderSets[17]->ShaderProgram->getUniformLocation("u_channelFlag"); + _shaderSets[17]->UniformBaseColorLocation = _shaderSets[17]->ShaderProgram->getUniformLocation("u_baseColor"); + + // 乗算(クリッピング・反転、PremultipliedAlpha) + _shaderSets[18]->AttributePositionLocation = _shaderSets[18]->ShaderProgram->getAttributeLocation("a_position"); + _shaderSets[18]->AttributeTexCoordLocation = _shaderSets[18]->ShaderProgram->getAttributeLocation("a_texCoord"); + _shaderSets[18]->SamplerTexture0Location = _shaderSets[18]->ShaderProgram->getUniformLocation("s_texture0"); + _shaderSets[18]->SamplerTexture1Location = _shaderSets[18]->ShaderProgram->getUniformLocation("s_texture1"); + _shaderSets[18]->UniformMatrixLocation = _shaderSets[18]->ShaderProgram->getUniformLocation("u_matrix"); + _shaderSets[18]->UniformClipMatrixLocation = _shaderSets[18]->ShaderProgram->getUniformLocation("u_clipMatrix"); + _shaderSets[18]->UnifromChannelFlagLocation = _shaderSets[18]->ShaderProgram->getUniformLocation("u_channelFlag"); + _shaderSets[18]->UniformBaseColorLocation = _shaderSets[18]->ShaderProgram->getUniformLocation("u_baseColor"); +} + +void CubismShader_Cocos2dx::SetupShaderProgram(CubismCommandBuffer_Cocos2dx::DrawCommandBuffer::DrawCommand* drawCommand, CubismRenderer_Cocos2dx* renderer, cocos2d::Texture2D* texture + , csmInt32 vertexCount, csmFloat32* vertexArray + , csmFloat32* uvArray, csmFloat32 opacity + , CubismRenderer::CubismBlendMode colorBlendMode + , CubismRenderer::CubismTextureColor baseColor + , csmBool isPremultipliedAlpha, CubismMatrix44 matrix4x4 + , csmBool invertedMask) +{ + if (_shaderSets.GetSize() == 0) + { + GenerateShaders(); + } + + cocos2d::backend::BlendDescriptor* blendDescriptor = drawCommand->GetBlendDescriptor(); + cocos2d::PipelineDescriptor* pipelineDescriptor = drawCommand->GetPipelineDescriptor(); + + cocos2d::backend::ProgramState* programState = pipelineDescriptor->programState; + + if (renderer->GetClippingContextBufferForMask() != NULL) // マスク生成時 + { + CubismShaderSet* shaderSet = _shaderSets[ShaderNames_SetupMask]; + + if (!programState) + { + programState = new cocos2d::backend::ProgramState(shaderSet->ShaderProgram); + } + + + //テクスチャ設定 + programState->setTexture(shaderSet->SamplerTexture0Location, 0, texture->getBackendTexture()); + + // 頂点配列の設定 + programState->getVertexLayout()->setAttribute("a_position", shaderSet->AttributePositionLocation, cocos2d::backend::VertexFormat::FLOAT2, 0, false); + // テクスチャ頂点の設定 + programState->getVertexLayout()->setAttribute("a_texCoord", shaderSet->AttributeTexCoordLocation, cocos2d::backend::VertexFormat::FLOAT2, sizeof(csmFloat32) * 2, false); + + // チャンネル + const csmInt32 channelNo = renderer->GetClippingContextBufferForMask()->_layoutChannelNo; + CubismRenderer::CubismTextureColor* colorChannel = renderer->GetClippingContextBufferForMask()->GetClippingManager()->GetChannelFlagAsColor(channelNo); + csmFloat32 colorFlag[4] = { colorChannel->R, colorChannel->G, colorChannel->B, colorChannel->A }; + programState->setUniform(shaderSet->UnifromChannelFlagLocation, colorFlag, sizeof(float) * 4); + + programState->setUniform(shaderSet->UniformClipMatrixLocation, + renderer->GetClippingContextBufferForMask()->_matrixForMask.GetArray(), + sizeof(float) * 16); + + csmRectF* rect = renderer->GetClippingContextBufferForMask()->_layoutBounds; + + csmFloat32 base[4] = { rect->X * 2.0f - 1.0f, + rect->Y * 2.0f - 1.0f, + rect->GetRight() * 2.0f - 1.0f, + rect->GetBottom() * 2.0f - 1.0f }; + programState->setUniform(shaderSet->UniformBaseColorLocation, base, sizeof(float) * 4); + + blendDescriptor->sourceRGBBlendFactor = cocos2d::backend::BlendFactor::ZERO; + blendDescriptor->destinationRGBBlendFactor = cocos2d::backend::BlendFactor::ONE_MINUS_SRC_COLOR; + blendDescriptor->sourceAlphaBlendFactor = cocos2d::backend::BlendFactor::ZERO; + blendDescriptor->destinationAlphaBlendFactor = cocos2d::backend::BlendFactor::ONE_MINUS_SRC_ALPHA; + } + else // マスク生成以外の場合 + { + const csmBool masked = renderer->GetClippingContextBufferForDraw() != NULL; // この描画オブジェクトはマスク対象か + const csmInt32 offset = (masked ? ( invertedMask ? 2 : 1 ) : 0) + (isPremultipliedAlpha ? 3 : 0); + + CubismShaderSet* shaderSet; + switch (colorBlendMode) + { + case CubismRenderer::CubismBlendMode_Normal: + default: + shaderSet = _shaderSets[ShaderNames_Normal + offset]; + blendDescriptor->sourceRGBBlendFactor = cocos2d::backend::BlendFactor::ONE; + blendDescriptor->destinationRGBBlendFactor = cocos2d::backend::BlendFactor::ONE_MINUS_SRC_ALPHA; + blendDescriptor->sourceAlphaBlendFactor = cocos2d::backend::BlendFactor::ONE; + blendDescriptor->destinationAlphaBlendFactor = cocos2d::backend::BlendFactor::ONE_MINUS_SRC_ALPHA; + break; + + case CubismRenderer::CubismBlendMode_Additive: + shaderSet = _shaderSets[ShaderNames_Add + offset]; + blendDescriptor->sourceRGBBlendFactor = cocos2d::backend::BlendFactor::ONE; + blendDescriptor->destinationRGBBlendFactor = cocos2d::backend::BlendFactor::ONE; + blendDescriptor->sourceAlphaBlendFactor = cocos2d::backend::BlendFactor::ZERO; + blendDescriptor->destinationAlphaBlendFactor = cocos2d::backend::BlendFactor::ONE; + break; + + case CubismRenderer::CubismBlendMode_Multiplicative: + shaderSet = _shaderSets[ShaderNames_Mult + offset]; + blendDescriptor->sourceRGBBlendFactor = cocos2d::backend::BlendFactor::DST_COLOR; + blendDescriptor->destinationRGBBlendFactor = cocos2d::backend::BlendFactor::ONE_MINUS_SRC_ALPHA; + blendDescriptor->sourceAlphaBlendFactor = cocos2d::backend::BlendFactor::ZERO; + blendDescriptor->destinationAlphaBlendFactor = cocos2d::backend::BlendFactor::ONE; + break; + } + + if (!programState) + { + programState = new cocos2d::backend::ProgramState(shaderSet->ShaderProgram); + } + + // 頂点配列の設定 + programState->getVertexLayout()->setAttribute("a_position", shaderSet->AttributePositionLocation, cocos2d::backend::VertexFormat::FLOAT2, 0, false); + // テクスチャ頂点の設定 + programState->getVertexLayout()->setAttribute("a_texCoord", shaderSet->AttributeTexCoordLocation, cocos2d::backend::VertexFormat::FLOAT2, sizeof(csmFloat32) * 2, false); + + if (masked) + { + // frameBufferに書かれたテクスチャ + cocos2d::Texture2D* tex = renderer->_offscreenFrameBuffer.GetColorBuffer(); + + programState->setTexture(shaderSet->SamplerTexture1Location, 1, tex->getBackendTexture()); + + // View座標をClippingContextの座標に変換するための行列を設定 + programState->setUniform(shaderSet->UniformClipMatrixLocation, + renderer->GetClippingContextBufferForDraw()->_matrixForDraw.GetArray(), + sizeof(float) * 16); + + // 使用するカラーチャンネルを設定 + const csmInt32 channelNo = renderer->GetClippingContextBufferForDraw()->_layoutChannelNo; + CubismRenderer::CubismTextureColor* colorChannel = renderer->GetClippingContextBufferForDraw()->GetClippingManager()->GetChannelFlagAsColor(channelNo); + csmFloat32 colorFlag[4] = { colorChannel->R, colorChannel->G, colorChannel->B, colorChannel->A }; + programState->setUniform(shaderSet->UnifromChannelFlagLocation, colorFlag, sizeof(float) * 4); + } + + //テクスチャ設定 + programState->setTexture(shaderSet->SamplerTexture0Location, 0, texture->getBackendTexture()); + + //座標変換 + programState->setUniform(shaderSet->UniformMatrixLocation, matrix4x4.GetArray(), sizeof(float) * 16); + + csmFloat32 base[4] = { baseColor.R, baseColor.G, baseColor.B, baseColor.A }; + programState->setUniform(shaderSet->UniformBaseColorLocation, base, sizeof(float) * 4); + } + + programState->getVertexLayout()->setLayout(sizeof(csmFloat32) * 4); + blendDescriptor->blendEnabled = true; + pipelineDescriptor->programState = programState; +} + +cocos2d::backend::Program* CubismShader_Cocos2dx::LoadShaderProgram(const csmChar* vertShaderSrc, const csmChar* fragShaderSrc) +{ + // cocos2dx対応 + // Create shader program. + return cocos2d::backend::Device::getInstance()->newProgram(vertShaderSrc, fragShaderSrc); +} + +/********************************************************************************************************************* + * CubismRenderer_Cocos2dx + ********************************************************************************************************************/ + +#ifdef CSM_TARGET_ANDROID_ES2 +void CubismRenderer_Cocos2dx::SetExtShaderMode(csmBool extMode, csmBool extPAMode) +{ + CubismShader_Cocos2dx::SetExtShaderMode(extMode, extPAMode); + CubismShader_Cocos2dx::DeleteInstance(); +} + +void CubismRenderer_Cocos2dx::ReloadShader() +{ + CubismShader_Cocos2dx::DeleteInstance(); +} +#endif + +CubismRenderer* CubismRenderer::Create() +{ + return CSM_NEW CubismRenderer_Cocos2dx(); +} + +void CubismRenderer::StaticRelease() +{ + CubismRenderer_Cocos2dx::DoStaticRelease(); +} + +CubismRenderer_Cocos2dx::CubismRenderer_Cocos2dx() : _clippingManager(NULL) + , _clippingContextBufferForMask(NULL) + , _clippingContextBufferForDraw(NULL) +{ + // テクスチャ対応マップの容量を確保しておく. + _textures.PrepareCapacity(32, true); +} + +CubismRenderer_Cocos2dx::~CubismRenderer_Cocos2dx() +{ + CSM_DELETE_SELF(CubismClippingManager_Cocos2dx, _clippingManager); +} + +void CubismRenderer_Cocos2dx::DoStaticRelease() +{ +#ifdef CSM_TARGET_WINGL + s_isInitializeGlFunctionsSuccess = false; ///< 初期化が完了したかどうか。trueなら初期化完了 + s_isFirstInitializeGlFunctions = true; ///< 最初の初期化実行かどうか。trueなら最初の初期化実行 +#endif + CubismShader_Cocos2dx::DeleteInstance(); +} + +void CubismRenderer_Cocos2dx::Initialize(CubismModel* model) +{ + if (model->IsUsingMasking()) + { + _clippingManager = CSM_NEW CubismClippingManager_Cocos2dx(); //クリッピングマスク・バッファ前処理方式を初期化 + _clippingManager->Initialize( + *model, + model->GetDrawableCount(), + model->GetDrawableMasks(), + model->GetDrawableMaskCounts() + ); + + _offscreenFrameBuffer.CreateOffscreenFrame(_clippingManager->GetClippingMaskBufferSize(), _clippingManager->GetClippingMaskBufferSize()); + } + + _sortedDrawableIndexList.Resize(model->GetDrawableCount(), 0); + + _drawableDrawCommandBuffer.Resize(model->GetDrawableCount()); + + for (csmInt32 i = 0; i < _drawableDrawCommandBuffer.GetSize(); ++i) + { + const csmInt32 drawableVertexCount = model->GetDrawableVertexCount(i); + const csmInt32 drawableVertexIndexCount = model->GetDrawableVertexIndexCount(i); + const csmSizeInt vertexSize = sizeof(csmFloat32) * 2; + + _drawableDrawCommandBuffer[i] = CSM_NEW CubismCommandBuffer_Cocos2dx::DrawCommandBuffer(); + _drawableDrawCommandBuffer[i]->GetCommandDraw()->GetCommand()->setDrawType(cocos2d::CustomCommand::DrawType::ELEMENT); + _drawableDrawCommandBuffer[i]->GetCommandDraw()->GetCommand()->setPrimitiveType(cocos2d::backend::PrimitiveType::TRIANGLE); + _drawableDrawCommandBuffer[i]->CreateVertexBuffer(vertexSize, drawableVertexCount * 2); // Vertices + UVs + + if (drawableVertexIndexCount > 0) + { + _drawableDrawCommandBuffer[i]->CreateIndexBuffer(drawableVertexIndexCount); + } + } + + + CubismRenderer::Initialize(model); //親クラスの処理を呼ぶ +} + +void CubismRenderer_Cocos2dx::PreDraw() +{ + _commandBuffer.SetOperationEnable(CubismCommandBuffer_Cocos2dx::OperationType_ScissorTest, false); + _commandBuffer.SetOperationEnable(CubismCommandBuffer_Cocos2dx::OperationType_StencilTest, false); + _commandBuffer.SetOperationEnable(CubismCommandBuffer_Cocos2dx::OperationType_DepthTest, false); + + + //異方性フィルタリング。プラットフォームのOpenGLによっては未対応の場合があるので、未設定のときは設定しない + if (GetAnisotropy() > 0.0f) + { + // Not supported. + } +} + + +void CubismRenderer_Cocos2dx::DoDrawModel() +{ + //------------ クリッピングマスク・バッファ前処理方式の場合 ------------ + if (_clippingManager != NULL) + { + PreDraw(); + + // サイズが違う場合はここで作成しなおし + if (_offscreenFrameBuffer.GetBufferWidth() != static_cast(_clippingManager->GetClippingMaskBufferSize()) || + _offscreenFrameBuffer.GetBufferHeight() != static_cast(_clippingManager->GetClippingMaskBufferSize())) + { + _offscreenFrameBuffer.DestroyOffscreenFrame(); + _offscreenFrameBuffer.CreateOffscreenFrame( + static_cast(_clippingManager->GetClippingMaskBufferSize()), static_cast(_clippingManager->GetClippingMaskBufferSize())); + } + + _clippingManager->SetupClippingContext(*GetModel(), this, _rendererProfile._lastColorBuffer, _rendererProfile._lastViewport); + } + + // 上記クリッピング処理内でも一度PreDrawを呼ぶので注意!! + PreDraw(); + + const csmInt32 drawableCount = GetModel()->GetDrawableCount(); + const csmInt32* renderOrder = GetModel()->GetDrawableRenderOrders(); + + // インデックスを描画順でソート + for (csmInt32 i = 0; i < drawableCount; ++i) + { + const csmInt32 order = renderOrder[i]; + _sortedDrawableIndexList[order] = i; + } + + // Update Vertex / Index buffer. + for (csmInt32 i = 0; i < drawableCount; ++i) + { + csmFloat32* vertices = const_cast(GetModel()->GetDrawableVertices(i)); + Core::csmVector2* uvs = const_cast(GetModel()->GetDrawableVertexUvs(i)); + csmUint16* vertexIndices = const_cast(GetModel()->GetDrawableVertexIndices(i)); + const csmUint32 vertexCount = GetModel()->GetDrawableVertexCount(i); + const csmUint32 vertexIndexCount = GetModel()->GetDrawableVertexIndexCount(i); + + _drawableDrawCommandBuffer[i]->UpdateVertexBuffer(vertices, uvs, vertexCount); + _drawableDrawCommandBuffer[i]->CommitVertexBuffer(); + if (vertexIndexCount > 0) + { + _drawableDrawCommandBuffer[i]->UpdateIndexBuffer(vertexIndices, vertexIndexCount); + } + + } + + // 描画 + for (csmInt32 i = 0; i < drawableCount; ++i) + { + const csmInt32 drawableIndex = _sortedDrawableIndexList[i]; + + // Drawableが表示状態でなければ処理をパスする + if (!GetModel()->GetDrawableDynamicFlagIsVisible(drawableIndex)) + { + continue; + } + + // クリッピングマスク + CubismClippingContext* clipContext = (_clippingManager != NULL) + ? (*_clippingManager->GetClippingContextListForDraw())[drawableIndex] + : NULL; + + if (clipContext != NULL && IsUsingHighPrecisionMask()) // マスクを書く必要がある + { + if(clipContext->_isUsing) // 書くことになっていた + { + // 生成したFrameBufferと同じサイズでビューポートを設定 + _commandBuffer.Viewport(0, 0, _clippingManager->GetClippingMaskBufferSize(), _clippingManager->GetClippingMaskBufferSize()); + + PreDraw(); // バッファをクリアする + + _offscreenFrameBuffer.BeginDraw(&_commandBuffer, _rendererProfile._lastColorBuffer); + + // マスクをクリアする + // 1が無効(描かれない)領域、0が有効(描かれる)領域。(シェーダで Cd*Csで0に近い値をかけてマスクを作る。1をかけると何も起こらない) + _offscreenFrameBuffer.Clear(&_commandBuffer, 1.0f, 1.0f, 1.0f, 1.0f); + } + + { + const csmInt32 clipDrawCount = clipContext->_clippingIdCount; + for (csmInt32 index = 0; index < clipDrawCount; index++) + { + const csmInt32 clipDrawIndex = clipContext->_clippingIdList[index]; + CubismCommandBuffer_Cocos2dx::DrawCommandBuffer::DrawCommand* drawCommandMask = clipContext->_clippingCommandBufferList->At(index)->GetCommandDraw(); + + + // 頂点情報が更新されておらず、信頼性がない場合は描画をパスする + if (!GetModel()->GetDrawableDynamicFlagVertexPositionsDidChange(clipDrawIndex)) + { + continue; + } + + IsCulling(GetModel()->GetDrawableCulling(clipDrawIndex) != 0); + + if (GetModel()->GetDrawableVertexIndexCount(clipDrawIndex) <= 0) + { + continue; + } + + // 今回専用の変換を適用して描く + // チャンネルも切り替える必要がある(A,R,G,B) + SetClippingContextBufferForMask(clipContext); + DrawMeshCocos2d( + drawCommandMask, + GetModel()->GetDrawableTextureIndices(clipDrawIndex), + GetModel()->GetDrawableVertexIndexCount(clipDrawIndex), + GetModel()->GetDrawableVertexCount(clipDrawIndex), + const_cast(GetModel()->GetDrawableVertexIndices(clipDrawIndex)), + const_cast(GetModel()->GetDrawableVertices(clipDrawIndex)), + reinterpret_cast(const_cast(GetModel()->GetDrawableVertexUvs(clipDrawIndex))), + GetModel()->GetDrawableOpacity(clipDrawIndex), + CubismRenderer::CubismBlendMode_Normal, //クリッピングは通常描画を強制 + false // マスク生成時はクリッピングの反転使用は全く関係がない + ); + } + } + + { + // --- 後処理 --- + _offscreenFrameBuffer.EndDraw(&_commandBuffer); + SetClippingContextBufferForMask(NULL); + _commandBuffer.Viewport(_rendererProfile._lastViewport.X, _rendererProfile._lastViewport.Y, _rendererProfile._lastViewport.Width, _rendererProfile._lastViewport.Height); + + PreDraw(); // バッファをクリアする + } + } + + CubismCommandBuffer_Cocos2dx::DrawCommandBuffer::DrawCommand* drawCommandDraw = _drawableDrawCommandBuffer[drawableIndex]->GetCommandDraw(); + + // クリッピングマスクをセットする + SetClippingContextBufferForDraw(clipContext); + + IsCulling(GetModel()->GetDrawableCulling(drawableIndex) != 0); + + if (GetModel()->GetDrawableVertexIndexCount(drawableIndex) <= 0) + { + continue; + } + + DrawMeshCocos2d( + drawCommandDraw, + GetModel()->GetDrawableTextureIndices(drawableIndex), + GetModel()->GetDrawableVertexIndexCount(drawableIndex), + GetModel()->GetDrawableVertexCount(drawableIndex), + const_cast(GetModel()->GetDrawableVertexIndices(drawableIndex)), + const_cast(GetModel()->GetDrawableVertices(drawableIndex)), + reinterpret_cast(const_cast(GetModel()->GetDrawableVertexUvs(drawableIndex))), + GetModel()->GetDrawableOpacity(drawableIndex), + GetModel()->GetDrawableBlendMode(drawableIndex), + GetModel()->GetDrawableInvertedMask(drawableIndex) // マスクを反転使用するか + ); + } + + // + PostDraw(); + +} + +void CubismRenderer_Cocos2dx::DrawMesh(csmInt32 textureNo, csmInt32 indexCount, csmInt32 vertexCount, + csmUint16* indexArray, csmFloat32* vertexArray, csmFloat32* uvArray, csmFloat32 opacity, + CubismBlendMode colorBlendMode, csmBool invertedMask) +{ +} + +void CubismRenderer_Cocos2dx::DrawMeshCocos2d(CubismCommandBuffer_Cocos2dx::DrawCommandBuffer::DrawCommand* drawCommand, csmInt32 textureNo, csmInt32 indexCount, csmInt32 vertexCount + , csmUint16* indexArray, csmFloat32* vertexArray, csmFloat32* uvArray + , csmFloat32 opacity, CubismBlendMode colorBlendMode, csmBool invertedMask) +{ +#ifndef CSM_DEBUG + if (_textures[textureNo] == 0) return; // モデルが参照するテクスチャがバインドされていない場合は描画をスキップする +#endif + + // 裏面描画の有効・無効 + if (IsCulling()) + { + _commandBuffer.SetOperationEnable(CubismCommandBuffer_Cocos2dx::OperationType_Culling, true); + } + else + { + _commandBuffer.SetOperationEnable(CubismCommandBuffer_Cocos2dx::OperationType_Culling, false); + } + + // Cubism SDK OpenGLはマスク・アートメッシュ共にCCWが表面 + _commandBuffer.SetWindingMode(CubismCommandBuffer_Cocos2dx::WindingType_CounterClockWise); + + CubismTextureColor modelColorRGBA = GetModelColor(); + + if (GetClippingContextBufferForMask() == NULL) // マスク生成時以外 + { + modelColorRGBA.A *= opacity; + if (IsPremultipliedAlpha()) + { + modelColorRGBA.R *= modelColorRGBA.A; + modelColorRGBA.G *= modelColorRGBA.A; + modelColorRGBA.B *= modelColorRGBA.A; + } + } + + cocos2d::Texture2D* drawTexture; // シェーダに渡すテクスチャ + + // テクスチャマップからバインド済みテクスチャIDを取得 + // バインドされていなければダミーのテクスチャIDをセットする + if(_textures[textureNo] != NULL) + { + drawTexture = _textures[textureNo]; + } + else + { + drawTexture = NULL; + } + + + CubismShader_Cocos2dx::GetInstance()->SetupShaderProgram( + drawCommand, this, drawTexture, vertexCount, vertexArray, uvArray + , opacity, colorBlendMode, modelColorRGBA, IsPremultipliedAlpha() + , GetMvpMatrix(), invertedMask + ); + + + // ポリゴンメッシュを描画する + _commandBuffer.AddDrawCommand(drawCommand); + + + // 後処理 + SetClippingContextBufferForDraw(NULL); + SetClippingContextBufferForMask(NULL); +} + +CubismCommandBuffer_Cocos2dx::DrawCommandBuffer* CubismRenderer_Cocos2dx::GetDrawCommandBufferData(csmInt32 drawableIndex) +{ + return _drawableDrawCommandBuffer[drawableIndex]; +} + +void CubismRenderer_Cocos2dx::SaveProfile() +{ + _rendererProfile.Save(); +} + +void CubismRenderer_Cocos2dx::RestoreProfile() +{ + _rendererProfile.Restore(); +} + +void CubismRenderer_Cocos2dx::BindTexture(csmUint32 modelTextureNo, cocos2d::Texture2D* texture) +{ + _textures[modelTextureNo] = texture; +} + +const csmMap& CubismRenderer_Cocos2dx::GetBindedTextures() const +{ + return _textures; +} + +void CubismRenderer_Cocos2dx::SetClippingMaskBufferSize(csmInt32 size) +{ + //FrameBufferのサイズを変更するためにインスタンスを破棄・再作成する + CSM_DELETE_SELF(CubismClippingManager_Cocos2dx, _clippingManager); + + _clippingManager = CSM_NEW CubismClippingManager_Cocos2dx(); + + _clippingManager->SetClippingMaskBufferSize(size); + + _clippingManager->Initialize( + *GetModel(), + GetModel()->GetDrawableCount(), + GetModel()->GetDrawableMasks(), + GetModel()->GetDrawableMaskCounts() + ); +} + +csmInt32 CubismRenderer_Cocos2dx::GetClippingMaskBufferSize() const +{ + return _clippingManager->GetClippingMaskBufferSize(); +} + +void CubismRenderer_Cocos2dx::SetClippingContextBufferForMask(CubismClippingContext* clip) +{ + _clippingContextBufferForMask = clip; +} + +CubismClippingContext* CubismRenderer_Cocos2dx::GetClippingContextBufferForMask() const +{ + return _clippingContextBufferForMask; +} + +void CubismRenderer_Cocos2dx::SetClippingContextBufferForDraw(CubismClippingContext* clip) +{ + _clippingContextBufferForDraw = clip; +} + +CubismClippingContext* CubismRenderer_Cocos2dx::GetClippingContextBufferForDraw() const +{ + return _clippingContextBufferForDraw; +} + +}}}} + +//------------ LIVE2D NAMESPACE ------------ diff --git a/src/Rendering/Cocos2d/CubismRenderer_Cocos2dx.hpp b/src/Rendering/Cocos2d/CubismRenderer_Cocos2dx.hpp new file mode 100644 index 0000000..01a85f2 --- /dev/null +++ b/src/Rendering/Cocos2d/CubismRenderer_Cocos2dx.hpp @@ -0,0 +1,555 @@ +/** + * Copyright(c) Live2D Inc. All rights reserved. + * + * Use of this source code is governed by the Live2D Open Software license + * that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + +#pragma once + +#include "../CubismRenderer.hpp" +#include "CubismFramework.hpp" +#include "CubismOffscreenSurface_Cocos2dx.hpp" +#include "CubismCommandBuffer_Cocos2dx.hpp" +#include "Type/csmVector.hpp" +#include "Type/csmRectF.hpp" +#include "Type/csmMap.hpp" + + +#ifdef CSM_TARGET_ANDROID_ES2 +#include +#include +#include +#include +#endif + +#ifdef CSM_TARGET_IPHONE_ES2 +#include +#include +#endif + +#if defined(CSM_TARGET_WIN_GL) || defined(CSM_TARGET_LINUX_GL) +#include +#include +#endif + +#ifdef CSM_TARGET_MAC_GL +#ifndef CSM_TARGET_COCOS +#include +#endif +#include +#endif + +//------------ LIVE2D NAMESPACE ------------ +namespace Live2D { namespace Cubism { namespace Framework { namespace Rendering { + +// 前方宣言 +class CubismRenderer_Cocos2dx; +class CubismClippingContext; + +/** + * @brief クリッピングマスクの処理を実行するクラス + * + */ +class CubismClippingManager_Cocos2dx +{ + friend class CubismShader_Cocos2dx; + friend class CubismRenderer_Cocos2dx; + +private: + + /** + * @brief カラーチャンネル(RGBA)のフラグを取得する + * + * @param[in] channelNo -> カラーチャンネル(RGBA)の番号(0:R , 1:G , 2:B, 3:A) + */ + CubismRenderer::CubismTextureColor* GetChannelFlagAsColor(csmInt32 channelNo); + + /** + * @brief マスクされる描画オブジェクト群全体を囲む矩形(モデル座標系)を計算する + * + * @param[in] model -> モデルのインスタンス + * @param[in] clippingContext -> クリッピングマスクのコンテキスト + */ + void CalcClippedDrawTotalBounds(CubismModel& model, CubismClippingContext* clippingContext); + + /** + * @brief コンストラクタ + */ + CubismClippingManager_Cocos2dx(); + + /** + * @brief デストラクタ + */ + virtual ~CubismClippingManager_Cocos2dx(); + + /** + * @brief マネージャの初期化処理
+ * クリッピングマスクを使う描画オブジェクトの登録を行う + * + * @param[in] model -> モデルのインスタンス + * @param[in] drawableCount -> 描画オブジェクトの数 + * @param[in] drawableMasks -> 描画オブジェクトをマスクする描画オブジェクトのインデックスのリスト + * @param[in] drawableMaskCounts -> 描画オブジェクトをマスクする描画オブジェクトの数 + */ + void Initialize(CubismModel& model, csmInt32 drawableCount, const csmInt32** drawableMasks, const csmInt32* drawableMaskCounts); + + /** + * @brief クリッピングコンテキストを作成する。モデル描画時に実行する。 + * + * @param[in] model -> モデルのインスタンス + * @param[in] renderer -> レンダラのインスタンス + * @param[in] lastFBO -> フレームバッファ + * @param[in] lastViewport -> ビューポート + */ + void SetupClippingContext(CubismModel& model, CubismRenderer_Cocos2dx* renderer, cocos2d::Texture2D* lastColorBuffer, csmRectF lastViewport); + + /** + * @brief 既にマスクを作っているかを確認。
+ * 作っているようであれば該当するクリッピングマスクのインスタンスを返す。
+ * 作っていなければNULLを返す + * + * @param[in] drawableMasks -> 描画オブジェクトをマスクする描画オブジェクトのリスト + * @param[in] drawableMaskCounts -> 描画オブジェクトをマスクする描画オブジェクトの数 + * @return 該当するクリッピングマスクが存在すればインスタンスを返し、なければNULLを返す。 + */ + CubismClippingContext* FindSameClip(const csmInt32* drawableMasks, csmInt32 drawableMaskCounts) const; + + /** + * @brief クリッピングコンテキストを配置するレイアウト。
+ * ひとつのレンダーテクスチャを極力いっぱいに使ってマスクをレイアウトする。
+ * マスクグループの数が4以下ならRGBA各チャンネルに1つずつマスクを配置し、5以上6以下ならRGBAを2,2,1,1と配置する。 + * + * @param[in] usingClipCount -> 配置するクリッピングコンテキストの数 + */ + void SetupLayoutBounds(csmInt32 usingClipCount) const; + + /** + * @brief 画面描画に使用するクリッピングマスクのリストを取得する + * + * @return 画面描画に使用するクリッピングマスクのリスト + */ + csmVector* GetClippingContextListForDraw(); + + /** + *@brief クリッピングマスクバッファのサイズを設定する + * + *@param size -> クリッピングマスクバッファのサイズ + * + */ + void SetClippingMaskBufferSize(csmInt32 size); + + /** + *@brief クリッピングマスクバッファのサイズを取得する + * + *@return クリッピングマスクバッファのサイズ + * + */ + csmInt32 GetClippingMaskBufferSize() const; + + csmInt32 _currentFrameNo; ///< マスクテクスチャに与えるフレーム番号 + + csmVector _channelColors; + csmVector _clippingContextListForMask; ///< マスク用クリッピングコンテキストのリスト + csmVector _clippingContextListForDraw; ///< 描画用クリッピングコンテキストのリスト + csmInt32 _clippingMaskBufferSize; ///< クリッピングマスクのバッファサイズ(初期値:256) + + CubismMatrix44 _tmpMatrix; ///< マスク計算用の行列 + CubismMatrix44 _tmpMatrixForMask; ///< マスク計算用の行列 + CubismMatrix44 _tmpMatrixForDraw; ///< マスク計算用の行列 + csmRectF _tmpBoundsOnModel; ///< マスク配置計算用の矩形 + +}; + +/** + * @brief クリッピングマスクのコンテキスト + */ +class CubismClippingContext +{ + friend class CubismClippingManager_Cocos2dx; + friend class CubismShader_Cocos2dx; + friend class CubismRenderer_Cocos2dx; + +private: + /** + * @brief 引数付きコンストラクタ + * + */ + CubismClippingContext(CubismClippingManager_Cocos2dx* manager, CubismModel& model, const csmInt32* clippingDrawableIndices, csmInt32 clipCount); + + /** + * @brief デストラクタ + */ + virtual ~CubismClippingContext(); + + /** + * @brief このマスクにクリップされる描画オブジェクトを追加する + * + * @param[in] drawableIndex -> クリッピング対象に追加する描画オブジェクトのインデックス + */ + void AddClippedDrawable(csmInt32 drawableIndex); + + /** + * @brief このマスクを管理するマネージャのインスタンスを取得する。 + * + * @return クリッピングマネージャのインスタンス + */ + CubismClippingManager_Cocos2dx* GetClippingManager(); + + csmBool _isUsing; ///< 現在の描画状態でマスクの準備が必要ならtrue + const csmInt32* _clippingIdList; ///< クリッピングマスクのIDリスト + csmInt32 _clippingIdCount; ///< クリッピングマスクの数 + csmInt32 _layoutChannelNo; ///< RGBAのいずれのチャンネルにこのクリップを配置するか(0:R , 1:G , 2:B , 3:A) + csmRectF* _layoutBounds; ///< マスク用チャンネルのどの領域にマスクを入れるか(View座標-1..1, UVは0..1に直す) + csmRectF* _allClippedDrawRect; ///< このクリッピングで、クリッピングされる全ての描画オブジェクトの囲み矩形(毎回更新) + CubismMatrix44 _matrixForMask; ///< マスクの位置計算結果を保持する行列 + CubismMatrix44 _matrixForDraw; ///< 描画オブジェクトの位置計算結果を保持する行列 + csmVector* _clippedDrawableIndexList; ///< このマスクにクリップされる描画オブジェクトのリスト + csmVector* _clippingCommandBufferList; + + CubismClippingManager_Cocos2dx* _owner; ///< このマスクを管理しているマネージャのインスタンス +}; + +/** + * @brief Cocos2dx用のシェーダプログラムを生成・破棄するクラス
+ * シングルトンなクラスであり、CubismShader_Cocos2dx::GetInstance()からアクセスする。 + * + */ +class CubismShader_Cocos2dx +{ + friend class CubismRenderer_Cocos2dx; + +private: + /** + * @brief インスタンスを取得する(シングルトン)。 + * + * @return インスタンスのポインタ + */ + static CubismShader_Cocos2dx* GetInstance(); + + /** + * @brief インスタンスを解放する(シングルトン)。 + */ + static void DeleteInstance(); + + /** + * @bref シェーダープログラムとシェーダ変数のアドレスを保持する構造体 + * + */ + struct CubismShaderSet + { + cocos2d::backend::Program* ShaderProgram; ///< シェーダプログラムのアドレス + unsigned int AttributePositionLocation; ///< シェーダプログラムに渡す変数のアドレス(Position) + unsigned int AttributeTexCoordLocation; ///< シェーダプログラムに渡す変数のアドレス(TexCoord) + cocos2d::backend::UniformLocation UniformMatrixLocation; ///< シェーダプログラムに渡す変数のアドレス(Matrix) + cocos2d::backend::UniformLocation UniformClipMatrixLocation; ///< シェーダプログラムに渡す変数のアドレス(ClipMatrix) + cocos2d::backend::UniformLocation SamplerTexture0Location; ///< シェーダプログラムに渡す変数のアドレス(Texture0) + cocos2d::backend::UniformLocation SamplerTexture1Location; ///< シェーダプログラムに渡す変数のアドレス(Texture1) + cocos2d::backend::UniformLocation UniformBaseColorLocation; ///< シェーダプログラムに渡す変数のアドレス(BaseColor) + cocos2d::backend::UniformLocation UnifromChannelFlagLocation; ///< シェーダプログラムに渡す変数のアドレス(ChannelFlag) + }; + + /** + * @brief privateなコンストラクタ + */ + CubismShader_Cocos2dx(); + + /** + * @brief privateなデストラクタ + */ + virtual ~CubismShader_Cocos2dx(); + + /** + * @brief シェーダプログラムの一連のセットアップを実行する + * + * @param[in] renderer -> レンダラのインスタンス + * @param[in] textureId -> GPUのテクスチャID + * @param[in] vertexCount -> ポリゴンメッシュの頂点数 + * @param[in] vertexArray -> ポリゴンメッシュの頂点配列 + * @param[in] uvArray -> uv配列 + * @param[in] opacity -> 不透明度 + * @param[in] colorBlendMode -> カラーブレンディングのタイプ + * @param[in] baseColor -> ベースカラー + * @param[in] isPremultipliedAlpha -> 乗算済みアルファかどうか + * @param[in] matrix4x4 -> Model-View-Projection行列 + * @param[in] invertedMask -> マスクを反転して使用するフラグ + */ + void SetupShaderProgram(CubismCommandBuffer_Cocos2dx::DrawCommandBuffer::DrawCommand* drawCommand, CubismRenderer_Cocos2dx* renderer, cocos2d::Texture2D* texture + , csmInt32 vertexCount, csmFloat32* vertexArray + , csmFloat32* uvArray, csmFloat32 opacity + , CubismRenderer::CubismBlendMode colorBlendMode + , CubismRenderer::CubismTextureColor baseColor + , csmBool isPremultipliedAlpha, CubismMatrix44 matrix4x4 + , csmBool invertedMask); + + /** + * @brief シェーダプログラムを解放する + */ + void ReleaseShaderProgram(); + + /** + * @brief シェーダプログラムを初期化する + */ + void GenerateShaders(); + + /** + * @brief シェーダプログラムをロードしてアドレス返す。 + * + * @param[in] vertShaderSrc -> 頂点シェーダのソース + * @param[in] fragShaderSrc -> フラグメントシェーダのソース + * + * @return シェーダプログラムのアドレス + */ + cocos2d::backend::Program* LoadShaderProgram(const csmChar* vertShaderSrc, const csmChar* fragShaderSrc); + +#ifdef CSM_TARGET_ANDROID_ES2 +public: + /** + * @brief Tegraプロセッサ対応。拡張方式による描画の有効・無効 + * + * @param[in] extMode -> trueなら拡張方式で描画する + * @param[in] extPAMode -> trueなら拡張方式のPA設定を有効にする + */ + static void SetExtShaderMode(csmBool extMode, csmBool extPAMode); + +private: + static csmBool s_extMode; ///< Tegra対応.拡張方式で描画 + static csmBool s_extPAMode; ///< 拡張方式のPA設定用の変数 +#endif + + csmVector _shaderSets; ///< ロードしたシェーダプログラムを保持する変数 + +}; + +/** + * @brief Cubismモデルを描画する直前のCocos2dxのステートを保持・復帰させるクラス + * + */ +class CubismRendererProfile_Cocos2dx +{ + friend class CubismRenderer_Cocos2dx; + +private: + /** + * @biref privateなコンストラクタ + */ + CubismRendererProfile_Cocos2dx() {}; + + /** + * @biref privateなデストラクタ + */ + virtual ~CubismRendererProfile_Cocos2dx() {}; + + /** + * @brief Cocos2dxのステートを保持する + */ + void Save(); + + /** + * @brief 保持したCocos2dxのステートを復帰させる + * + */ + void Restore(); + + csmBool _lastScissorTest; ///< モデル描画直前のGL_VERTEX_ATTRIB_ARRAY_ENABLEDパラメータ + csmBool _lastBlend; ///< モデル描画直前のGL_SCISSOR_TESTパラメータ + csmBool _lastStencilTest; ///< モデル描画直前のGL_STENCIL_TESTパラメータ + csmBool _lastDepthTest; ///< モデル描画直前のGL_DEPTH_TESTパラメータ + cocos2d::CullMode _lastCullFace; ///< モデル描画直前のGL_CULL_FACEパラメータ + cocos2d::Winding _lastWinding; + cocos2d::Texture2D* _lastColorBuffer; ///< モデル描画直前のフレームバッファ + cocos2d::Texture2D* _lastDepthBuffer; + cocos2d::Texture2D* _lastStencilBuffer; + cocos2d::RenderTargetFlag _lastRenderTargetFlag; + csmRectF _lastViewport; ///< モデル描画直前のビューポート +}; + +/** + * @brief Cocos2dx用の描画命令を実装したクラス + * + */ +class CubismRenderer_Cocos2dx : public CubismRenderer +{ + friend class CubismRenderer; + friend class CubismClippingManager_Cocos2dx; + friend class CubismShader_Cocos2dx; + +public: + /** + * @brief レンダラの初期化処理を実行する
+ * 引数に渡したモデルからレンダラの初期化処理に必要な情報を取り出すことができる + * + * @param[in] model -> モデルのインスタンス + */ + void Initialize(Framework::CubismModel* model); + + /** + * @brief OpenGLテクスチャのバインド処理
+ * CubismRendererにテクスチャを設定し、CubismRenderer中でその画像を参照するためのIndex値を戻り値とする + * + * @param[in] modelTextureNo -> セットするモデルテクスチャの番号 + * @param[in] texture -> バックエンドテクスチャ + * + */ + void BindTexture(csmUint32 modelTextureNo, cocos2d::Texture2D* texture); + + /** + * @brief OpenGLにバインドされたテクスチャのリストを取得する + * + * @return テクスチャのアドレスのリスト + */ + const csmMap& GetBindedTextures() const; + + /** + * @brief クリッピングマスクバッファのサイズを設定する
+ * マスク用のFrameBufferを破棄・再作成するため処理コストは高い。 + * + * @param[in] size -> クリッピングマスクバッファのサイズ + * + */ + void SetClippingMaskBufferSize(csmInt32 size); + + /** + * @brief クリッピングマスクバッファのサイズを取得する + * + * @return クリッピングマスクバッファのサイズ + * + */ + csmInt32 GetClippingMaskBufferSize() const; + + + CubismCommandBuffer_Cocos2dx* GetCommandBuffer() + { + return &_commandBuffer; + } + +protected: + /** + * @brief コンストラクタ + */ + CubismRenderer_Cocos2dx(); + + /** + * @brief デストラクタ + */ + virtual ~CubismRenderer_Cocos2dx(); + + /** + * @brief モデルを描画する実際の処理 + * + */ + void DoDrawModel(); + + /** + * @brief [オーバーライド]
+ * 描画オブジェクト(アートメッシュ)を描画する。
+ * ポリゴンメッシュとテクスチャ番号をセットで渡す。 + * + * @param[in] textureNo -> 描画するテクスチャ番号 + * @param[in] indexCount -> 描画オブジェクトのインデックス値 + * @param[in] vertexCount -> ポリゴンメッシュの頂点数 + * @param[in] indexArray -> ポリゴンメッシュのインデックス配列 + * @param[in] vertexArray -> ポリゴンメッシュの頂点配列 + * @param[in] uvArray -> uv配列 + * @param[in] opacity -> 不透明度 + * @param[in] colorBlendMode -> カラー合成タイプ + * @param[in] invertedMask -> マスク使用時のマスクの反転使用 + * + */ + + void DrawMesh(csmInt32 textureNo, csmInt32 indexCount, csmInt32 vertexCount, csmUint16* indexArray, csmFloat32* vertexArray, csmFloat32* uvArray, csmFloat32 opacity, CubismBlendMode colorBlendMode, csmBool invertedMask); + + void DrawMeshCocos2d(CubismCommandBuffer_Cocos2dx::DrawCommandBuffer::DrawCommand* drawCommand, csmInt32 textureNo, csmInt32 indexCount, csmInt32 vertexCount + , csmUint16* indexArray, csmFloat32* vertexArray, csmFloat32* uvArray + , csmFloat32 opacity, CubismBlendMode colorBlendMode, csmBool invertedMask); + + CubismCommandBuffer_Cocos2dx::DrawCommandBuffer* GetDrawCommandBufferData(csmInt32 drawableIndex); + +#ifdef CSM_TARGET_ANDROID_ES2 +public: + /** + * @brief Tegraプロセッサ対応。拡張方式による描画の有効・無効 + * + * @param[in] extMode -> trueなら拡張方式で描画する + * @param[in] extPAMode -> trueなら拡張方式のPA設定を有効にする + */ + static void SetExtShaderMode(csmBool extMdoe, csmBool extPAMode = false); + + /** + * @brief Android-Tegra対応. シェーダプログラムをリロードする。 + */ + static void ReloadShader(); +#endif + +private: + // Prevention of copy Constructor + CubismRenderer_Cocos2dx(const CubismRenderer_Cocos2dx&); + CubismRenderer_Cocos2dx& operator=(const CubismRenderer_Cocos2dx&); + + /** + * @brief レンダラが保持する静的なリソースを解放する
+ * Cocos2dxの静的なシェーダプログラムを解放する + */ + static void DoStaticRelease(); + + /** + * @brief 描画開始時の追加処理。
+ * モデルを描画する前にクリッピングマスクに必要な処理を実装している。 + */ + void PreDraw(); + + /** + * @brief 描画完了後の追加処理。 + * + */ + void PostDraw(){}; + + /** + * @brief モデル描画直前のCocos2dxのステートを保持する + */ + virtual void SaveProfile(); + + /** + * @brief モデル描画直前のCocos2dxのステートを保持する + */ + virtual void RestoreProfile(); + + /** + * @brief マスクテクスチャに描画するクリッピングコンテキストをセットする。 + */ + void SetClippingContextBufferForMask(CubismClippingContext* clip); + + /** + * @brief マスクテクスチャに描画するクリッピングコンテキストを取得する。 + * + * @return マスクテクスチャに描画するクリッピングコンテキスト + */ + CubismClippingContext* GetClippingContextBufferForMask() const; + + /** + * @brief 画面上に描画するクリッピングコンテキストをセットする。 + */ + void SetClippingContextBufferForDraw(CubismClippingContext* clip); + + /** + * @brief 画面上に描画するクリッピングコンテキストを取得する。 + * + * @return 画面上に描画するクリッピングコンテキスト + */ + CubismClippingContext* GetClippingContextBufferForDraw() const; + + + csmMap _textures; ///< モデルが参照するテクスチャとレンダラでバインドしているテクスチャとのマップ + csmVector _sortedDrawableIndexList; ///< 描画オブジェクトのインデックスを描画順に並べたリスト + CubismRendererProfile_Cocos2dx _rendererProfile; ///< OpenGLのステートを保持するオブジェクト + CubismClippingManager_Cocos2dx* _clippingManager; ///< クリッピングマスク管理オブジェクト + CubismClippingContext* _clippingContextBufferForMask; ///< マスクテクスチャに描画するためのクリッピングコンテキスト + CubismClippingContext* _clippingContextBufferForDraw; ///< 画面上描画するためのクリッピングコンテキスト + + CubismOffscreenFrame_Cocos2dx _offscreenFrameBuffer; ///< マスク描画用のフレームバッファ + CubismCommandBuffer_Cocos2dx _commandBuffer; + csmVector _drawableDrawCommandBuffer; +}; + +}}}} +//------------ LIVE2D NAMESPACE ------------ diff --git a/src/Rendering/D3D11/CubismRenderer_D3D11.cpp b/src/Rendering/D3D11/CubismRenderer_D3D11.cpp index bb46471..4019cfb 100644 --- a/src/Rendering/D3D11/CubismRenderer_D3D11.cpp +++ b/src/Rendering/D3D11/CubismRenderer_D3D11.cpp @@ -55,7 +55,7 @@ const csmInt32 ColorChannelCount = 4; ///< 実験時に1チャンネルの場 CubismClippingManager_D3D11::CubismClippingManager_D3D11() : _colorBuffer(NULL) , _currentFrameNo(0) - , _clippingMaskBufferSize(256) + , _clippingMaskBufferSize(256, 256) { CubismRenderer::CubismTextureColor* tmp = NULL; tmp = CSM_NEW CubismRenderer::CubismTextureColor(); @@ -196,8 +196,8 @@ void CubismClippingManager_D3D11::SetupClippingContext(ID3D11DeviceContext* rend CubismRenderer_D3D11::GetRenderStateManager()->SetViewport(renderContext, 0, 0, - static_cast(_clippingMaskBufferSize), - static_cast(_clippingMaskBufferSize), + static_cast(_clippingMaskBufferSize.X), + static_cast(_clippingMaskBufferSize.Y), 0.0f, 1.0f); useTarget.BeginDraw(renderContext); @@ -216,17 +216,53 @@ void CubismClippingManager_D3D11::SetupClippingContext(ID3D11DeviceContext* rend CubismClippingContext* clipContext = _clippingContextListForMask[clipIndex]; csmRectF* allClippedDrawRect = clipContext->_allClippedDrawRect; //このマスクを使う、全ての描画オブジェクトの論理座標上の囲み矩形 csmRectF* layoutBoundsOnTex01 = clipContext->_layoutBounds; //この中にマスクを収める - - // モデル座標上の矩形を、適宜マージンを付けて使う const csmFloat32 MARGIN = 0.05f; - _tmpBoundsOnModel.SetRect(allClippedDrawRect); - _tmpBoundsOnModel.Expand(allClippedDrawRect->Width * MARGIN, allClippedDrawRect->Height * MARGIN); - //########## 本来は割り当てられた領域の全体を使わず必要最低限のサイズがよい + csmFloat32 scaleX = 0.0f; + csmFloat32 scaleY = 0.0f; + + + if (renderer->IsUsingHighPrecisionMask()) + { + const csmFloat32 ppu = model.GetPixelsPerUnit(); + const csmFloat32 maskPixelWidth = clipContext->_owner->_clippingMaskBufferSize.X; + const csmFloat32 maskPixelHeight = clipContext->_owner->_clippingMaskBufferSize.Y; + const csmFloat32 physicalMaskWidth = layoutBoundsOnTex01->Width * maskPixelWidth; + const csmFloat32 physicalMaskHeight = layoutBoundsOnTex01->Height * maskPixelHeight; + + _tmpBoundsOnModel.SetRect(allClippedDrawRect); + + if (_tmpBoundsOnModel.Width * ppu > physicalMaskWidth) + { + _tmpBoundsOnModel.Expand(allClippedDrawRect->Width * MARGIN, 0.0f); + scaleX = layoutBoundsOnTex01->Width / _tmpBoundsOnModel.Width; + } + else + { + scaleX = ppu / physicalMaskWidth; + } + + if (_tmpBoundsOnModel.Height * ppu > physicalMaskHeight) + { + _tmpBoundsOnModel.Expand(0.0f, allClippedDrawRect->Height * MARGIN); + scaleY = layoutBoundsOnTex01->Height / _tmpBoundsOnModel.Height; + } + else + { + scaleY = ppu / physicalMaskHeight; + } + } + else + { + // モデル座標上の矩形を、適宜マージンを付けて使う + _tmpBoundsOnModel.SetRect(allClippedDrawRect); + _tmpBoundsOnModel.Expand(allClippedDrawRect->Width * MARGIN, allClippedDrawRect->Height * MARGIN); + //########## 本来は割り当てられた領域の全体を使わず必要最低限のサイズがよい + // シェーダ用の計算式を求める。回転を考慮しない場合は以下のとおり + // movePeriod' = movePeriod * scaleX + offX [[ movePeriod' = (movePeriod - tmpBoundsOnModel.movePeriod)*scale + layoutBoundsOnTex01.movePeriod ]] + scaleX = layoutBoundsOnTex01->Width / _tmpBoundsOnModel.Width; + scaleY = layoutBoundsOnTex01->Height / _tmpBoundsOnModel.Height; + } - // シェーダ用の計算式を求める。回転を考慮しない場合は以下のとおり - // movePeriod' = movePeriod * scaleX + offX [[ movePeriod' = (movePeriod - tmpBoundsOnModel.movePeriod)*scale + layoutBoundsOnTex01.movePeriod ]] - const csmFloat32 scaleX = layoutBoundsOnTex01->Width / _tmpBoundsOnModel.Width; - const csmFloat32 scaleY = layoutBoundsOnTex01->Height / _tmpBoundsOnModel.Height; // マスク生成時に使う行列を求める { @@ -317,7 +353,7 @@ void CubismClippingManager_D3D11::CalcClippedDrawTotalBounds(CubismModel& model, { // 被クリッピングマスク(マスクされる描画オブジェクト)の全体の矩形 csmFloat32 clippedDrawTotalMinX = FLT_MAX, clippedDrawTotalMinY = FLT_MAX; - csmFloat32 clippedDrawTotalMaxX = FLT_MIN, clippedDrawTotalMaxY = FLT_MIN; + csmFloat32 clippedDrawTotalMaxX = -FLT_MAX, clippedDrawTotalMaxY = -FLT_MAX; // このマスクが実際に必要か判定する // このクリッピングを利用する「描画オブジェクト」がひとつでも使用可能であればマスクを生成する必要がある @@ -332,7 +368,7 @@ void CubismClippingManager_D3D11::CalcClippedDrawTotalBounds(CubismModel& model, const csmFloat32* drawableVertexes = const_cast(model.GetDrawableVertices(drawableIndex)); csmFloat32 minX = FLT_MAX, minY = FLT_MAX; - csmFloat32 maxX = FLT_MIN, maxY = FLT_MIN; + csmFloat32 maxX = -FLT_MAX, maxY = -FLT_MAX; csmInt32 loop = drawableVertexCount * Constant::VertexStep; for (csmInt32 pi = Constant::VertexOffset; pi < loop; pi += Constant::VertexStep) @@ -507,12 +543,12 @@ csmVector* CubismClippingManager_D3D11::GetClippingConte return &_clippingContextListForDraw; } -void CubismClippingManager_D3D11::SetClippingMaskBufferSize(csmInt32 size) +void CubismClippingManager_D3D11::SetClippingMaskBufferSize(csmFloat32 width, csmFloat32 height) { - _clippingMaskBufferSize = size; + _clippingMaskBufferSize = CubismVector2(width, height); } -csmInt32 CubismClippingManager_D3D11::GetClippingMaskBufferSize() const +CubismVector2 CubismClippingManager_D3D11::GetClippingMaskBufferSize() const { return _clippingMaskBufferSize; } @@ -863,7 +899,8 @@ void CubismRenderer_D3D11::Initialize(CubismModel* model) if (model->IsUsingMasking()) { - const csmInt32 bufferHeight = _clippingManager->GetClippingMaskBufferSize(); + const csmInt32 bufferWidth = _clippingManager->GetClippingMaskBufferSize().X; + const csmInt32 bufferHeight = _clippingManager->GetClippingMaskBufferSize().Y; // バックバッファ分確保 for (csmUint32 i = 0; i < s_bufferSetNum; i++) @@ -876,7 +913,7 @@ void CubismRenderer_D3D11::Initialize(CubismModel* model) { _offscreenFrameBuffer[i].CreateOffscreenFrame( s_device, - bufferHeight, bufferHeight); + bufferWidth, bufferHeight); } } } @@ -909,12 +946,12 @@ void CubismRenderer_D3D11::DoDrawModel() _clippingManager->_colorBuffer = &_offscreenFrameBuffer[_commandBufferCurrent]; // サイズが違う場合はここで作成しなおし - if (_clippingManager->_colorBuffer->GetBufferWidth() != static_cast(_clippingManager->GetClippingMaskBufferSize()) || - _clippingManager->_colorBuffer->GetBufferHeight() != static_cast(_clippingManager->GetClippingMaskBufferSize())) + if (_clippingManager->_colorBuffer->GetBufferWidth() != static_cast(_clippingManager->GetClippingMaskBufferSize().X) || + _clippingManager->_colorBuffer->GetBufferHeight() != static_cast(_clippingManager->GetClippingMaskBufferSize().Y)) { _clippingManager->_colorBuffer->DestroyOffscreenFrame(); _clippingManager->_colorBuffer->CreateOffscreenFrame(s_device, - static_cast(_clippingManager->GetClippingMaskBufferSize()), static_cast(_clippingManager->GetClippingMaskBufferSize())); + static_cast(_clippingManager->GetClippingMaskBufferSize().X), static_cast(_clippingManager->GetClippingMaskBufferSize().Y)); } _clippingManager->SetupClippingContext(s_context, *GetModel(), this, *_clippingManager->_colorBuffer); @@ -964,8 +1001,8 @@ void CubismRenderer_D3D11::DoDrawModel() CubismRenderer_D3D11::GetRenderStateManager()->SetViewport(s_context, 0, 0, - static_cast(_clippingManager->GetClippingMaskBufferSize()), - static_cast(_clippingManager->GetClippingMaskBufferSize()), + static_cast(_clippingManager->GetClippingMaskBufferSize().X), + static_cast(_clippingManager->GetClippingMaskBufferSize().Y), 0.0f, 1.0f); _clippingManager->_colorBuffer->BeginDraw(s_context); @@ -1369,14 +1406,14 @@ const csmMap& CubismRenderer_D3D11::GetBind return _textures; } -void CubismRenderer_D3D11::SetClippingMaskBufferSize(csmInt32 size) +void CubismRenderer_D3D11::SetClippingMaskBufferSize(csmFloat32 width, csmFloat32 height) { //FrameBufferのサイズを変更するためにインスタンスを破棄・再作成する CSM_DELETE_SELF(CubismClippingManager_D3D11, _clippingManager); _clippingManager = CSM_NEW CubismClippingManager_D3D11(); - _clippingManager->SetClippingMaskBufferSize(size); + _clippingManager->SetClippingMaskBufferSize(width, height); _clippingManager->Initialize( *GetModel(), @@ -1386,11 +1423,16 @@ void CubismRenderer_D3D11::SetClippingMaskBufferSize(csmInt32 size) ); } -csmInt32 CubismRenderer_D3D11::GetClippingMaskBufferSize() const +CubismVector2 CubismRenderer_D3D11::GetClippingMaskBufferSize() const { return _clippingManager->GetClippingMaskBufferSize(); } +const csmVector& CubismRenderer_D3D11::GetMaskBuffer() const +{ + return _offscreenFrameBuffer; +} + void CubismRenderer_D3D11::InitializeConstantSettings(csmUint32 bufferSetNum, ID3D11Device* device) { s_bufferSetNum = bufferSetNum; diff --git a/src/Rendering/D3D11/CubismRenderer_D3D11.hpp b/src/Rendering/D3D11/CubismRenderer_D3D11.hpp index fcdc933..475cc08 100644 --- a/src/Rendering/D3D11/CubismRenderer_D3D11.hpp +++ b/src/Rendering/D3D11/CubismRenderer_D3D11.hpp @@ -13,6 +13,7 @@ #include "CubismFramework.hpp" #include "Type/csmVector.hpp" #include "Type/csmRectF.hpp" +#include "Math/CubismVector2.hpp" #include "Type/csmMap.hpp" #include "Rendering/D3D11/CubismOffscreenSurface_D3D11.hpp" #include "CubismRenderState_D3D11.hpp" @@ -125,15 +126,15 @@ class CubismClippingManager_D3D11 *@param size -> クリッピングマスクバッファのサイズ * */ - void SetClippingMaskBufferSize(csmInt32 size); + void SetClippingMaskBufferSize(csmFloat32 width, csmFloat32 height); /** - *@brief クリッピングマスクバッファのサイズを取得する + * @brief クリッピングマスクバッファのサイズを取得する * - *@return クリッピングマスクバッファのサイズ + * @return クリッピングマスクバッファのサイズ * */ - csmInt32 GetClippingMaskBufferSize() const; + CubismVector2 GetClippingMaskBufferSize() const; CubismOffscreenFrame_D3D11* _colorBuffer; ///< マスク用カラーバッファーのアドレス csmInt32 _currentFrameNo; ///< マスクテクスチャに与えるフレーム番号 @@ -141,7 +142,7 @@ class CubismClippingManager_D3D11 csmVector _channelColors; csmVector _clippingContextListForMask; ///< マスク用クリッピングコンテキストのリスト csmVector _clippingContextListForDraw; ///< 描画用クリッピングコンテキストのリスト - csmInt32 _clippingMaskBufferSize; ///< クリッピングマスクのバッファサイズ(初期値:256) + CubismVector2 _clippingMaskBufferSize; ///< クリッピングマスクのバッファサイズ(初期値:256) CubismMatrix44 _tmpMatrix; ///< マスク計算用の行列 CubismMatrix44 _tmpMatrixForMask; ///< マスク計算用の行列 @@ -308,7 +309,7 @@ class CubismRenderer_D3D11 : public CubismRenderer * @param[in] size -> クリッピングマスクバッファのサイズ * */ - void SetClippingMaskBufferSize(csmInt32 size); + void SetClippingMaskBufferSize(csmFloat32 width, csmFloat32 height); /** * @brief クリッピングマスクバッファのサイズを取得する @@ -316,7 +317,15 @@ class CubismRenderer_D3D11 : public CubismRenderer * @return クリッピングマスクバッファのサイズ * */ - csmInt32 GetClippingMaskBufferSize() const; + CubismVector2 GetClippingMaskBufferSize() const; + + /** + * @brief クリッピングマスクのバッファを取得する + * + * @return クリッピングマスクのバッファへの参照 + * + */ + const csmVector& GetMaskBuffer() const; /** * @brief 使用するシェーダの設定・コンスタントバッファの設定などを行い、描画を実行 diff --git a/src/Rendering/D3D9/CubismRenderState_D3D9.cpp b/src/Rendering/D3D9/CubismRenderState_D3D9.cpp index 083ce9d..5d79543 100644 --- a/src/Rendering/D3D9/CubismRenderState_D3D9.cpp +++ b/src/Rendering/D3D9/CubismRenderState_D3D9.cpp @@ -81,10 +81,15 @@ void CubismRenderState_D3D9::Restore(LPDIRECT3DDEVICE9 device) SetCullMode(device, current.CullModeFaceMode, true); isSet[State_CullMode] = true; } - if (_pushed[i]._valid[State_TextureFilter] && !isSet[State_TextureFilter]) + if (_pushed[i]._valid[State_TextureFilterStage0] && !isSet[State_TextureFilterStage0]) { - SetTextureFilter(device, current.MinFilter, current.MagFilter, current.MipFilter, current.AddressU, current.AddressV, current.Anisotropy, true); - isSet[State_TextureFilter] = true; + SetTextureFilter(device, 0, current.MinFilter[0], current.MagFilter[0], current.MipFilter[0], current.AddressU[0], current.AddressV[0], current.Anisotropy[0], true); + isSet[State_TextureFilterStage0] = true; + } + if (_pushed[i]._valid[State_TextureFilterStage1] && !isSet[State_TextureFilterStage1]) + { + SetTextureFilter(device, 1, current.MinFilter[1], current.MagFilter[1], current.MipFilter[1], current.AddressU[1], current.AddressV[1], current.Anisotropy[1], true); + isSet[State_TextureFilterStage1] = true; } } @@ -200,36 +205,41 @@ void CubismRenderState_D3D9::SetCullMode(LPDIRECT3DDEVICE9 device, D3DCULL cullF _stored._valid[State_CullMode] = true; } -void CubismRenderState_D3D9::SetTextureFilter(LPDIRECT3DDEVICE9 device, D3DTEXTUREFILTERTYPE minFilter, D3DTEXTUREFILTERTYPE magFilter, D3DTEXTUREFILTERTYPE mipFilter, D3DTEXTUREADDRESS addressU, D3DTEXTUREADDRESS addressV, csmFloat32 anisotropy, csmBool force) +void CubismRenderState_D3D9::SetTextureFilter(LPDIRECT3DDEVICE9 device, csmInt32 stage, D3DTEXTUREFILTERTYPE minFilter, D3DTEXTUREFILTERTYPE magFilter, D3DTEXTUREFILTERTYPE mipFilter, D3DTEXTUREADDRESS addressU, D3DTEXTUREADDRESS addressV, csmFloat32 anisotropy, csmBool force) { - if (!_stored._valid[State_TextureFilter] || force || - _stored.MinFilter != minFilter || - _stored.MagFilter != magFilter || - _stored.MipFilter != mipFilter || - _stored.AddressU != addressU || - _stored.AddressV != addressV || - _stored.Anisotropy != anisotropy) + const csmInt32 stateIndex = State_TextureFilterStage0 + stage; + + // ステージインデックスの範囲内検知 + CSM_ASSERT((stateIndex == State_TextureFilterStage0) || (stateIndex == State_TextureFilterStage1)); + + if (!_stored._valid[stateIndex] || force || + _stored.MinFilter[stage] != minFilter || + _stored.MagFilter[stage] != magFilter || + _stored.MipFilter[stage] != mipFilter || + _stored.AddressU[stage] != addressU || + _stored.AddressV[stage] != addressV || + _stored.Anisotropy[stage] != anisotropy) { - device->SetSamplerState(0, D3DSAMP_MINFILTER, minFilter); - device->SetSamplerState(0, D3DSAMP_MAGFILTER, magFilter); - device->SetSamplerState(0, D3DSAMP_ADDRESSU, addressU); - device->SetSamplerState(0, D3DSAMP_ADDRESSV, addressV); - if (anisotropy > 0.0) + device->SetSamplerState(stage, D3DSAMP_MINFILTER, minFilter); + device->SetSamplerState(stage, D3DSAMP_MAGFILTER, magFilter); + device->SetSamplerState(stage, D3DSAMP_ADDRESSU, addressU); + device->SetSamplerState(stage, D3DSAMP_ADDRESSV, addressV); + if (anisotropy > 0.0f) { - device->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_NONE); - device->SetSamplerState(0, D3DSAMP_MAXANISOTROPY, anisotropy); + device->SetSamplerState(stage, D3DSAMP_MIPFILTER, D3DTEXF_NONE); + device->SetSamplerState(stage, D3DSAMP_MAXANISOTROPY, anisotropy); } } - _stored.MinFilter = minFilter; - _stored.MagFilter = magFilter; - _stored.MipFilter = mipFilter; - _stored.AddressU = addressU; - _stored.AddressV = addressV; - _stored.Anisotropy = anisotropy; + _stored.MinFilter[stage] = minFilter; + _stored.MagFilter[stage] = magFilter; + _stored.MipFilter[stage] = mipFilter; + _stored.AddressU[stage] = addressU; + _stored.AddressV[stage] = addressV; + _stored.Anisotropy[stage] = anisotropy; - _stored._valid[State_TextureFilter] = true; + _stored._valid[stateIndex] = true; } void CubismRenderState_D3D9::SaveCurrentNativeState(LPDIRECT3DDEVICE9 device) @@ -274,14 +284,16 @@ void CubismRenderState_D3D9::SaveCurrentNativeState(LPDIRECT3DDEVICE9 device) SetCullMode(device, static_cast(setting[0]), true); // TextureFilter - device->GetSamplerState(0, D3DSAMP_MINFILTER, &setting[0]); - device->GetSamplerState(0, D3DSAMP_MAGFILTER, &setting[1]); - device->GetSamplerState(0, D3DSAMP_MIPFILTER, &setting[2]); - device->GetSamplerState(0, D3DSAMP_ADDRESSU, &setting[3]); - device->GetSamplerState(0, D3DSAMP_ADDRESSV, &setting[4]); - device->GetSamplerState(0, D3DSAMP_MAXANISOTROPY, &setting[5]); - SetTextureFilter(device, static_cast(setting[0]), static_cast(setting[1]), static_cast(setting[2]), - static_cast(setting[3]), static_cast(setting[4]), static_cast(setting[5]), true); + for (csmInt32 stage = 0; stage < 2; stage++) { + device->GetSamplerState(stage, D3DSAMP_MINFILTER, &setting[0]); + device->GetSamplerState(stage, D3DSAMP_MAGFILTER, &setting[1]); + device->GetSamplerState(stage, D3DSAMP_MIPFILTER, &setting[2]); + device->GetSamplerState(stage, D3DSAMP_ADDRESSU, &setting[3]); + device->GetSamplerState(stage, D3DSAMP_ADDRESSV, &setting[4]); + device->GetSamplerState(stage, D3DSAMP_MAXANISOTROPY, &setting[5]); + SetTextureFilter(device, stage, static_cast(setting[0]), static_cast(setting[1]), static_cast(setting[2]), + static_cast(setting[3]), static_cast(setting[4]), static_cast(setting[5]), true); + } // 最後に上記の値を保存 Save(); diff --git a/src/Rendering/D3D9/CubismRenderState_D3D9.hpp b/src/Rendering/D3D9/CubismRenderState_D3D9.hpp index 135e82e..dbe2c66 100644 --- a/src/Rendering/D3D9/CubismRenderState_D3D9.hpp +++ b/src/Rendering/D3D9/CubismRenderState_D3D9.hpp @@ -35,7 +35,8 @@ class CubismRenderState_D3D9 State_DepthTarget, ///< 深度ターゲット State_ZEnable, ///< Z有効無効 State_CullMode, ///< カリングモード - State_TextureFilter,///< テクスチャフィルター + State_TextureFilterStage0, ///< テクスチャフィルター(ステージ0) + State_TextureFilterStage1, ///< テクスチャフィルター(ステージ1) State_Max, }; @@ -69,12 +70,19 @@ class CubismRenderState_D3D9 CullModeFaceMode = D3DCULL_NONE; - MinFilter = D3DTEXF_NONE; - MagFilter = D3DTEXF_NONE; - MipFilter = D3DTEXF_NONE; - AddressU = D3DTADDRESS_WRAP; - AddressV = D3DTADDRESS_WRAP; - Anisotropy = 0.0; + MinFilter[0] = D3DTEXF_NONE; + MagFilter[0] = D3DTEXF_NONE; + MipFilter[0] = D3DTEXF_NONE; + AddressU[0] = D3DTADDRESS_WRAP; + AddressV[0] = D3DTADDRESS_WRAP; + Anisotropy[0] = 0.0f; + + MinFilter[1] = D3DTEXF_NONE; + MagFilter[1] = D3DTEXF_NONE; + MipFilter[1] = D3DTEXF_NONE; + AddressU[1] = D3DTADDRESS_WRAP; + AddressV[1] = D3DTADDRESS_WRAP; + Anisotropy[1] = 0.0f; memset(_valid, 0, sizeof(_valid)); } @@ -107,13 +115,13 @@ class CubismRenderState_D3D9 // State_CullMode D3DCULL CullModeFaceMode; // 消す面を指定 CWだと時計回りが消える - // State_TextureFilter サンプラー0番フィルター - D3DTEXTUREFILTERTYPE MinFilter; - D3DTEXTUREFILTERTYPE MagFilter; - D3DTEXTUREFILTERTYPE MipFilter; - D3DTEXTUREADDRESS AddressU; - D3DTEXTUREADDRESS AddressV; - float Anisotropy; + // State_TextureFilter サンプラーフィルター(0番, 1番) + D3DTEXTUREFILTERTYPE MinFilter[2]; + D3DTEXTUREFILTERTYPE MagFilter[2]; + D3DTEXTUREFILTERTYPE MipFilter[2]; + D3DTEXTUREADDRESS AddressU[2]; + D3DTEXTUREADDRESS AddressV[2]; + float Anisotropy[2]; csmBool _valid[State_Max]; ///< 設定したかどうか。現在はStartFrameで一通りは呼んでいる }; @@ -192,16 +200,17 @@ class CubismRenderState_D3D9 void SetCullMode(LPDIRECT3DDEVICE9 device, D3DCULL cullFace, csmBool force = false); /** - * @brief テクスチャサンプラー0番フィルタセット + * @brief テクスチャサンプラーにフィルタセット * * @param device[in] 描画デバイス + * @param stage[in] サンプラーステージインデックス(サンプラー番号) * @param minFilter[in] 縮小時フィルタ * @param magFilter[in] 拡大時フィルタ * @param mipFilter[in] ミップフィルタ * @param addressU[in] アドレッシングモードU * @param addressV[in] アドレッシングモードV */ - void SetTextureFilter(LPDIRECT3DDEVICE9 device, D3DTEXTUREFILTERTYPE minFilter, D3DTEXTUREFILTERTYPE magFilter, D3DTEXTUREFILTERTYPE mipFilter, D3DTEXTUREADDRESS addressU, D3DTEXTUREADDRESS addressV, csmFloat32 anisotropy = 0.0, csmBool force = false); + void SetTextureFilter(LPDIRECT3DDEVICE9 device, csmInt32 stage, D3DTEXTUREFILTERTYPE minFilter, D3DTEXTUREFILTERTYPE magFilter, D3DTEXTUREFILTERTYPE mipFilter, D3DTEXTUREADDRESS addressU, D3DTEXTUREADDRESS addressV, csmFloat32 anisotropy = 0.0, csmBool force = false); private: CubismRenderState_D3D9(); diff --git a/src/Rendering/D3D9/CubismRenderer_D3D9.cpp b/src/Rendering/D3D9/CubismRenderer_D3D9.cpp index dd0e975..cd7cc0d 100644 --- a/src/Rendering/D3D9/CubismRenderer_D3D9.cpp +++ b/src/Rendering/D3D9/CubismRenderer_D3D9.cpp @@ -55,7 +55,7 @@ const csmInt32 ColorChannelCount = 4; ///< 実験時に1チャンネルの場 CubismClippingManager_DX9::CubismClippingManager_DX9() : _colorBuffer(NULL) , _currentFrameNo(0) - , _clippingMaskBufferSize(256) + , _clippingMaskBufferSize(256, 256) { CubismRenderer::CubismTextureColor* tmp = NULL; tmp = CSM_NEW CubismRenderer::CubismTextureColor(); @@ -197,8 +197,8 @@ void CubismClippingManager_DX9::SetupClippingContext(LPDIRECT3DDEVICE9 device, C CubismRenderer_D3D9::GetRenderStateManager()->SetViewport(device, 0, 0, - _clippingMaskBufferSize, - _clippingMaskBufferSize, + _clippingMaskBufferSize.X, + _clippingMaskBufferSize.Y, 0.0f, 1.0f); useTarget.BeginDraw(device); @@ -217,17 +217,53 @@ void CubismClippingManager_DX9::SetupClippingContext(LPDIRECT3DDEVICE9 device, C CubismClippingContext* clipContext = _clippingContextListForMask[clipIndex]; csmRectF* allClippedDrawRect = clipContext->_allClippedDrawRect; //このマスクを使う、全ての描画オブジェクトの論理座標上の囲み矩形 csmRectF* layoutBoundsOnTex01 = clipContext->_layoutBounds; //この中にマスクを収める - - // モデル座標上の矩形を、適宜マージンを付けて使う const csmFloat32 MARGIN = 0.05f; - _tmpBoundsOnModel.SetRect(allClippedDrawRect); - _tmpBoundsOnModel.Expand(allClippedDrawRect->Width * MARGIN, allClippedDrawRect->Height * MARGIN); - //########## 本来は割り当てられた領域の全体を使わず必要最低限のサイズがよい + csmFloat32 scaleX = 0.0f; + csmFloat32 scaleY = 0.0f; + + + if (renderer->IsUsingHighPrecisionMask()) + { + const csmFloat32 ppu = model.GetPixelsPerUnit(); + const csmFloat32 maskPixelWidth = clipContext->_owner->_clippingMaskBufferSize.X; + const csmFloat32 maskPixelHeight = clipContext->_owner->_clippingMaskBufferSize.Y; + const csmFloat32 physicalMaskWidth = layoutBoundsOnTex01->Width * maskPixelWidth; + const csmFloat32 physicalMaskHeight = layoutBoundsOnTex01->Height * maskPixelHeight; + + _tmpBoundsOnModel.SetRect(allClippedDrawRect); + + if (_tmpBoundsOnModel.Width * ppu > physicalMaskWidth) + { + _tmpBoundsOnModel.Expand(allClippedDrawRect->Width * MARGIN, 0.0f); + scaleX = layoutBoundsOnTex01->Width / _tmpBoundsOnModel.Width; + } + else + { + scaleX = ppu / physicalMaskWidth; + } + + if (_tmpBoundsOnModel.Height * ppu > physicalMaskHeight) + { + _tmpBoundsOnModel.Expand(0.0f, allClippedDrawRect->Height * MARGIN); + scaleY = layoutBoundsOnTex01->Height / _tmpBoundsOnModel.Height; + } + else + { + scaleY = ppu / physicalMaskHeight; + } + } + else + { + // モデル座標上の矩形を、適宜マージンを付けて使う + _tmpBoundsOnModel.SetRect(allClippedDrawRect); + _tmpBoundsOnModel.Expand(allClippedDrawRect->Width * MARGIN, allClippedDrawRect->Height * MARGIN); + //########## 本来は割り当てられた領域の全体を使わず必要最低限のサイズがよい + // シェーダ用の計算式を求める。回転を考慮しない場合は以下のとおり + // movePeriod' = movePeriod * scaleX + offX [[ movePeriod' = (movePeriod - tmpBoundsOnModel.movePeriod)*scale + layoutBoundsOnTex01.movePeriod ]] + scaleX = layoutBoundsOnTex01->Width / _tmpBoundsOnModel.Width; + scaleY = layoutBoundsOnTex01->Height / _tmpBoundsOnModel.Height; + } - // シェーダ用の計算式を求める。回転を考慮しない場合は以下のとおり - // movePeriod' = movePeriod * scaleX + offX [[ movePeriod' = (movePeriod - tmpBoundsOnModel.movePeriod)*scale + layoutBoundsOnTex01.movePeriod ]] - const csmFloat32 scaleX = layoutBoundsOnTex01->Width / _tmpBoundsOnModel.Width; - const csmFloat32 scaleY = layoutBoundsOnTex01->Height / _tmpBoundsOnModel.Height; // マスク生成時に使う行列を求める { @@ -318,7 +354,7 @@ void CubismClippingManager_DX9::CalcClippedDrawTotalBounds(CubismModel& model, C { // 被クリッピングマスク(マスクされる描画オブジェクト)の全体の矩形 csmFloat32 clippedDrawTotalMinX = FLT_MAX, clippedDrawTotalMinY = FLT_MAX; - csmFloat32 clippedDrawTotalMaxX = FLT_MIN, clippedDrawTotalMaxY = FLT_MIN; + csmFloat32 clippedDrawTotalMaxX = -FLT_MAX, clippedDrawTotalMaxY = -FLT_MAX; // このマスクが実際に必要か判定する // このクリッピングを利用する「描画オブジェクト」がひとつでも使用可能であればマスクを生成する必要がある @@ -333,7 +369,7 @@ void CubismClippingManager_DX9::CalcClippedDrawTotalBounds(CubismModel& model, C const csmFloat32* drawableVertexes = const_cast(model.GetDrawableVertices(drawableIndex)); csmFloat32 minX = FLT_MAX, minY = FLT_MAX; - csmFloat32 maxX = FLT_MIN, maxY = FLT_MIN; + csmFloat32 maxX = -FLT_MAX, maxY = -FLT_MAX; csmInt32 loop = drawableVertexCount * Constant::VertexStep; for (csmInt32 pi = Constant::VertexOffset; pi < loop; pi += Constant::VertexStep) @@ -508,12 +544,12 @@ csmVector* CubismClippingManager_DX9::GetClippingContext return &_clippingContextListForDraw; } -void CubismClippingManager_DX9::SetClippingMaskBufferSize(csmInt32 size) +void CubismClippingManager_DX9::SetClippingMaskBufferSize(csmFloat32 width, csmFloat32 height) { - _clippingMaskBufferSize = size; + _clippingMaskBufferSize = CubismVector2(width, height); } -csmInt32 CubismClippingManager_DX9::GetClippingMaskBufferSize() const +CubismVector2 CubismClippingManager_DX9::GetClippingMaskBufferSize() const { return _clippingMaskBufferSize; } @@ -790,7 +826,8 @@ void CubismRenderer_D3D9::Initialize(CubismModel* model) if (model->IsUsingMasking()) { - const csmInt32 bufferHeight = _clippingManager->GetClippingMaskBufferSize(); + const csmInt32 bufferWidth = _clippingManager->GetClippingMaskBufferSize().X; + const csmInt32 bufferHeight = _clippingManager->GetClippingMaskBufferSize().Y; // バックバッファ分確保 for (csmUint32 i = 0; i < s_bufferSetNum; i++) @@ -803,7 +840,7 @@ void CubismRenderer_D3D9::Initialize(CubismModel* model) { _offscreenFrameBuffer[i].CreateOffscreenFrame( s_useDevice, - bufferHeight, bufferHeight); + bufferWidth, bufferHeight); } } } @@ -838,12 +875,12 @@ void CubismRenderer_D3D9::DoDrawModel() { _clippingManager->_colorBuffer = &_offscreenFrameBuffer[_commandBufferCurrent]; // サイズが違う場合はここで作成しなおし - if (_clippingManager->_colorBuffer->GetBufferWidth() != static_cast(_clippingManager->GetClippingMaskBufferSize()) || - _clippingManager->_colorBuffer->GetBufferHeight() != static_cast(_clippingManager->GetClippingMaskBufferSize())) + if (_clippingManager->_colorBuffer->GetBufferWidth() != static_cast(_clippingManager->GetClippingMaskBufferSize().X) || + _clippingManager->_colorBuffer->GetBufferHeight() != static_cast(_clippingManager->GetClippingMaskBufferSize().Y)) { _clippingManager->_colorBuffer->DestroyOffscreenFrame(); _clippingManager->_colorBuffer->CreateOffscreenFrame(s_useDevice, - static_cast(_clippingManager->GetClippingMaskBufferSize()), static_cast(_clippingManager->GetClippingMaskBufferSize())); + static_cast(_clippingManager->GetClippingMaskBufferSize().X), static_cast(_clippingManager->GetClippingMaskBufferSize().Y)); } _clippingManager->SetupClippingContext(s_useDevice, *GetModel(), this, *_clippingManager->_colorBuffer); @@ -893,8 +930,8 @@ void CubismRenderer_D3D9::DoDrawModel() GetRenderStateManager()->SetViewport(s_useDevice, 0, 0, - _clippingManager->GetClippingMaskBufferSize(), - _clippingManager->GetClippingMaskBufferSize(), + _clippingManager->GetClippingMaskBufferSize().X, + _clippingManager->GetClippingMaskBufferSize().Y, 0.0f, 1.0f); _clippingManager->_colorBuffer->BeginDraw(s_useDevice); @@ -1019,13 +1056,16 @@ void CubismRenderer_D3D9::ExecuteDraw(LPDIRECT3DDEVICE9 device, CubismVertexD3D9 if (GetAnisotropy() > 0.0) { - GetRenderStateManager()->SetTextureFilter(device, D3DTEXF_ANISOTROPIC, D3DTEXF_ANISOTROPIC, D3DTEXF_LINEAR, D3DTADDRESS_WRAP, D3DTADDRESS_WRAP, GetAnisotropy()); + GetRenderStateManager()->SetTextureFilter(device, 0, D3DTEXF_ANISOTROPIC, D3DTEXF_ANISOTROPIC, D3DTEXF_LINEAR, D3DTADDRESS_WRAP, D3DTADDRESS_WRAP, GetAnisotropy()); } else { - GetRenderStateManager()->SetTextureFilter(device, D3DTEXF_LINEAR, D3DTEXF_LINEAR, D3DTEXF_LINEAR, D3DTADDRESS_WRAP, D3DTADDRESS_WRAP); + GetRenderStateManager()->SetTextureFilter(device, 0, D3DTEXF_LINEAR, D3DTEXF_LINEAR, D3DTEXF_LINEAR, D3DTADDRESS_WRAP, D3DTADDRESS_WRAP); } + // マスクには線形補間を適用 + GetRenderStateManager()->SetTextureFilter(device, 1, D3DTEXF_LINEAR, D3DTEXF_LINEAR, D3DTEXF_LINEAR, D3DTADDRESS_WRAP, D3DTADDRESS_WRAP); + // 定数バッファ { csmRectF* rect = GetClippingContextBufferForMask()->_layoutBounds; @@ -1106,11 +1146,11 @@ void CubismRenderer_D3D9::ExecuteDraw(LPDIRECT3DDEVICE9 device, CubismVertexD3D9 if (GetAnisotropy() > 0.0) { - GetRenderStateManager()->SetTextureFilter(device, D3DTEXF_ANISOTROPIC, D3DTEXF_ANISOTROPIC, D3DTEXF_LINEAR, D3DTADDRESS_WRAP, D3DTADDRESS_WRAP, GetAnisotropy()); + GetRenderStateManager()->SetTextureFilter(device, 0, D3DTEXF_ANISOTROPIC, D3DTEXF_ANISOTROPIC, D3DTEXF_LINEAR, D3DTADDRESS_WRAP, D3DTADDRESS_WRAP, GetAnisotropy()); } else { - GetRenderStateManager()->SetTextureFilter(device, D3DTEXF_LINEAR, D3DTEXF_LINEAR, D3DTEXF_LINEAR, D3DTADDRESS_WRAP, D3DTADDRESS_WRAP); + GetRenderStateManager()->SetTextureFilter(device, 0, D3DTEXF_LINEAR, D3DTEXF_LINEAR, D3DTEXF_LINEAR, D3DTADDRESS_WRAP, D3DTADDRESS_WRAP); } ID3DXEffect* shaderEffect = shaderManager->GetShaderEffect(); @@ -1312,14 +1352,14 @@ const csmMap& CubismRenderer_D3D9::GetBindedTextur return _textures; } -void CubismRenderer_D3D9::SetClippingMaskBufferSize(csmInt32 size) +void CubismRenderer_D3D9::SetClippingMaskBufferSize(csmFloat32 width, csmFloat32 height) { //FrameBufferのサイズを変更するためにインスタンスを破棄・再作成する CSM_DELETE_SELF(CubismClippingManager_DX9, _clippingManager); _clippingManager = CSM_NEW CubismClippingManager_DX9(); - _clippingManager->SetClippingMaskBufferSize(size); + _clippingManager->SetClippingMaskBufferSize(width, height); _clippingManager->Initialize( *GetModel(), @@ -1329,11 +1369,16 @@ void CubismRenderer_D3D9::SetClippingMaskBufferSize(csmInt32 size) ); } -csmInt32 CubismRenderer_D3D9::GetClippingMaskBufferSize() const +CubismVector2 CubismRenderer_D3D9::GetClippingMaskBufferSize() const { return _clippingManager->GetClippingMaskBufferSize(); } +const csmVector& CubismRenderer_D3D9::GetMaskBuffer() const +{ + return _offscreenFrameBuffer; +} + void CubismRenderer_D3D9::InitializeConstantSettings(csmUint32 bufferSetNum, LPDIRECT3DDEVICE9 device) { s_bufferSetNum = bufferSetNum; @@ -1365,7 +1410,7 @@ void CubismRenderer_D3D9::SetDefaultRenderState() // フィルタ GetRenderStateManager()->SetTextureFilter(s_useDevice, - D3DTEXF_LINEAR, D3DTEXF_LINEAR, D3DTEXF_LINEAR, D3DTADDRESS_WRAP, D3DTADDRESS_WRAP + 0, D3DTEXF_LINEAR, D3DTEXF_LINEAR, D3DTEXF_LINEAR, D3DTADDRESS_WRAP, D3DTADDRESS_WRAP ); } diff --git a/src/Rendering/D3D9/CubismRenderer_D3D9.hpp b/src/Rendering/D3D9/CubismRenderer_D3D9.hpp index fec43f5..b136717 100644 --- a/src/Rendering/D3D9/CubismRenderer_D3D9.hpp +++ b/src/Rendering/D3D9/CubismRenderer_D3D9.hpp @@ -13,6 +13,7 @@ #include "CubismFramework.hpp" #include "Type/csmVector.hpp" #include "Type/csmRectF.hpp" +#include "Math/CubismVector2.hpp" #include "Type/csmMap.hpp" #include "Rendering/D3D9/CubismOffscreenSurface_D3D9.hpp" #include "CubismRenderState_D3D9.hpp" @@ -126,7 +127,7 @@ class CubismClippingManager_DX9 *@param size -> クリッピングマスクバッファのサイズ * */ - void SetClippingMaskBufferSize(csmInt32 size); + void SetClippingMaskBufferSize(csmFloat32 width, csmFloat32 height); /** *@brief クリッピングマスクバッファのサイズを取得する @@ -134,7 +135,7 @@ class CubismClippingManager_DX9 *@return クリッピングマスクバッファのサイズ * */ - csmInt32 GetClippingMaskBufferSize() const; + CubismVector2 GetClippingMaskBufferSize() const; CubismOffscreenFrame_D3D9* _colorBuffer; ///< マスク用カラーバッファーのアドレス csmInt32 _currentFrameNo; ///< マスクテクスチャに与えるフレーム番号 @@ -142,7 +143,7 @@ class CubismClippingManager_DX9 csmVector _channelColors; csmVector _clippingContextListForMask; ///< マスク用クリッピングコンテキストのリスト csmVector _clippingContextListForDraw; ///< 描画用クリッピングコンテキストのリスト - csmInt32 _clippingMaskBufferSize; ///< クリッピングマスクのバッファサイズ(初期値:256) + CubismVector2 _clippingMaskBufferSize; ///< クリッピングマスクのバッファサイズ(初期値:256) CubismMatrix44 _tmpMatrix; ///< マスク計算用の行列 CubismMatrix44 _tmpMatrixForMask; ///< マスク計算用の行列 @@ -310,7 +311,7 @@ class CubismRenderer_D3D9 : public CubismRenderer * @param[in] size -> クリッピングマスクバッファのサイズ * */ - void SetClippingMaskBufferSize(csmInt32 size); + void SetClippingMaskBufferSize(csmFloat32 width, csmFloat32 height); /** * @brief クリッピングマスクバッファのサイズを取得する @@ -318,7 +319,15 @@ class CubismRenderer_D3D9 : public CubismRenderer * @return クリッピングマスクバッファのサイズ * */ - csmInt32 GetClippingMaskBufferSize() const; + CubismVector2 GetClippingMaskBufferSize() const; + + /** + * @brief クリッピングマスクのバッファを取得する + * + * @return クリッピングマスクのバッファへの参照 + * + */ + const csmVector& GetMaskBuffer() const; /** * @brief 使用するシェーダの設定・コンスタントバッファの設定などを行い、描画を実行 diff --git a/src/Rendering/OpenGL/CubismRenderer_OpenGLES2.cpp b/src/Rendering/OpenGL/CubismRenderer_OpenGLES2.cpp index 5a58cf2..237af6d 100644 --- a/src/Rendering/OpenGL/CubismRenderer_OpenGLES2.cpp +++ b/src/Rendering/OpenGL/CubismRenderer_OpenGLES2.cpp @@ -28,7 +28,7 @@ const csmInt32 ColorChannelCount = 4; ///< 実験時に1チャンネルの場 CubismClippingManager_OpenGLES2::CubismClippingManager_OpenGLES2() : _currentFrameNo(0) - , _clippingMaskBufferSize(256) + , _clippingMaskBufferSize(256, 256) { CubismRenderer::CubismTextureColor* tmp; tmp = CSM_NEW CubismRenderer::CubismTextureColor(); @@ -165,7 +165,7 @@ void CubismClippingManager_OpenGLES2::SetupClippingContext(CubismModel& model, C if (!renderer->IsUsingHighPrecisionMask()) { // 生成したFrameBufferと同じサイズでビューポートを設定 - glViewport(0, 0, _clippingMaskBufferSize, _clippingMaskBufferSize); + glViewport(0, 0, _clippingMaskBufferSize.X, _clippingMaskBufferSize.Y); // モデル描画時にDrawMeshNowに渡される変換(モデルtoワールド座標変換) CubismMatrix44 modelToWorldF = renderer->GetMvpMatrix(); @@ -191,17 +191,54 @@ void CubismClippingManager_OpenGLES2::SetupClippingContext(CubismModel& model, C CubismClippingContext* clipContext = _clippingContextListForMask[clipIndex]; csmRectF* allClippedDrawRect = clipContext->_allClippedDrawRect; //このマスクを使う、全ての描画オブジェクトの論理座標上の囲み矩形 csmRectF* layoutBoundsOnTex01 = clipContext->_layoutBounds; //この中にマスクを収める - - // モデル座標上の矩形を、適宜マージンを付けて使う const csmFloat32 MARGIN = 0.05f; - _tmpBoundsOnModel.SetRect(allClippedDrawRect); - _tmpBoundsOnModel.Expand(allClippedDrawRect->Width * MARGIN, allClippedDrawRect->Height * MARGIN); - //########## 本来は割り当てられた領域の全体を使わず必要最低限のサイズがよい + csmFloat32 scaleX = 0.0f; + csmFloat32 scaleY = 0.0f; + + + if (renderer->IsUsingHighPrecisionMask()) + { + const csmFloat32 ppu = model.GetPixelsPerUnit(); + const csmFloat32 maskPixelWidth = clipContext->_owner->_clippingMaskBufferSize.X; + const csmFloat32 maskPixelHeight = clipContext->_owner->_clippingMaskBufferSize.Y; + const csmFloat32 physicalMaskWidth = layoutBoundsOnTex01->Width * maskPixelWidth; + const csmFloat32 physicalMaskHeight = layoutBoundsOnTex01->Height * maskPixelHeight; + + + _tmpBoundsOnModel.SetRect(allClippedDrawRect); + + if (_tmpBoundsOnModel.Width * ppu > physicalMaskWidth) + { + _tmpBoundsOnModel.Expand(allClippedDrawRect->Width * MARGIN, 0.0f); + scaleX = layoutBoundsOnTex01->Width / _tmpBoundsOnModel.Width; + } + else + { + scaleX = ppu / physicalMaskWidth; + } + + if (_tmpBoundsOnModel.Height * ppu > physicalMaskHeight) + { + _tmpBoundsOnModel.Expand(0.0f, allClippedDrawRect->Height * MARGIN); + scaleY = layoutBoundsOnTex01->Height / _tmpBoundsOnModel.Height; + } + else + { + scaleY = ppu / physicalMaskHeight; + } + } + else + { + // モデル座標上の矩形を、適宜マージンを付けて使う + _tmpBoundsOnModel.SetRect(allClippedDrawRect); + _tmpBoundsOnModel.Expand(allClippedDrawRect->Width * MARGIN, allClippedDrawRect->Height * MARGIN); + //########## 本来は割り当てられた領域の全体を使わず必要最低限のサイズがよい + // シェーダ用の計算式を求める。回転を考慮しない場合は以下のとおり + // movePeriod' = movePeriod * scaleX + offX [[ movePeriod' = (movePeriod - tmpBoundsOnModel.movePeriod)*scale + layoutBoundsOnTex01.movePeriod ]] + scaleX = layoutBoundsOnTex01->Width / _tmpBoundsOnModel.Width; + scaleY = layoutBoundsOnTex01->Height / _tmpBoundsOnModel.Height; + } - // シェーダ用の計算式を求める。回転を考慮しない場合は以下のとおり - // movePeriod' = movePeriod * scaleX + offX [[ movePeriod' = (movePeriod - tmpBoundsOnModel.movePeriod)*scale + layoutBoundsOnTex01.movePeriod ]] - const csmFloat32 scaleX = layoutBoundsOnTex01->Width / _tmpBoundsOnModel.Width; - const csmFloat32 scaleY = layoutBoundsOnTex01->Height / _tmpBoundsOnModel.Height; // マスク生成時に使う行列を求める { @@ -288,7 +325,7 @@ void CubismClippingManager_OpenGLES2::CalcClippedDrawTotalBounds(CubismModel& mo { // 被クリッピングマスク(マスクされる描画オブジェクト)の全体の矩形 csmFloat32 clippedDrawTotalMinX = FLT_MAX, clippedDrawTotalMinY = FLT_MAX; - csmFloat32 clippedDrawTotalMaxX = FLT_MIN, clippedDrawTotalMaxY = FLT_MIN; + csmFloat32 clippedDrawTotalMaxX = -FLT_MAX, clippedDrawTotalMaxY = -FLT_MAX; // このマスクが実際に必要か判定する // このクリッピングを利用する「描画オブジェクト」がひとつでも使用可能であればマスクを生成する必要がある @@ -303,7 +340,7 @@ void CubismClippingManager_OpenGLES2::CalcClippedDrawTotalBounds(CubismModel& mo csmFloat32* drawableVertexes = const_cast(model.GetDrawableVertices(drawableIndex)); csmFloat32 minX = FLT_MAX, minY = FLT_MAX; - csmFloat32 maxX = FLT_MIN, maxY = FLT_MIN; + csmFloat32 maxX = -FLT_MAX, maxY = -FLT_MAX; csmInt32 loop = drawableVertexCount * Constant::VertexStep; for (csmInt32 pi = Constant::VertexOffset; pi < loop; pi += Constant::VertexStep) @@ -473,12 +510,12 @@ csmVector* CubismClippingManager_OpenGLES2::GetClippingC return &_clippingContextListForDraw; } -void CubismClippingManager_OpenGLES2::SetClippingMaskBufferSize(csmInt32 size) +void CubismClippingManager_OpenGLES2::SetClippingMaskBufferSize(csmFloat32 width, csmFloat32 height) { - _clippingMaskBufferSize = size; + _clippingMaskBufferSize = CubismVector2(width, height); } -csmInt32 CubismClippingManager_OpenGLES2::GetClippingMaskBufferSize() const +CubismVector2 CubismClippingManager_OpenGLES2::GetClippingMaskBufferSize() const { return _clippingMaskBufferSize; } @@ -1773,7 +1810,7 @@ void CubismRenderer_OpenGLES2::Initialize(CubismModel* model) model->GetDrawableMaskCounts() ); - _offscreenFrameBuffer.CreateOffscreenFrame(_clippingManager->GetClippingMaskBufferSize(), _clippingManager->GetClippingMaskBufferSize()); + _offscreenFrameBuffer.CreateOffscreenFrame(_clippingManager->GetClippingMaskBufferSize().X, _clippingManager->GetClippingMaskBufferSize().Y); } _sortedDrawableIndexList.Resize(model->GetDrawableCount(), 0); @@ -1822,12 +1859,12 @@ void CubismRenderer_OpenGLES2::DoDrawModel() PreDraw(); // サイズが違う場合はここで作成しなおし - if (_offscreenFrameBuffer.GetBufferWidth() != static_cast(_clippingManager->GetClippingMaskBufferSize()) || - _offscreenFrameBuffer.GetBufferHeight() != static_cast(_clippingManager->GetClippingMaskBufferSize())) + if (_offscreenFrameBuffer.GetBufferWidth() != static_cast(_clippingManager->GetClippingMaskBufferSize().X) || + _offscreenFrameBuffer.GetBufferHeight() != static_cast(_clippingManager->GetClippingMaskBufferSize().Y)) { _offscreenFrameBuffer.DestroyOffscreenFrame(); _offscreenFrameBuffer.CreateOffscreenFrame( - static_cast(_clippingManager->GetClippingMaskBufferSize()), static_cast(_clippingManager->GetClippingMaskBufferSize())); + static_cast(_clippingManager->GetClippingMaskBufferSize().X), static_cast(_clippingManager->GetClippingMaskBufferSize().Y)); } _clippingManager->SetupClippingContext(*GetModel(), this, _rendererProfile._lastFBO, _rendererProfile._lastViewport); @@ -1867,7 +1904,7 @@ void CubismRenderer_OpenGLES2::DoDrawModel() if(clipContext->_isUsing) // 書くことになっていた { // 生成したFrameBufferと同じサイズでビューポートを設定 - glViewport(0, 0, _clippingManager->GetClippingMaskBufferSize(), _clippingManager->GetClippingMaskBufferSize()); + glViewport(0, 0, _clippingManager->GetClippingMaskBufferSize().X, _clippingManager->GetClippingMaskBufferSize().Y); PreDraw(); // バッファをクリアする @@ -2028,14 +2065,14 @@ const csmMap& CubismRenderer_OpenGLES2::GetBindedTextures() co return _textures; } -void CubismRenderer_OpenGLES2::SetClippingMaskBufferSize(csmInt32 size) +void CubismRenderer_OpenGLES2::SetClippingMaskBufferSize(csmFloat32 width, csmFloat32 height) { //FrameBufferのサイズを変更するためにインスタンスを破棄・再作成する CSM_DELETE_SELF(CubismClippingManager_OpenGLES2, _clippingManager); _clippingManager = CSM_NEW CubismClippingManager_OpenGLES2(); - _clippingManager->SetClippingMaskBufferSize(size); + _clippingManager->SetClippingMaskBufferSize(width, height); _clippingManager->Initialize( *GetModel(), @@ -2045,11 +2082,16 @@ void CubismRenderer_OpenGLES2::SetClippingMaskBufferSize(csmInt32 size) ); } -csmInt32 CubismRenderer_OpenGLES2::GetClippingMaskBufferSize() const +CubismVector2 CubismRenderer_OpenGLES2::GetClippingMaskBufferSize() const { return _clippingManager->GetClippingMaskBufferSize(); } +const CubismOffscreenFrame_OpenGLES2* CubismRenderer_OpenGLES2::GetMaskBuffer() const +{ + return &_offscreenFrameBuffer; +} + void CubismRenderer_OpenGLES2::SetClippingContextBufferForMask(CubismClippingContext* clip) { _clippingContextBufferForMask = clip; diff --git a/src/Rendering/OpenGL/CubismRenderer_OpenGLES2.hpp b/src/Rendering/OpenGL/CubismRenderer_OpenGLES2.hpp index 821528c..6c55cbe 100644 --- a/src/Rendering/OpenGL/CubismRenderer_OpenGLES2.hpp +++ b/src/Rendering/OpenGL/CubismRenderer_OpenGLES2.hpp @@ -12,6 +12,7 @@ #include "CubismOffscreenSurface_OpenGLES2.hpp" #include "Type/csmVector.hpp" #include "Type/csmRectF.hpp" +#include "Math/CubismVector2.hpp" #include "Type/csmMap.hpp" #ifdef CSM_TARGET_ANDROID_ES2 @@ -135,7 +136,7 @@ class CubismClippingManager_OpenGLES2 *@param size -> クリッピングマスクバッファのサイズ * */ - void SetClippingMaskBufferSize(csmInt32 size); + void SetClippingMaskBufferSize(csmFloat32 width, csmFloat32 height); /** *@brief クリッピングマスクバッファのサイズを取得する @@ -143,14 +144,14 @@ class CubismClippingManager_OpenGLES2 *@return クリッピングマスクバッファのサイズ * */ - csmInt32 GetClippingMaskBufferSize() const; + CubismVector2 GetClippingMaskBufferSize() const; csmInt32 _currentFrameNo; ///< マスクテクスチャに与えるフレーム番号 csmVector _channelColors; csmVector _clippingContextListForMask; ///< マスク用クリッピングコンテキストのリスト csmVector _clippingContextListForDraw; ///< 描画用クリッピングコンテキストのリスト - csmInt32 _clippingMaskBufferSize; ///< クリッピングマスクのバッファサイズ(初期値:256) + CubismVector2 _clippingMaskBufferSize; ///< クリッピングマスクのバッファサイズ(初期値:256) CubismMatrix44 _tmpMatrix; ///< マスク計算用の行列 CubismMatrix44 _tmpMatrixForMask; ///< マスク計算用の行列 @@ -458,7 +459,7 @@ class CubismRenderer_OpenGLES2 : public CubismRenderer * @param[in] size -> クリッピングマスクバッファのサイズ * */ - void SetClippingMaskBufferSize(csmInt32 size); + void SetClippingMaskBufferSize(csmFloat32 width, csmFloat32 height); /** * @brief クリッピングマスクバッファのサイズを取得する @@ -466,8 +467,15 @@ class CubismRenderer_OpenGLES2 : public CubismRenderer * @return クリッピングマスクバッファのサイズ * */ - csmInt32 GetClippingMaskBufferSize() const; + CubismVector2 GetClippingMaskBufferSize() const; + /** + * @brief クリッピングマスクのバッファを取得する + * + * @return クリッピングマスクのバッファへのポインタ + * + */ + const CubismOffscreenFrame_OpenGLES2* GetMaskBuffer() const; protected: /** * @brief コンストラクタ From 523f6175f33c5d64a696ec9832e3d40632eeb622 Mon Sep 17 00:00:00 2001 From: ito Date: Thu, 10 Jun 2021 11:23:07 +0900 Subject: [PATCH 2/2] Update to Cubism 4 SDK for Native R3 --- CHANGELOG.md | 3 +++ README.md | 6 +----- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 19005f0..bb2f371 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). +## [4-r.3] - 2021-06-10 + ## [4-r.3-beta.1] - 2021-05-13 ### Added @@ -98,6 +100,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). * Fix invalid expressions of `CubismCdiJson`. +[4-r.3]: https://github.com/Live2D/CubismNativeFramework/compare/4-r.3-beta.1...4-r.3 [4-r.3-beta.1]: https://github.com/Live2D/CubismNativeFramework/compare/4-r.2...4-r.3-beta.1 [4-r.2]: https://github.com/Live2D/CubismNativeFramework/compare/4-r.1...4-r.2 [4-r.1]: https://github.com/Live2D/CubismNativeFramework/compare/4-beta.2...4-r.1 diff --git a/README.md b/README.md index 7d2d742..e1fb571 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,10 @@ -# \[Beta Version\] Cubism Native Framework +# Cubism Native Framework Live2D Cubism 4 Editor で出力したモデルをアプリケーションで利用するためのフレームワークです。 モデルを表示、操作するための各種機能を提供します。 モデルをロードするには Cubism Core ライブラリと組み合わせて使用します。 -**本 SDK は、 Beta バージョンとなります。先行して新機能を取り込んでいるため、不安定な挙動を示す場合がございます。安定した製品をお求めの方は、公式サイトから配布されている正式版のパッケージ又は `develop` `master` ブランチをご利用ください。** - -**\[Beta Version\] の SDK の不具合、各種ご意見等に関しましては、 Live2D コミュニティ にてご連絡ください。直接のコードに対する指摘、修正等は、直接 Pull requests としてご投稿ください。** - ## ライセンス