OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2012 The Android Open Source Project | 2 * Copyright 2012 The Android Open Source Project |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkLightingImageFilter.h" | 8 #include "SkLightingImageFilter.h" |
9 #include "SkBitmap.h" | 9 #include "SkBitmap.h" |
10 #include "SkColorPriv.h" | 10 #include "SkColorPriv.h" |
(...skipping 1319 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1330 delete fLight; | 1330 delete fLight; |
1331 } | 1331 } |
1332 | 1332 |
1333 void GrGLLightingEffect::emitCode(GrGLFPBuilder* builder, | 1333 void GrGLLightingEffect::emitCode(GrGLFPBuilder* builder, |
1334 const GrFragmentProcessor&, | 1334 const GrFragmentProcessor&, |
1335 const char* outputColor, | 1335 const char* outputColor, |
1336 const char* inputColor, | 1336 const char* inputColor, |
1337 const TransformedCoordsArray& coords, | 1337 const TransformedCoordsArray& coords, |
1338 const TextureSamplerArray& samplers) { | 1338 const TextureSamplerArray& samplers) { |
1339 fImageIncrementUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visib
ility, | 1339 fImageIncrementUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visib
ility, |
1340 kVec2f_GrSLType, | 1340 kVec2f_GrSLType, kDefault_GrSLPrec
ision, |
1341 "ImageIncrement"); | 1341 "ImageIncrement"); |
1342 fSurfaceScaleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibil
ity, | 1342 fSurfaceScaleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibil
ity, |
1343 kFloat_GrSLType, | 1343 kFloat_GrSLType, kDefault_GrSLPrecisi
on, |
1344 "SurfaceScale"); | 1344 "SurfaceScale"); |
1345 fLight->emitLightColorUniform(builder); | 1345 fLight->emitLightColorUniform(builder); |
1346 SkString lightFunc; | 1346 SkString lightFunc; |
1347 this->emitLightFunc(builder, &lightFunc); | 1347 this->emitLightFunc(builder, &lightFunc); |
1348 static const GrGLShaderVar gSobelArgs[] = { | 1348 static const GrGLShaderVar gSobelArgs[] = { |
1349 GrGLShaderVar("a", kFloat_GrSLType), | 1349 GrGLShaderVar("a", kFloat_GrSLType), |
1350 GrGLShaderVar("b", kFloat_GrSLType), | 1350 GrGLShaderVar("b", kFloat_GrSLType), |
1351 GrGLShaderVar("c", kFloat_GrSLType), | 1351 GrGLShaderVar("c", kFloat_GrSLType), |
1352 GrGLShaderVar("d", kFloat_GrSLType), | 1352 GrGLShaderVar("d", kFloat_GrSLType), |
1353 GrGLShaderVar("e", kFloat_GrSLType), | 1353 GrGLShaderVar("e", kFloat_GrSLType), |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1446 | 1446 |
1447 /////////////////////////////////////////////////////////////////////////////// | 1447 /////////////////////////////////////////////////////////////////////////////// |
1448 | 1448 |
1449 GrGLDiffuseLightingEffect::GrGLDiffuseLightingEffect(const GrProcessor& proc) | 1449 GrGLDiffuseLightingEffect::GrGLDiffuseLightingEffect(const GrProcessor& proc) |
1450 : INHERITED(proc) { | 1450 : INHERITED(proc) { |
1451 } | 1451 } |
1452 | 1452 |
1453 void GrGLDiffuseLightingEffect::emitLightFunc(GrGLFPBuilder* builder, SkString*
funcName) { | 1453 void GrGLDiffuseLightingEffect::emitLightFunc(GrGLFPBuilder* builder, SkString*
funcName) { |
1454 const char* kd; | 1454 const char* kd; |
1455 fKDUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, | 1455 fKDUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, |
1456 kFloat_GrSLType, | 1456 kFloat_GrSLType, kDefault_GrSLPrecision, |
1457 "KD", | 1457 "KD", &kd); |
1458 &kd); | |
1459 | 1458 |
1460 static const GrGLShaderVar gLightArgs[] = { | 1459 static const GrGLShaderVar gLightArgs[] = { |
1461 GrGLShaderVar("normal", kVec3f_GrSLType), | 1460 GrGLShaderVar("normal", kVec3f_GrSLType), |
1462 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType), | 1461 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType), |
1463 GrGLShaderVar("lightColor", kVec3f_GrSLType) | 1462 GrGLShaderVar("lightColor", kVec3f_GrSLType) |
1464 }; | 1463 }; |
1465 SkString lightBody; | 1464 SkString lightBody; |
1466 lightBody.appendf("\tfloat colorScale = %s * dot(normal, surfaceToLight);\n"
, kd); | 1465 lightBody.appendf("\tfloat colorScale = %s * dot(normal, surfaceToLight);\n"
, kd); |
1467 lightBody.appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1
.0);\n"); | 1466 lightBody.appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1
.0);\n"); |
1468 builder->getFragmentShaderBuilder()->emitFunction(kVec4f_GrSLType, | 1467 builder->getFragmentShaderBuilder()->emitFunction(kVec4f_GrSLType, |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1532 | 1531 |
1533 GrGLSpecularLightingEffect::GrGLSpecularLightingEffect(const GrProcessor& proc) | 1532 GrGLSpecularLightingEffect::GrGLSpecularLightingEffect(const GrProcessor& proc) |
1534 : INHERITED(proc) { | 1533 : INHERITED(proc) { |
1535 } | 1534 } |
1536 | 1535 |
1537 void GrGLSpecularLightingEffect::emitLightFunc(GrGLFPBuilder* builder, SkString*
funcName) { | 1536 void GrGLSpecularLightingEffect::emitLightFunc(GrGLFPBuilder* builder, SkString*
funcName) { |
1538 const char* ks; | 1537 const char* ks; |
1539 const char* shininess; | 1538 const char* shininess; |
1540 | 1539 |
1541 fKSUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, | 1540 fKSUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, |
1542 kFloat_GrSLType, "KS", &ks); | 1541 kFloat_GrSLType, kDefault_GrSLPrecision, "KS",
&ks); |
1543 fShininessUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility
, | 1542 fShininessUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility
, |
1544 kFloat_GrSLType, "Shininess", &shininess
); | 1543 kFloat_GrSLType, kDefault_GrSLPrecision,
"Shininess", &shininess); |
1545 | 1544 |
1546 static const GrGLShaderVar gLightArgs[] = { | 1545 static const GrGLShaderVar gLightArgs[] = { |
1547 GrGLShaderVar("normal", kVec3f_GrSLType), | 1546 GrGLShaderVar("normal", kVec3f_GrSLType), |
1548 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType), | 1547 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType), |
1549 GrGLShaderVar("lightColor", kVec3f_GrSLType) | 1548 GrGLShaderVar("lightColor", kVec3f_GrSLType) |
1550 }; | 1549 }; |
1551 SkString lightBody; | 1550 SkString lightBody; |
1552 lightBody.appendf("\tvec3 halfDir = vec3(normalize(surfaceToLight + vec3(0,
0, 1)));\n"); | 1551 lightBody.appendf("\tvec3 halfDir = vec3(normalize(surfaceToLight + vec3(0,
0, 1)));\n"); |
1553 lightBody.appendf("\tfloat colorScale = %s * pow(dot(normal, halfDir), %s);\
n", ks, shininess); | 1552 lightBody.appendf("\tfloat colorScale = %s * pow(dot(normal, halfDir), %s);\
n", ks, shininess); |
1554 lightBody.appendf("\tvec3 color = lightColor * clamp(colorScale, 0.0, 1.0);\
n"); | 1553 lightBody.appendf("\tvec3 color = lightColor * clamp(colorScale, 0.0, 1.0);\
n"); |
(...skipping 10 matching lines...) Expand all Loading... |
1565 const GrProcessor& effect) { | 1564 const GrProcessor& effect) { |
1566 INHERITED::setData(pdman, effect); | 1565 INHERITED::setData(pdman, effect); |
1567 const GrSpecularLightingEffect& spec = effect.cast<GrSpecularLightingEffect>
(); | 1566 const GrSpecularLightingEffect& spec = effect.cast<GrSpecularLightingEffect>
(); |
1568 pdman.set1f(fKSUni, spec.ks()); | 1567 pdman.set1f(fKSUni, spec.ks()); |
1569 pdman.set1f(fShininessUni, spec.shininess()); | 1568 pdman.set1f(fShininessUni, spec.shininess()); |
1570 } | 1569 } |
1571 | 1570 |
1572 /////////////////////////////////////////////////////////////////////////////// | 1571 /////////////////////////////////////////////////////////////////////////////// |
1573 void GrGLLight::emitLightColorUniform(GrGLFPBuilder* builder) { | 1572 void GrGLLight::emitLightColorUniform(GrGLFPBuilder* builder) { |
1574 fColorUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, | 1573 fColorUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, |
1575 kVec3f_GrSLType, "LightColor"); | 1574 kVec3f_GrSLType, kDefault_GrSLPrecision, |
| 1575 "LightColor"); |
1576 } | 1576 } |
1577 | 1577 |
1578 void GrGLLight::emitLightColor(GrGLFPBuilder* builder, | 1578 void GrGLLight::emitLightColor(GrGLFPBuilder* builder, |
1579 const char *surfaceToLight) { | 1579 const char *surfaceToLight) { |
1580 builder->getFragmentShaderBuilder()->codeAppend(builder->getUniformCStr(this
->lightColorUni())); | 1580 builder->getFragmentShaderBuilder()->codeAppend(builder->getUniformCStr(this
->lightColorUni())); |
1581 } | 1581 } |
1582 | 1582 |
1583 void GrGLLight::setData(const GrGLProgramDataManager& pdman, | 1583 void GrGLLight::setData(const GrGLProgramDataManager& pdman, |
1584 const SkLight* light) const { | 1584 const SkLight* light) const { |
1585 setUniformPoint3(pdman, fColorUni, light->color() * SkScalarInvert(SkIntToSc
alar(255))); | 1585 setUniformPoint3(pdman, fColorUni, light->color() * SkScalarInvert(SkIntToSc
alar(255))); |
1586 } | 1586 } |
1587 | 1587 |
1588 /////////////////////////////////////////////////////////////////////////////// | 1588 /////////////////////////////////////////////////////////////////////////////// |
1589 | 1589 |
1590 void GrGLDistantLight::setData(const GrGLProgramDataManager& pdman, | 1590 void GrGLDistantLight::setData(const GrGLProgramDataManager& pdman, |
1591 const SkLight* light) const { | 1591 const SkLight* light) const { |
1592 INHERITED::setData(pdman, light); | 1592 INHERITED::setData(pdman, light); |
1593 SkASSERT(light->type() == SkLight::kDistant_LightType); | 1593 SkASSERT(light->type() == SkLight::kDistant_LightType); |
1594 const SkDistantLight* distantLight = static_cast<const SkDistantLight*>(ligh
t); | 1594 const SkDistantLight* distantLight = static_cast<const SkDistantLight*>(ligh
t); |
1595 setUniformNormal3(pdman, fDirectionUni, distantLight->direction()); | 1595 setUniformNormal3(pdman, fDirectionUni, distantLight->direction()); |
1596 } | 1596 } |
1597 | 1597 |
1598 void GrGLDistantLight::emitSurfaceToLight(GrGLFPBuilder* builder, const char* z)
{ | 1598 void GrGLDistantLight::emitSurfaceToLight(GrGLFPBuilder* builder, const char* z)
{ |
1599 const char* dir; | 1599 const char* dir; |
1600 fDirectionUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility
, kVec3f_GrSLType, | 1600 fDirectionUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility
, |
| 1601 kVec3f_GrSLType, kDefault_GrSLPrecision, |
1601 "LightDirection", &dir); | 1602 "LightDirection", &dir); |
1602 builder->getFragmentShaderBuilder()->codeAppend(dir); | 1603 builder->getFragmentShaderBuilder()->codeAppend(dir); |
1603 } | 1604 } |
1604 | 1605 |
1605 /////////////////////////////////////////////////////////////////////////////// | 1606 /////////////////////////////////////////////////////////////////////////////// |
1606 | 1607 |
1607 void GrGLPointLight::setData(const GrGLProgramDataManager& pdman, | 1608 void GrGLPointLight::setData(const GrGLProgramDataManager& pdman, |
1608 const SkLight* light) const { | 1609 const SkLight* light) const { |
1609 INHERITED::setData(pdman, light); | 1610 INHERITED::setData(pdman, light); |
1610 SkASSERT(light->type() == SkLight::kPoint_LightType); | 1611 SkASSERT(light->type() == SkLight::kPoint_LightType); |
1611 const SkPointLight* pointLight = static_cast<const SkPointLight*>(light); | 1612 const SkPointLight* pointLight = static_cast<const SkPointLight*>(light); |
1612 setUniformPoint3(pdman, fLocationUni, pointLight->location()); | 1613 setUniformPoint3(pdman, fLocationUni, pointLight->location()); |
1613 } | 1614 } |
1614 | 1615 |
1615 void GrGLPointLight::emitSurfaceToLight(GrGLFPBuilder* builder, const char* z) { | 1616 void GrGLPointLight::emitSurfaceToLight(GrGLFPBuilder* builder, const char* z) { |
1616 const char* loc; | 1617 const char* loc; |
1617 fLocationUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
kVec3f_GrSLType, | 1618 fLocationUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, |
| 1619 kVec3f_GrSLType, kDefault_GrSLPrecision, |
1618 "LightLocation", &loc); | 1620 "LightLocation", &loc); |
1619 GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder(); | 1621 GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder(); |
1620 fsBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))", | 1622 fsBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))", |
1621 loc, fsBuilder->fragmentPosition(), z); | 1623 loc, fsBuilder->fragmentPosition(), z); |
1622 } | 1624 } |
1623 | 1625 |
1624 /////////////////////////////////////////////////////////////////////////////// | 1626 /////////////////////////////////////////////////////////////////////////////// |
1625 | 1627 |
1626 void GrGLSpotLight::setData(const GrGLProgramDataManager& pdman, | 1628 void GrGLSpotLight::setData(const GrGLProgramDataManager& pdman, |
1627 const SkLight* light) const { | 1629 const SkLight* light) const { |
1628 INHERITED::setData(pdman, light); | 1630 INHERITED::setData(pdman, light); |
1629 SkASSERT(light->type() == SkLight::kSpot_LightType); | 1631 SkASSERT(light->type() == SkLight::kSpot_LightType); |
1630 const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light); | 1632 const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light); |
1631 setUniformPoint3(pdman, fLocationUni, spotLight->location()); | 1633 setUniformPoint3(pdman, fLocationUni, spotLight->location()); |
1632 pdman.set1f(fExponentUni, spotLight->specularExponent()); | 1634 pdman.set1f(fExponentUni, spotLight->specularExponent()); |
1633 pdman.set1f(fCosInnerConeAngleUni, spotLight->cosInnerConeAngle()); | 1635 pdman.set1f(fCosInnerConeAngleUni, spotLight->cosInnerConeAngle()); |
1634 pdman.set1f(fCosOuterConeAngleUni, spotLight->cosOuterConeAngle()); | 1636 pdman.set1f(fCosOuterConeAngleUni, spotLight->cosOuterConeAngle()); |
1635 pdman.set1f(fConeScaleUni, spotLight->coneScale()); | 1637 pdman.set1f(fConeScaleUni, spotLight->coneScale()); |
1636 setUniformNormal3(pdman, fSUni, spotLight->s()); | 1638 setUniformNormal3(pdman, fSUni, spotLight->s()); |
1637 } | 1639 } |
1638 | 1640 |
1639 void GrGLSpotLight::emitSurfaceToLight(GrGLFPBuilder* builder, const char* z) { | 1641 void GrGLSpotLight::emitSurfaceToLight(GrGLFPBuilder* builder, const char* z) { |
1640 const char* location; | 1642 const char* location; |
1641 fLocationUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, | 1643 fLocationUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, |
1642 kVec3f_GrSLType, "LightLocation", &locati
on); | 1644 kVec3f_GrSLType, kDefault_GrSLPrecision, |
| 1645 "LightLocation", &location); |
1643 | 1646 |
1644 GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder(); | 1647 GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder(); |
1645 fsBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))", | 1648 fsBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))", |
1646 location, fsBuilder->fragmentPosition(), z); | 1649 location, fsBuilder->fragmentPosition(), z); |
1647 } | 1650 } |
1648 | 1651 |
1649 void GrGLSpotLight::emitLightColor(GrGLFPBuilder* builder, | 1652 void GrGLSpotLight::emitLightColor(GrGLFPBuilder* builder, |
1650 const char *surfaceToLight) { | 1653 const char *surfaceToLight) { |
1651 | 1654 |
1652 const char* color = builder->getUniformCStr(this->lightColorUni()); // creat
ed by parent class. | 1655 const char* color = builder->getUniformCStr(this->lightColorUni()); // creat
ed by parent class. |
1653 | 1656 |
1654 const char* exponent; | 1657 const char* exponent; |
1655 const char* cosInner; | 1658 const char* cosInner; |
1656 const char* cosOuter; | 1659 const char* cosOuter; |
1657 const char* coneScale; | 1660 const char* coneScale; |
1658 const char* s; | 1661 const char* s; |
1659 fExponentUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, | 1662 fExponentUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, |
1660 kFloat_GrSLType, "Exponent", &exponent); | 1663 kFloat_GrSLType, kDefault_GrSLPrecision, |
| 1664 "Exponent", &exponent); |
1661 fCosInnerConeAngleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Vi
sibility, | 1665 fCosInnerConeAngleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Vi
sibility, |
1662 kFloat_GrSLType, "CosInnerConeAn
gle", &cosInner); | 1666 kFloat_GrSLType, kDefault_GrSLPr
ecision, |
| 1667 "CosInnerConeAngle", &cosInner); |
1663 fCosOuterConeAngleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Vi
sibility, | 1668 fCosOuterConeAngleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Vi
sibility, |
1664 kFloat_GrSLType, "CosOuterConeAn
gle", &cosOuter); | 1669 kFloat_GrSLType, kDefault_GrSLPr
ecision, |
| 1670 "CosOuterConeAngle", &cosOuter); |
1665 fConeScaleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility
, | 1671 fConeScaleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility
, |
1666 kFloat_GrSLType, "ConeScale", &coneScale
); | 1672 kFloat_GrSLType, kDefault_GrSLPrecision, |
| 1673 "ConeScale", &coneScale); |
1667 fSUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, | 1674 fSUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, |
1668 kVec3f_GrSLType, "S", &s); | 1675 kVec3f_GrSLType, kDefault_GrSLPrecision, "S", &s
); |
1669 | 1676 |
1670 static const GrGLShaderVar gLightColorArgs[] = { | 1677 static const GrGLShaderVar gLightColorArgs[] = { |
1671 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType) | 1678 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType) |
1672 }; | 1679 }; |
1673 SkString lightColorBody; | 1680 SkString lightColorBody; |
1674 lightColorBody.appendf("\tfloat cosAngle = -dot(surfaceToLight, %s);\n", s); | 1681 lightColorBody.appendf("\tfloat cosAngle = -dot(surfaceToLight, %s);\n", s); |
1675 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosOuter); | 1682 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosOuter); |
1676 lightColorBody.appendf("\t\treturn vec3(0);\n"); | 1683 lightColorBody.appendf("\t\treturn vec3(0);\n"); |
1677 lightColorBody.appendf("\t}\n"); | 1684 lightColorBody.appendf("\t}\n"); |
1678 lightColorBody.appendf("\tfloat scale = pow(cosAngle, %s);\n", exponent); | 1685 lightColorBody.appendf("\tfloat scale = pow(cosAngle, %s);\n", exponent); |
(...skipping 12 matching lines...) Expand all Loading... |
1691 | 1698 |
1692 fsBuilder->codeAppendf("%s(%s)", fLightColorFunc.c_str(), surfaceToLight); | 1699 fsBuilder->codeAppendf("%s(%s)", fLightColorFunc.c_str(), surfaceToLight); |
1693 } | 1700 } |
1694 | 1701 |
1695 #endif | 1702 #endif |
1696 | 1703 |
1697 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingImageFilter) | 1704 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingImageFilter) |
1698 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiffuseLightingImageFilter) | 1705 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiffuseLightingImageFilter) |
1699 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpecularLightingImageFilter) | 1706 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpecularLightingImageFilter) |
1700 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END | 1707 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END |
OLD | NEW |