Remove generalized gradient code
BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2223203003 Committed: https://skia.googlesource.com/skia/+/0c63006b88a16e3418d92852a62771615799839d Review-Url: https://codereview.chromium.org/2223203003
This commit is contained in:
parent
88b138da99
commit
99818d6937
@ -228,21 +228,8 @@ void SkGradientShaderBase::flatten(SkWriteBuffer& buffer) const {
|
||||
desc.flatten(buffer);
|
||||
}
|
||||
|
||||
SkGradientShaderBase::GpuColorType SkGradientShaderBase::getGpuColorType(SkColor colors[3]) const {
|
||||
if (fColorCount <= 3) {
|
||||
memcpy(colors, fOrigColors, fColorCount * sizeof(SkColor));
|
||||
}
|
||||
|
||||
if (SkShader::kClamp_TileMode == fTileMode) {
|
||||
if (2 == fColorCount) {
|
||||
return kTwo_GpuColorType;
|
||||
} else if (3 == fColorCount &&
|
||||
(SkScalarAbs(
|
||||
SkFixedToScalar(fRecs[1].fPos) - SK_ScalarHalf) < SK_Scalar1 / 1000)) {
|
||||
return kThree_GpuColorType;
|
||||
}
|
||||
}
|
||||
return kTexture_GpuColorType;
|
||||
static inline bool close_to_one_half(const SkFixed& val) {
|
||||
return SkScalarNearlyEqual(SkFixedToScalar(val), SK_ScalarHalf);
|
||||
}
|
||||
|
||||
void SkGradientShaderBase::FlipGradientColors(SkColor* colorDst, Rec* recDst,
|
||||
@ -911,114 +898,187 @@ SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
|
||||
#include "glsl/GrGLSLUniformHandler.h"
|
||||
#include "SkGr.h"
|
||||
|
||||
GrGradientEffect::GLSLProcessor::GLSLProcessor()
|
||||
: fCachedYCoord(SK_ScalarMax) {
|
||||
static inline int color_type_to_color_count(GrGradientEffect::ColorType colorType) {
|
||||
switch (colorType) {
|
||||
#if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS
|
||||
case GrGradientEffect::kHardStopCentered_ColorType:
|
||||
return 4;
|
||||
case GrGradientEffect::kHardStopLeftEdged_ColorType:
|
||||
case GrGradientEffect::kHardStopRightEdged_ColorType:
|
||||
return 3;
|
||||
#endif
|
||||
case GrGradientEffect::kTwo_ColorType:
|
||||
return 2;
|
||||
case GrGradientEffect::kThree_ColorType:
|
||||
return 3;
|
||||
case GrGradientEffect::kTexture_ColorType:
|
||||
return 0;
|
||||
}
|
||||
|
||||
SkDEBUGFAIL("Unhandled ColorType in color_type_to_color_count()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
GrGradientEffect::ColorType GrGradientEffect::determineColorType(
|
||||
const SkGradientShaderBase& shader) {
|
||||
#if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS
|
||||
if (shader.fOrigPos) {
|
||||
if (4 == shader.fColorCount) {
|
||||
if (SkScalarNearlyEqual(shader.fOrigPos[0], 0.0f) &&
|
||||
SkScalarNearlyEqual(shader.fOrigPos[1], 0.5f) &&
|
||||
SkScalarNearlyEqual(shader.fOrigPos[2], 0.5f) &&
|
||||
SkScalarNearlyEqual(shader.fOrigPos[3], 1.0f)) {
|
||||
|
||||
return kHardStopCentered_ColorType;
|
||||
}
|
||||
} else if (3 == shader.fColorCount) {
|
||||
if (SkScalarNearlyEqual(shader.fOrigPos[0], 0.0f) &&
|
||||
SkScalarNearlyEqual(shader.fOrigPos[1], 0.0f) &&
|
||||
SkScalarNearlyEqual(shader.fOrigPos[2], 1.0f)) {
|
||||
|
||||
return kHardStopLeftEdged_ColorType;
|
||||
} else if (SkScalarNearlyEqual(shader.fOrigPos[0], 0.0f) &&
|
||||
SkScalarNearlyEqual(shader.fOrigPos[1], 1.0f) &&
|
||||
SkScalarNearlyEqual(shader.fOrigPos[2], 1.0f)) {
|
||||
|
||||
return kHardStopRightEdged_ColorType;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (SkShader::kClamp_TileMode == shader.getTileMode()) {
|
||||
if (2 == shader.fColorCount) {
|
||||
return kTwo_ColorType;
|
||||
} else if (3 == shader.fColorCount &&
|
||||
close_to_one_half(shader.getRecs()[1].fPos)) {
|
||||
return kThree_ColorType;
|
||||
}
|
||||
}
|
||||
|
||||
return kTexture_ColorType;
|
||||
}
|
||||
|
||||
void GrGradientEffect::GLSLProcessor::emitUniforms(GrGLSLUniformHandler* uniformHandler,
|
||||
const GrGradientEffect& ge) {
|
||||
|
||||
if (SkGradientShaderBase::kTwo_GpuColorType == ge.getColorType()) { // 2 Color case
|
||||
fColorStartUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
|
||||
kVec4f_GrSLType, kDefault_GrSLPrecision,
|
||||
"GradientStartColor");
|
||||
fColorEndUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
|
||||
kVec4f_GrSLType, kDefault_GrSLPrecision,
|
||||
"GradientEndColor");
|
||||
|
||||
} else if (SkGradientShaderBase::kThree_GpuColorType == ge.getColorType()) { // 3 Color Case
|
||||
fColorStartUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
|
||||
kVec4f_GrSLType, kDefault_GrSLPrecision,
|
||||
"GradientStartColor");
|
||||
fColorMidUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
|
||||
kVec4f_GrSLType, kDefault_GrSLPrecision,
|
||||
"GradientMidColor");
|
||||
fColorEndUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
|
||||
kVec4f_GrSLType, kDefault_GrSLPrecision,
|
||||
"GradientEndColor");
|
||||
|
||||
} else { // if not a fast case
|
||||
if (int colorCount = color_type_to_color_count(ge.getColorType())) {
|
||||
fColorsUni = uniformHandler->addUniformArray(kFragment_GrShaderFlag,
|
||||
kVec4f_GrSLType,
|
||||
kDefault_GrSLPrecision,
|
||||
"Colors",
|
||||
colorCount);
|
||||
} else {
|
||||
fFSYUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
|
||||
kFloat_GrSLType, kDefault_GrSLPrecision,
|
||||
"GradientYCoordFS");
|
||||
}
|
||||
}
|
||||
|
||||
static inline void set_color_uni(const GrGLSLProgramDataManager& pdman,
|
||||
const GrGLSLProgramDataManager::UniformHandle uni,
|
||||
const SkColor* color) {
|
||||
pdman.set4f(uni,
|
||||
SkColorGetR(*color) / 255.f,
|
||||
SkColorGetG(*color) / 255.f,
|
||||
SkColorGetB(*color) / 255.f,
|
||||
SkColorGetA(*color) / 255.f);
|
||||
static inline void set_after_interp_color_uni_array(const GrGLSLProgramDataManager& pdman,
|
||||
const GrGLSLProgramDataManager::UniformHandle uni,
|
||||
const SkTDArray<SkColor>& colors) {
|
||||
int count = colors.count();
|
||||
constexpr int kSmallCount = 10;
|
||||
|
||||
SkAutoSTArray<4*kSmallCount, float> vals(4*count);
|
||||
|
||||
for (int i = 0; i < colors.count(); i++) {
|
||||
// RGBA
|
||||
vals[4*i + 0] = SkColorGetR(colors[i]) / 255.f;
|
||||
vals[4*i + 1] = SkColorGetG(colors[i]) / 255.f;
|
||||
vals[4*i + 2] = SkColorGetB(colors[i]) / 255.f;
|
||||
vals[4*i + 3] = SkColorGetA(colors[i]) / 255.f;
|
||||
}
|
||||
|
||||
pdman.set4fv(uni, colors.count(), vals.get());
|
||||
}
|
||||
|
||||
static inline void set_mul_color_uni(const GrGLSLProgramDataManager& pdman,
|
||||
const GrGLSLProgramDataManager::UniformHandle uni,
|
||||
const SkColor* color){
|
||||
float a = SkColorGetA(*color) / 255.f;
|
||||
float aDiv255 = a / 255.f;
|
||||
pdman.set4f(uni,
|
||||
SkColorGetR(*color) * aDiv255,
|
||||
SkColorGetG(*color) * aDiv255,
|
||||
SkColorGetB(*color) * aDiv255,
|
||||
a);
|
||||
static inline void set_before_interp_color_uni_array(const GrGLSLProgramDataManager& pdman,
|
||||
const GrGLSLProgramDataManager::UniformHandle uni,
|
||||
const SkTDArray<SkColor>& colors) {
|
||||
int count = colors.count();
|
||||
constexpr int kSmallCount = 10;
|
||||
|
||||
SkAutoSTArray<4*kSmallCount, float> vals(4*count);
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
float a = SkColorGetA(colors[i]) / 255.f;
|
||||
float aDiv255 = a / 255.f;
|
||||
|
||||
// RGBA
|
||||
vals[4*i + 0] = SkColorGetR(colors[i]) * aDiv255;
|
||||
vals[4*i + 1] = SkColorGetG(colors[i]) * aDiv255;
|
||||
vals[4*i + 2] = SkColorGetB(colors[i]) * aDiv255;
|
||||
vals[4*i + 3] = a;
|
||||
}
|
||||
|
||||
pdman.set4fv(uni, count, vals.get());
|
||||
}
|
||||
|
||||
void GrGradientEffect::GLSLProcessor::onSetData(const GrGLSLProgramDataManager& pdman,
|
||||
const GrProcessor& processor) {
|
||||
|
||||
const GrGradientEffect& e = processor.cast<GrGradientEffect>();
|
||||
|
||||
switch (e.getColorType()) {
|
||||
#if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS
|
||||
case GrGradientEffect::kHardStopCentered_ColorType:
|
||||
case GrGradientEffect::kHardStopLeftEdged_ColorType:
|
||||
case GrGradientEffect::kHardStopRightEdged_ColorType:
|
||||
#endif
|
||||
case GrGradientEffect::kTwo_ColorType:
|
||||
case GrGradientEffect::kThree_ColorType: {
|
||||
if (GrGradientEffect::kBeforeInterp_PremulType == e.getPremulType()) {
|
||||
set_before_interp_color_uni_array(pdman, fColorsUni, e.fColors);
|
||||
} else {
|
||||
set_after_interp_color_uni_array(pdman, fColorsUni, e.fColors);
|
||||
}
|
||||
|
||||
if (SkGradientShaderBase::kTwo_GpuColorType == e.getColorType()){
|
||||
|
||||
if (GrGradientEffect::kBeforeInterp_PremulType == e.getPremulType()) {
|
||||
set_mul_color_uni(pdman, fColorStartUni, e.getColors(0));
|
||||
set_mul_color_uni(pdman, fColorEndUni, e.getColors(1));
|
||||
} else {
|
||||
set_color_uni(pdman, fColorStartUni, e.getColors(0));
|
||||
set_color_uni(pdman, fColorEndUni, e.getColors(1));
|
||||
break;
|
||||
}
|
||||
|
||||
} else if (SkGradientShaderBase::kThree_GpuColorType == e.getColorType()){
|
||||
|
||||
if (GrGradientEffect::kBeforeInterp_PremulType == e.getPremulType()) {
|
||||
set_mul_color_uni(pdman, fColorStartUni, e.getColors(0));
|
||||
set_mul_color_uni(pdman, fColorMidUni, e.getColors(1));
|
||||
set_mul_color_uni(pdman, fColorEndUni, e.getColors(2));
|
||||
} else {
|
||||
set_color_uni(pdman, fColorStartUni, e.getColors(0));
|
||||
set_color_uni(pdman, fColorMidUni, e.getColors(1));
|
||||
set_color_uni(pdman, fColorEndUni, e.getColors(2));
|
||||
}
|
||||
} else {
|
||||
|
||||
SkScalar yCoord = e.getYCoord();
|
||||
if (yCoord != fCachedYCoord) {
|
||||
pdman.set1f(fFSYUni, yCoord);
|
||||
fCachedYCoord = yCoord;
|
||||
case GrGradientEffect::kTexture_ColorType: {
|
||||
SkScalar yCoord = e.getYCoord();
|
||||
if (yCoord != fCachedYCoord) {
|
||||
pdman.set1f(fFSYUni, yCoord);
|
||||
fCachedYCoord = yCoord;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32_t GrGradientEffect::GLSLProcessor::GenBaseGradientKey(const GrProcessor& processor) {
|
||||
const GrGradientEffect& e = processor.cast<GrGradientEffect>();
|
||||
|
||||
uint32_t key = 0;
|
||||
|
||||
if (SkGradientShaderBase::kTwo_GpuColorType == e.getColorType()) {
|
||||
key |= kTwoColorKey;
|
||||
} else if (SkGradientShaderBase::kThree_GpuColorType == e.getColorType()) {
|
||||
key |= kThreeColorKey;
|
||||
}
|
||||
|
||||
if (GrGradientEffect::kBeforeInterp_PremulType == e.getPremulType()) {
|
||||
key |= kPremulBeforeInterpKey;
|
||||
}
|
||||
|
||||
if (GrGradientEffect::kTwo_ColorType == e.getColorType()) {
|
||||
key |= kTwoColorKey;
|
||||
} else if (GrGradientEffect::kThree_ColorType == e.getColorType()) {
|
||||
key |= kThreeColorKey;
|
||||
}
|
||||
#if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS
|
||||
else if (GrGradientEffect::kHardStopCentered_ColorType == e.getColorType()) {
|
||||
key |= kHardStopCenteredKey;
|
||||
} else if (GrGradientEffect::kHardStopLeftEdged_ColorType == e.getColorType()) {
|
||||
key |= kHardStopZeroZeroOneKey;
|
||||
} else if (GrGradientEffect::kHardStopRightEdged_ColorType == e.getColorType()) {
|
||||
key |= kHardStopZeroOneOneKey;
|
||||
}
|
||||
|
||||
if (SkShader::TileMode::kClamp_TileMode == e.fTileMode) {
|
||||
key |= kClampTileMode;
|
||||
} else if (SkShader::TileMode::kRepeat_TileMode == e.fTileMode) {
|
||||
key |= kRepeatTileMode;
|
||||
} else {
|
||||
key |= kMirrorTileMode;
|
||||
}
|
||||
#endif
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
@ -1030,56 +1090,183 @@ void GrGradientEffect::GLSLProcessor::emitColor(GrGLSLFPFragmentBuilder* fragBui
|
||||
const char* outputColor,
|
||||
const char* inputColor,
|
||||
const SamplerHandle* texSamplers) {
|
||||
if (SkGradientShaderBase::kTwo_GpuColorType == ge.getColorType()){
|
||||
fragBuilder->codeAppendf("\tvec4 colorTemp = mix(%s, %s, clamp(%s, 0.0, 1.0));\n",
|
||||
uniformHandler->getUniformVariable(fColorStartUni).c_str(),
|
||||
uniformHandler->getUniformVariable(fColorEndUni).c_str(),
|
||||
gradientTValue);
|
||||
// Note that we could skip this step if both colors are known to be opaque. Two
|
||||
// considerations:
|
||||
// The gradient SkShader reporting opaque is more restrictive than necessary in the two pt
|
||||
// case. Make sure the key reflects this optimization (and note that it can use the same
|
||||
// shader as thekBeforeIterp case). This same optimization applies to the 3 color case
|
||||
// below.
|
||||
if (GrGradientEffect::kAfterInterp_PremulType == ge.getPremulType()) {
|
||||
fragBuilder->codeAppend("\tcolorTemp.rgb *= colorTemp.a;\n");
|
||||
switch (ge.getColorType()) {
|
||||
#if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS
|
||||
case kHardStopCentered_ColorType: {
|
||||
const char* t = gradientTValue;
|
||||
const char* colors = uniformHandler->getUniformCStr(fColorsUni);
|
||||
|
||||
fragBuilder->codeAppendf("float clamp_t = clamp(%s, 0.0, 1.0);", t);
|
||||
|
||||
// Account for tile mode
|
||||
if (SkShader::kRepeat_TileMode == ge.fTileMode) {
|
||||
fragBuilder->codeAppendf("clamp_t = fract(%s);", t);
|
||||
} else if (SkShader::kMirror_TileMode == ge.fTileMode) {
|
||||
fragBuilder->codeAppendf("if (%s < 0.0 || %s > 1.0) {", t, t);
|
||||
fragBuilder->codeAppendf(" if (mod(floor(%s), 2.0) == 0.0) {", t);
|
||||
fragBuilder->codeAppendf(" clamp_t = fract(%s);", t);
|
||||
fragBuilder->codeAppendf(" } else {");
|
||||
fragBuilder->codeAppendf(" clamp_t = 1.0 - fract(%s);", t);
|
||||
fragBuilder->codeAppendf(" }");
|
||||
fragBuilder->codeAppendf("}");
|
||||
}
|
||||
|
||||
// Calculate color
|
||||
fragBuilder->codeAppendf("float relative_t = fract(2.0 * clamp_t);");
|
||||
if (SkShader::kClamp_TileMode == ge.fTileMode) {
|
||||
fragBuilder->codeAppendf("relative_t += step(1.0, %s);", t);
|
||||
}
|
||||
fragBuilder->codeAppendf("vec4 colorTemp = mix(%s[0], %s[1], relative_t);", colors,
|
||||
colors);
|
||||
fragBuilder->codeAppendf("if (clamp_t >= 0.5) {");
|
||||
fragBuilder->codeAppendf(" colorTemp = mix(%s[2], %s[3], relative_t);", colors,
|
||||
colors);
|
||||
fragBuilder->codeAppendf("}");
|
||||
|
||||
if (GrGradientEffect::kAfterInterp_PremulType == ge.getPremulType()) {
|
||||
fragBuilder->codeAppend("colorTemp.rgb *= colorTemp.a;");
|
||||
}
|
||||
fragBuilder->codeAppendf("%s = %s;", outputColor,
|
||||
(GrGLSLExpr4(inputColor) * GrGLSLExpr4("colorTemp")).c_str());
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
fragBuilder->codeAppendf("\t%s = %s;\n", outputColor,
|
||||
(GrGLSLExpr4(inputColor) * GrGLSLExpr4("colorTemp")).c_str());
|
||||
} else if (SkGradientShaderBase::kThree_GpuColorType == ge.getColorType()) {
|
||||
fragBuilder->codeAppendf("\tfloat oneMinus2t = 1.0 - (2.0 * (%s));\n",
|
||||
gradientTValue);
|
||||
fragBuilder->codeAppendf("\tvec4 colorTemp = clamp(oneMinus2t, 0.0, 1.0) * %s;\n",
|
||||
uniformHandler->getUniformVariable(fColorStartUni).c_str());
|
||||
if (!glslCaps->canUseMinAndAbsTogether()) {
|
||||
// The Tegra3 compiler will sometimes never return if we have
|
||||
// min(abs(oneMinus2t), 1.0), or do the abs first in a separate expression.
|
||||
fragBuilder->codeAppend("\tfloat minAbs = abs(oneMinus2t);\n");
|
||||
fragBuilder->codeAppend("\tminAbs = minAbs > 1.0 ? 1.0 : minAbs;\n");
|
||||
fragBuilder->codeAppendf("\tcolorTemp += (1.0 - minAbs) * %s;\n",
|
||||
uniformHandler->getUniformVariable(fColorMidUni).c_str());
|
||||
} else {
|
||||
fragBuilder->codeAppendf("\tcolorTemp += (1.0 - min(abs(oneMinus2t), 1.0)) * %s;\n",
|
||||
uniformHandler->getUniformVariable(fColorMidUni).c_str());
|
||||
}
|
||||
fragBuilder->codeAppendf("\tcolorTemp += clamp(-oneMinus2t, 0.0, 1.0) * %s;\n",
|
||||
uniformHandler->getUniformVariable(fColorEndUni).c_str());
|
||||
if (GrGradientEffect::kAfterInterp_PremulType == ge.getPremulType()) {
|
||||
fragBuilder->codeAppend("\tcolorTemp.rgb *= colorTemp.a;\n");
|
||||
case kHardStopLeftEdged_ColorType: {
|
||||
const char* t = gradientTValue;
|
||||
const char* colors = uniformHandler->getUniformCStr(fColorsUni);
|
||||
|
||||
fragBuilder->codeAppendf("float clamp_t = clamp(%s, 0.0, 1.0);", t);
|
||||
|
||||
// Account for tile mode
|
||||
if (SkShader::kRepeat_TileMode == ge.fTileMode) {
|
||||
fragBuilder->codeAppendf("clamp_t = fract(%s);", t);
|
||||
} else if (SkShader::kMirror_TileMode == ge.fTileMode) {
|
||||
fragBuilder->codeAppendf("if (%s < 0.0 || %s > 1.0) {", t, t);
|
||||
fragBuilder->codeAppendf(" if (mod(floor(%s), 2.0) == 0.0) {", t);
|
||||
fragBuilder->codeAppendf(" clamp_t = fract(%s);", t);
|
||||
fragBuilder->codeAppendf(" } else {");
|
||||
fragBuilder->codeAppendf(" clamp_t = 1.0 - fract(%s);", t);
|
||||
fragBuilder->codeAppendf(" }");
|
||||
fragBuilder->codeAppendf("}");
|
||||
}
|
||||
|
||||
fragBuilder->codeAppendf("vec4 colorTemp = mix(%s[1], %s[2], clamp_t);", colors,
|
||||
colors);
|
||||
if (SkShader::kClamp_TileMode == ge.fTileMode) {
|
||||
fragBuilder->codeAppendf("if (%s < 0.0) {", t);
|
||||
fragBuilder->codeAppendf(" colorTemp = %s[0];", colors);
|
||||
fragBuilder->codeAppendf("}");
|
||||
}
|
||||
|
||||
if (GrGradientEffect::kAfterInterp_PremulType == ge.getPremulType()) {
|
||||
fragBuilder->codeAppend("colorTemp.rgb *= colorTemp.a;");
|
||||
}
|
||||
fragBuilder->codeAppendf("%s = %s;", outputColor,
|
||||
(GrGLSLExpr4(inputColor) * GrGLSLExpr4("colorTemp")).c_str());
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
fragBuilder->codeAppendf("\t%s = %s;\n", outputColor,
|
||||
(GrGLSLExpr4(inputColor) * GrGLSLExpr4("colorTemp")).c_str());
|
||||
} else {
|
||||
fragBuilder->codeAppendf("\tvec2 coord = vec2(%s, %s);\n",
|
||||
gradientTValue,
|
||||
uniformHandler->getUniformVariable(fFSYUni).c_str());
|
||||
fragBuilder->codeAppendf("\t%s = ", outputColor);
|
||||
fragBuilder->appendTextureLookupAndModulate(inputColor,
|
||||
texSamplers[0],
|
||||
"coord");
|
||||
fragBuilder->codeAppend(";\n");
|
||||
case kHardStopRightEdged_ColorType: {
|
||||
const char* t = gradientTValue;
|
||||
const char* colors = uniformHandler->getUniformCStr(fColorsUni);
|
||||
|
||||
fragBuilder->codeAppendf("float clamp_t = clamp(%s, 0.0, 1.0);", t);
|
||||
|
||||
// Account for tile mode
|
||||
if (SkShader::kRepeat_TileMode == ge.fTileMode) {
|
||||
fragBuilder->codeAppendf("clamp_t = fract(%s);", t);
|
||||
} else if (SkShader::kMirror_TileMode == ge.fTileMode) {
|
||||
fragBuilder->codeAppendf("if (%s < 0.0 || %s > 1.0) {", t, t);
|
||||
fragBuilder->codeAppendf(" if (mod(floor(%s), 2.0) == 0.0) {", t);
|
||||
fragBuilder->codeAppendf(" clamp_t = fract(%s);", t);
|
||||
fragBuilder->codeAppendf(" } else {");
|
||||
fragBuilder->codeAppendf(" clamp_t = 1.0 - fract(%s);", t);
|
||||
fragBuilder->codeAppendf(" }");
|
||||
fragBuilder->codeAppendf("}");
|
||||
}
|
||||
|
||||
fragBuilder->codeAppendf("vec4 colorTemp = mix(%s[0], %s[1], clamp_t);", colors,
|
||||
colors);
|
||||
if (SkShader::kClamp_TileMode == ge.fTileMode) {
|
||||
fragBuilder->codeAppendf("if (%s > 1.0) {", t);
|
||||
fragBuilder->codeAppendf(" colorTemp = %s[2];", colors);
|
||||
fragBuilder->codeAppendf("}");
|
||||
}
|
||||
|
||||
if (GrGradientEffect::kAfterInterp_PremulType == ge.getPremulType()) {
|
||||
fragBuilder->codeAppend("colorTemp.rgb *= colorTemp.a;");
|
||||
}
|
||||
fragBuilder->codeAppendf("%s = %s;", outputColor,
|
||||
(GrGLSLExpr4(inputColor) * GrGLSLExpr4("colorTemp")).c_str());
|
||||
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
case kTwo_ColorType: {
|
||||
const char* t = gradientTValue;
|
||||
const char* colors = uniformHandler->getUniformCStr(fColorsUni);
|
||||
|
||||
fragBuilder->codeAppendf("vec4 colorTemp = mix(%s[0], %s[1], clamp(%s, 0.0, 1.0));",
|
||||
colors, colors, t);
|
||||
|
||||
// We could skip this step if both colors are known to be opaque. Two
|
||||
// considerations:
|
||||
// The gradient SkShader reporting opaque is more restrictive than necessary in the two
|
||||
// pt case. Make sure the key reflects this optimization (and note that it can use the
|
||||
// same shader as thekBeforeIterp case). This same optimization applies to the 3 color
|
||||
// case below.
|
||||
if (GrGradientEffect::kAfterInterp_PremulType == ge.getPremulType()) {
|
||||
fragBuilder->codeAppend("colorTemp.rgb *= colorTemp.a;");
|
||||
}
|
||||
|
||||
fragBuilder->codeAppendf("%s = %s;", outputColor,
|
||||
(GrGLSLExpr4(inputColor) * GrGLSLExpr4("colorTemp")).c_str());
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case kThree_ColorType: {
|
||||
const char* t = gradientTValue;
|
||||
const char* colors = uniformHandler->getUniformCStr(fColorsUni);
|
||||
|
||||
fragBuilder->codeAppendf("float oneMinus2t = 1.0 - (2.0 * %s);", t);
|
||||
fragBuilder->codeAppendf("vec4 colorTemp = clamp(oneMinus2t, 0.0, 1.0) * %s[0];",
|
||||
colors);
|
||||
if (!glslCaps->canUseMinAndAbsTogether()) {
|
||||
// The Tegra3 compiler will sometimes never return if we have
|
||||
// min(abs(oneMinus2t), 1.0), or do the abs first in a separate expression.
|
||||
fragBuilder->codeAppendf("float minAbs = abs(oneMinus2t);");
|
||||
fragBuilder->codeAppendf("minAbs = minAbs > 1.0 ? 1.0 : minAbs;");
|
||||
fragBuilder->codeAppendf("colorTemp += (1.0 - minAbs) * %s[1];", colors);
|
||||
} else {
|
||||
fragBuilder->codeAppendf("colorTemp += (1.0 - min(abs(oneMinus2t), 1.0)) * %s[1];",
|
||||
colors);
|
||||
}
|
||||
fragBuilder->codeAppendf("colorTemp += clamp(-oneMinus2t, 0.0, 1.0) * %s[2];", colors);
|
||||
|
||||
if (GrGradientEffect::kAfterInterp_PremulType == ge.getPremulType()) {
|
||||
fragBuilder->codeAppend("colorTemp.rgb *= colorTemp.a;");
|
||||
}
|
||||
|
||||
fragBuilder->codeAppendf("%s = %s;", outputColor,
|
||||
(GrGLSLExpr4(inputColor) * GrGLSLExpr4("colorTemp")).c_str());
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case kTexture_ColorType: {
|
||||
const char* fsyuni = uniformHandler->getUniformCStr(fFSYUni);
|
||||
|
||||
fragBuilder->codeAppendf("vec2 coord = vec2(%s, %s);", gradientTValue, fsyuni);
|
||||
fragBuilder->codeAppendf("%s = ", outputColor);
|
||||
fragBuilder->appendTextureLookupAndModulate(inputColor, texSamplers[0], "coord");
|
||||
fragBuilder->codeAppend(";");
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1092,56 +1279,87 @@ GrGradientEffect::GrGradientEffect(GrContext* ctx,
|
||||
|
||||
fIsOpaque = shader.isOpaque();
|
||||
|
||||
fColorType = shader.getGpuColorType(&fColors[0]);
|
||||
fColorType = this->determineColorType(shader);
|
||||
|
||||
// The two and three color specializations do not currently support tiling.
|
||||
if (SkGradientShaderBase::kTwo_GpuColorType == fColorType ||
|
||||
SkGradientShaderBase::kThree_GpuColorType == fColorType) {
|
||||
fRow = -1;
|
||||
|
||||
if (SkGradientShader::kInterpolateColorsInPremul_Flag & shader.getGradFlags()) {
|
||||
fPremulType = kBeforeInterp_PremulType;
|
||||
} else {
|
||||
fPremulType = kAfterInterp_PremulType;
|
||||
if (kTexture_ColorType != fColorType) {
|
||||
if (shader.fOrigColors) {
|
||||
fColors = SkTDArray<SkColor>(shader.fOrigColors, shader.fColorCount);
|
||||
}
|
||||
fCoordTransform.reset(kCoordSet, matrix);
|
||||
} else {
|
||||
// doesn't matter how this is set, just be consistent because it is part of the effect key.
|
||||
fPremulType = kBeforeInterp_PremulType;
|
||||
SkBitmap bitmap;
|
||||
shader.getGradientTableBitmap(&bitmap);
|
||||
|
||||
GrTextureStripAtlas::Desc desc;
|
||||
desc.fWidth = bitmap.width();
|
||||
desc.fHeight = 32;
|
||||
desc.fRowHeight = bitmap.height();
|
||||
desc.fContext = ctx;
|
||||
desc.fConfig = SkImageInfo2GrPixelConfig(bitmap.info(), *ctx->caps());
|
||||
fAtlas = GrTextureStripAtlas::GetAtlas(desc);
|
||||
SkASSERT(fAtlas);
|
||||
|
||||
// We always filter the gradient table. Each table is one row of a texture, always y-clamp.
|
||||
GrTextureParams params;
|
||||
params.setFilterMode(GrTextureParams::kBilerp_FilterMode);
|
||||
params.setTileModeX(tileMode);
|
||||
|
||||
fRow = fAtlas->lockRow(bitmap);
|
||||
if (-1 != fRow) {
|
||||
fYCoord = fAtlas->getYOffset(fRow) + SK_ScalarHalf * fAtlas->getNormalizedTexelHeight();
|
||||
fCoordTransform.reset(kCoordSet, matrix, fAtlas->getTexture(), params.filterMode());
|
||||
fTextureAccess.reset(fAtlas->getTexture(), params);
|
||||
} else {
|
||||
SkAutoTUnref<GrTexture> texture(
|
||||
GrRefCachedBitmapTexture(ctx, bitmap, params, SkSourceGammaTreatment::kRespect));
|
||||
if (!texture) {
|
||||
return;
|
||||
}
|
||||
fCoordTransform.reset(kCoordSet, matrix, texture, params.filterMode());
|
||||
fTextureAccess.reset(texture, params);
|
||||
fYCoord = SK_ScalarHalf;
|
||||
#if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS
|
||||
if (shader.fOrigPos) {
|
||||
fPositions = SkTDArray<SkScalar>(shader.fOrigPos, shader.fColorCount);
|
||||
}
|
||||
this->addTextureAccess(&fTextureAccess);
|
||||
|
||||
fTileMode = tileMode;
|
||||
#endif
|
||||
}
|
||||
|
||||
switch (fColorType) {
|
||||
// The two and three color specializations do not currently support tiling.
|
||||
case kTwo_ColorType:
|
||||
case kThree_ColorType:
|
||||
#if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS
|
||||
case kHardStopLeftEdged_ColorType:
|
||||
case kHardStopRightEdged_ColorType:
|
||||
case kHardStopCentered_ColorType:
|
||||
#endif
|
||||
fRow = -1;
|
||||
|
||||
if (SkGradientShader::kInterpolateColorsInPremul_Flag & shader.getGradFlags()) {
|
||||
fPremulType = kBeforeInterp_PremulType;
|
||||
} else {
|
||||
fPremulType = kAfterInterp_PremulType;
|
||||
}
|
||||
|
||||
fCoordTransform.reset(kCoordSet, matrix);
|
||||
|
||||
break;
|
||||
case kTexture_ColorType:
|
||||
// doesn't matter how this is set, just be consistent because it is part of the
|
||||
// effect key.
|
||||
fPremulType = kBeforeInterp_PremulType;
|
||||
|
||||
SkBitmap bitmap;
|
||||
shader.getGradientTableBitmap(&bitmap);
|
||||
|
||||
GrTextureStripAtlas::Desc desc;
|
||||
desc.fWidth = bitmap.width();
|
||||
desc.fHeight = 32;
|
||||
desc.fRowHeight = bitmap.height();
|
||||
desc.fContext = ctx;
|
||||
desc.fConfig = SkImageInfo2GrPixelConfig(bitmap.info(), *ctx->caps());
|
||||
fAtlas = GrTextureStripAtlas::GetAtlas(desc);
|
||||
SkASSERT(fAtlas);
|
||||
|
||||
// We always filter the gradient table. Each table is one row of a texture, always
|
||||
// y-clamp.
|
||||
GrTextureParams params;
|
||||
params.setFilterMode(GrTextureParams::kBilerp_FilterMode);
|
||||
params.setTileModeX(tileMode);
|
||||
|
||||
fRow = fAtlas->lockRow(bitmap);
|
||||
if (-1 != fRow) {
|
||||
fYCoord = fAtlas->getYOffset(fRow)+SK_ScalarHalf*fAtlas->getNormalizedTexelHeight();
|
||||
fCoordTransform.reset(kCoordSet, matrix, fAtlas->getTexture(), params.filterMode());
|
||||
fTextureAccess.reset(fAtlas->getTexture(), params);
|
||||
} else {
|
||||
SkAutoTUnref<GrTexture> texture(
|
||||
GrRefCachedBitmapTexture(ctx, bitmap, params,
|
||||
SkSourceGammaTreatment::kRespect));
|
||||
if (!texture) {
|
||||
return;
|
||||
}
|
||||
fCoordTransform.reset(kCoordSet, matrix, texture, params.filterMode());
|
||||
fTextureAccess.reset(texture, params);
|
||||
fYCoord = SK_ScalarHalf;
|
||||
}
|
||||
|
||||
this->addTextureAccess(&fTextureAccess);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
this->addCoordTransform(&fCoordTransform);
|
||||
}
|
||||
|
||||
@ -1152,30 +1370,27 @@ GrGradientEffect::~GrGradientEffect() {
|
||||
}
|
||||
|
||||
bool GrGradientEffect::onIsEqual(const GrFragmentProcessor& processor) const {
|
||||
const GrGradientEffect& s = processor.cast<GrGradientEffect>();
|
||||
const GrGradientEffect& ge = processor.cast<GrGradientEffect>();
|
||||
|
||||
if (this->fColorType == s.getColorType()){
|
||||
|
||||
if (SkGradientShaderBase::kTwo_GpuColorType == fColorType) {
|
||||
if (this->getPremulType() != s.getPremulType() ||
|
||||
*this->getColors(0) != *s.getColors(0) ||
|
||||
*this->getColors(1) != *s.getColors(1)) {
|
||||
return false;
|
||||
}
|
||||
} else if (SkGradientShaderBase::kThree_GpuColorType == fColorType) {
|
||||
if (this->getPremulType() != s.getPremulType() ||
|
||||
*this->getColors(0) != *s.getColors(0) ||
|
||||
*this->getColors(1) != *s.getColors(1) ||
|
||||
*this->getColors(2) != *s.getColors(2)) {
|
||||
if (this->fColorType == ge.getColorType()) {
|
||||
if (kTexture_ColorType == fColorType) {
|
||||
if (fYCoord != ge.getYCoord()) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (fYCoord != s.getYCoord()) {
|
||||
if (this->getPremulType() != ge.getPremulType() ||
|
||||
this->fColors.count() != ge.fColors.count()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < this->fColors.count(); i++) {
|
||||
if (*this->getColors(i) != *ge.getColors(i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SkASSERT(this->useAtlas() == s.useAtlas());
|
||||
SkASSERT(this->useAtlas() == ge.useAtlas());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,10 @@
|
||||
#include "SkShader.h"
|
||||
#include "SkOnce.h"
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
#define GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS 1
|
||||
#endif
|
||||
|
||||
static inline void sk_memset32_dither(uint32_t dst[], uint32_t v0, uint32_t v1,
|
||||
int count) {
|
||||
if (count > 0) {
|
||||
@ -128,7 +132,8 @@ public:
|
||||
bool getDither() const { return fCacheDither; }
|
||||
|
||||
private:
|
||||
// Working pointers. If either is nullptr, we need to recompute the corresponding cache values.
|
||||
// Working pointers. If either is nullptr, we need to recompute the corresponding
|
||||
// cache values.
|
||||
uint16_t* fCache16;
|
||||
SkPMColor* fCache32;
|
||||
|
||||
@ -197,17 +202,6 @@ public:
|
||||
kDitherStride16 = kCache16Count,
|
||||
};
|
||||
|
||||
enum GpuColorType {
|
||||
kTwo_GpuColorType,
|
||||
kThree_GpuColorType, // Symmetric three color
|
||||
kTexture_GpuColorType
|
||||
};
|
||||
|
||||
// Determines and returns the gradient is a two color gradient, symmetric three color gradient
|
||||
// or other (texture gradient). If it is two or symmetric three color, the colors array will
|
||||
// also be filled with the gradient colors
|
||||
GpuColorType getGpuColorType(SkColor colors[3]) const;
|
||||
|
||||
uint32_t getGradFlags() const { return fGradFlags; }
|
||||
|
||||
protected:
|
||||
@ -220,7 +214,6 @@ protected:
|
||||
const SkMatrix fPtsToUnit;
|
||||
TileMode fTileMode;
|
||||
TileProc fTileProc;
|
||||
int fColorCount;
|
||||
uint8_t fGradFlags;
|
||||
|
||||
struct Rec {
|
||||
@ -254,9 +247,15 @@ private:
|
||||
public:
|
||||
SkColor* fOrigColors; // original colors, before modulation by paint in context.
|
||||
SkScalar* fOrigPos; // original positions
|
||||
int fColorCount;
|
||||
|
||||
SkTArray<sk_sp<SkShader>> fSubGradients;
|
||||
|
||||
bool colorsAreOpaque() const { return fColorsAreOpaque; }
|
||||
|
||||
TileMode getTileMode() const { return fTileMode; }
|
||||
Rec* getRecs() const { return fRecs; }
|
||||
|
||||
private:
|
||||
bool fColorsAreOpaque;
|
||||
|
||||
@ -336,9 +335,30 @@ public:
|
||||
virtual ~GrGradientEffect();
|
||||
|
||||
bool useAtlas() const { return SkToBool(-1 != fRow); }
|
||||
SkScalar getYCoord() const { return fYCoord; };
|
||||
SkScalar getYCoord() const { return fYCoord; }
|
||||
|
||||
SkGradientShaderBase::GpuColorType getColorType() const { return fColorType; }
|
||||
enum ColorType {
|
||||
kTwo_ColorType,
|
||||
kThree_ColorType, // Symmetric three color
|
||||
kTexture_ColorType,
|
||||
|
||||
#if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS
|
||||
kHardStopCentered_ColorType, // 0, 0.5, 0.5, 1
|
||||
kHardStopLeftEdged_ColorType, // 0, 0, 1
|
||||
kHardStopRightEdged_ColorType, // 0, 1, 1
|
||||
#endif
|
||||
};
|
||||
|
||||
ColorType getColorType() const { return fColorType; }
|
||||
|
||||
// Determines the type of gradient, one of:
|
||||
// - Two-color
|
||||
// - Symmetric three-color
|
||||
// - Texture
|
||||
// - Centered hard stop
|
||||
// - Left-edged hard stop
|
||||
// - Right-edged hard stop
|
||||
ColorType determineColorType(const SkGradientShaderBase& shader);
|
||||
|
||||
enum PremulType {
|
||||
kBeforeInterp_PremulType,
|
||||
@ -348,8 +368,8 @@ public:
|
||||
PremulType getPremulType() const { return fPremulType; }
|
||||
|
||||
const SkColor* getColors(int pos) const {
|
||||
SkASSERT(fColorType != SkGradientShaderBase::kTexture_GpuColorType);
|
||||
SkASSERT((pos-1) <= fColorType);
|
||||
SkASSERT(fColorType != kTexture_ColorType);
|
||||
SkASSERT(pos < fColors.count());
|
||||
return &fColors[pos];
|
||||
}
|
||||
|
||||
@ -358,8 +378,8 @@ protected:
|
||||
The function decides whether stop values should be used or not. The return value indicates
|
||||
the number of colors, which will be capped by kMaxRandomGradientColors. colors should be
|
||||
sized to be at least kMaxRandomGradientColors. stops is a pointer to an array of at least
|
||||
size kMaxRandomGradientColors. It may be updated to nullptr, indicating that nullptr should be
|
||||
passed to the gradient factory rather than the array.
|
||||
size kMaxRandomGradientColors. It may be updated to nullptr, indicating that nullptr should
|
||||
be passed to the gradient factory rather than the array.
|
||||
*/
|
||||
static const int kMaxRandomGradientColors = 4;
|
||||
static int RandomGradientParams(SkRandom* r,
|
||||
@ -376,26 +396,31 @@ protected:
|
||||
private:
|
||||
static const GrCoordSet kCoordSet = kLocal_GrCoordSet;
|
||||
|
||||
SkTDArray<SkColor> fColors;
|
||||
SkTDArray<SkScalar> fPositions;
|
||||
SkShader::TileMode fTileMode;
|
||||
|
||||
GrCoordTransform fCoordTransform;
|
||||
GrTextureAccess fTextureAccess;
|
||||
SkScalar fYCoord;
|
||||
GrTextureStripAtlas* fAtlas;
|
||||
int fRow;
|
||||
bool fIsOpaque;
|
||||
SkGradientShaderBase::GpuColorType fColorType;
|
||||
SkColor fColors[3]; // More than 3 colors we use texture
|
||||
PremulType fPremulType; // This only changes behavior for two and three color special cases.
|
||||
// It is already baked into to the table for texture gradients.
|
||||
ColorType fColorType;
|
||||
PremulType fPremulType; // This is already baked into the table for texture gradients, and
|
||||
// only changes behavior for gradients that don't use a texture.
|
||||
typedef GrFragmentProcessor INHERITED;
|
||||
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Base class for GLSL gradient effects
|
||||
// Base class for GL gradient effects
|
||||
class GrGradientEffect::GLSLProcessor : public GrGLSLFragmentProcessor {
|
||||
public:
|
||||
GLSLProcessor();
|
||||
GLSLProcessor() {
|
||||
fCachedYCoord = SK_ScalarMax;
|
||||
}
|
||||
|
||||
protected:
|
||||
void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
|
||||
@ -412,10 +437,10 @@ protected:
|
||||
// should call this method from their emitCode().
|
||||
void emitUniforms(GrGLSLUniformHandler*, const GrGradientEffect&);
|
||||
|
||||
|
||||
// emit code that gets a fragment's color from an expression for t; Has branches for 3 separate
|
||||
// control flows inside -- 2 color gradients, 3 color symmetric gradients (both using
|
||||
// native GLSL mix), and 4+ color gradients that use the traditional texture lookup.
|
||||
// Emit code that gets a fragment's color from an expression for t; has branches for
|
||||
// several control flows inside -- 2-color gradients, 3-color symmetric gradients, 4+
|
||||
// color gradients that use the traditional texture lookup, as well as several varieties
|
||||
// of hard stop gradients
|
||||
void emitColor(GrGLSLFPFragmentBuilder* fragBuilder,
|
||||
GrGLSLUniformHandler* uniformHandler,
|
||||
const GrGLSLCaps* caps,
|
||||
@ -428,18 +453,30 @@ protected:
|
||||
private:
|
||||
enum {
|
||||
// First bit for premul before/after interp
|
||||
kPremulBeforeInterpKey = 1,
|
||||
kPremulBeforeInterpKey = 1,
|
||||
|
||||
// Next two bits for 2/3 color type (neither means using texture atlas)
|
||||
kTwoColorKey = 4,
|
||||
kThreeColorKey = 6,
|
||||
// Next three bits for 2/3 color type or different special
|
||||
// hard stop cases (neither means using texture atlas)
|
||||
kTwoColorKey = 2,
|
||||
kThreeColorKey = 4,
|
||||
#if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS
|
||||
kHardStopCenteredKey = 6,
|
||||
kHardStopZeroZeroOneKey = 8,
|
||||
kHardStopZeroOneOneKey = 10,
|
||||
|
||||
// Next two bits for tile mode
|
||||
kClampTileMode = 16,
|
||||
kRepeatTileMode = 32,
|
||||
kMirrorTileMode = 48,
|
||||
|
||||
// Lower six bits for premul, 2/3 color type, and tile mode
|
||||
kReservedBits = 6,
|
||||
#endif
|
||||
};
|
||||
|
||||
SkScalar fCachedYCoord;
|
||||
GrGLSLProgramDataManager::UniformHandle fColorsUni;
|
||||
GrGLSLProgramDataManager::UniformHandle fFSYUni;
|
||||
GrGLSLProgramDataManager::UniformHandle fColorStartUni;
|
||||
GrGLSLProgramDataManager::UniformHandle fColorMidUni;
|
||||
GrGLSLProgramDataManager::UniformHandle fColorEndUni;
|
||||
|
||||
typedef GrGLSLFragmentProcessor INHERITED;
|
||||
};
|
||||
|
@ -218,10 +218,10 @@ void GrSweepGradient::GLSLSweepProcessor::emitCode(EmitArgs& args) {
|
||||
// On Intel GPU there is an issue where it reads the second arguement to atan "- %s.x" as an int
|
||||
// thus must us -1.0 * %s.x to work correctly
|
||||
if (args.fGLSLCaps->mustForceNegatedAtanParamToFloat()){
|
||||
t.printf("atan(- %s.y, -1.0 * %s.x) * 0.1591549430918 + 0.5",
|
||||
t.printf("(atan(- %s.y, -1.0 * %s.x) * 0.1591549430918 + 0.5)",
|
||||
coords2D.c_str(), coords2D.c_str());
|
||||
} else {
|
||||
t.printf("atan(- %s.y, - %s.x) * 0.1591549430918 + 0.5",
|
||||
t.printf("(atan(- %s.y, - %s.x) * 0.1591549430918 + 0.5)",
|
||||
coords2D.c_str(), coords2D.c_str());
|
||||
}
|
||||
this->emitColor(args.fFragBuilder,
|
||||
|
Loading…
Reference in New Issue
Block a user