diff --git a/CHANGELOG.md b/CHANGELOG.md index 2697bd83..12fcb488 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ +# 0.92.14 - Aug 7, 2021 + +Added: + +- RuntimeEffect #120 #124 thx @Vechro + +# 0.92.13 - July 29, 2021 + +Added: + +- DirectContext::submit(bool syncCPU), thx @EgorOrachyov + # 0.92.11 - July 27, 2021 Added: diff --git a/README.md b/README.md index 90c9e538..f9da09ae 100644 --- a/README.md +++ b/README.md @@ -110,17 +110,17 @@ ColorSpace ▓▓▓▓░░░░░░ PictureRecorder ▓ Data ▓▓▓▓▓▓▓▓▓░ PixelRef ▓▓▓▓▓▓▓▓▓▓ Drawable ▓▓▓▓▓▓▓▓░░ Pixmap ▓▓▓▓▓▓▓▓▓▓ Flattenable ░░░░░░░░░░ Region ▓▓▓▓▓▓▓▓▓▓ -Font ▓▓▓▓▓▓▓▓▓▓ ScalerContext ░░░░░░░░░░ -FontData ░░░░░░░░░░ Shader ▓▓▓▓▓▓▓▓▓▓ -FontManager ▓▓▓▓▓▓▓▓▓░ ShadowUtils ▓▓▓▓▓▓▓▓▓▓ -FontStyle ▓▓▓▓▓▓▓▓▓▓ Stream ░░░░░░░░░░ -FontStyleSet ▓▓▓▓▓▓▓▓▓▓ String ▓░░░░░░░░░ -Image ▓▓░░░░░░░░ Surface ▓░░░░░░░░░ -ImageFilters ▓▓▓▓▓▓▓▓▓▓ TextBlob ▓▓▓▓▓▓▓▓▓▓ -ImageInfo ▓▓▓▓▓▓▓▓▓▓ TextBlobBuilder ▓▓▓▓▓▓▓▓▓▓ -MaskFilter ▓▓▓▓▓▓▓▓▓▓ Typeface ▓▓▓▓▓▓▓▓░░ -Matrix33 ▓▓▓░░░░░░░ WStream ▓▓░░░░░░░░ -Matrix44 ▓▓▓░░░░░░░ +Font ▓▓▓▓▓▓▓▓▓▓ RuntimeEffect ▓▓▓▓▓░░░░░ +FontData ░░░░░░░░░░ ScalerContext ░░░░░░░░░░ +FontManager ▓▓▓▓▓▓▓▓▓░ Shader ▓▓▓▓▓▓▓▓▓▓ +FontStyle ▓▓▓▓▓▓▓▓▓▓ ShadowUtils ▓▓▓▓▓▓▓▓▓▓ +FontStyleSet ▓▓▓▓▓▓▓▓▓▓ Stream ░░░░░░░░░░ +Image ▓▓░░░░░░░░ String ▓░░░░░░░░░ +ImageFilters ▓▓▓▓▓▓▓▓▓▓ Surface ▓░░░░░░░░░ +ImageInfo ▓▓▓▓▓▓▓▓▓▓ TextBlob ▓▓▓▓▓▓▓▓▓▓ +MaskFilter ▓▓▓▓▓▓▓▓▓▓ TextBlobBuilder ▓▓▓▓▓▓▓▓▓▓ +Matrix33 ▓▓▓░░░░░░░ Typeface ▓▓▓▓▓▓▓▓░░ +Matrix44 ▓▓▓░░░░░░░ WStream ▓▓░░░░░░░░ Shaper: Paragraph: diff --git a/examples/scenes/images/triangle.png b/examples/scenes/images/triangle.png new file mode 100644 index 00000000..e94ad6ab Binary files /dev/null and b/examples/scenes/images/triangle.png differ diff --git a/examples/scenes/src/RuntimeEffectScene.java b/examples/scenes/src/RuntimeEffectScene.java new file mode 100644 index 00000000..62cd78f8 --- /dev/null +++ b/examples/scenes/src/RuntimeEffectScene.java @@ -0,0 +1,48 @@ +package org.jetbrains.skija.examples.scenes; + +import java.nio.*; +import java.nio.file.*; +import java.nio.file.Path; +import java.io.*; +import org.jetbrains.skija.*; + +public class RuntimeEffectScene extends Scene { + public final Shader _texture; + public final RuntimeEffect _effect; + + public RuntimeEffectScene() { + try { + _texture = Image.makeFromEncoded(Files.readAllBytes(Path.of(file("images/triangle.png")))).makeShader(); + } catch (IOException e) { + throw new RuntimeException(e); + } + + _effect = RuntimeEffect.makeForShader( + "uniform float xScale;\n" + + "uniform float xBias;\n" + + "uniform float yScale;\n" + + "uniform float yBias;\n" + + "uniform shader input;\n" + + "half4 main(float2 xy) {\n" + + " half4 tex = sample(input, mod(xy, 100));\n" + + " return half4((xy.x - xBias) / xScale / 2 + 0.5, (xy.y - yBias) / yScale / 2 + 0.5, tex.b, 1);\n" + + "}" + ); + } + + @Override + public void draw(Canvas canvas, int width, int height, float dpi, int xpos, int ypos) { + var bb = ByteBuffer.allocate(4 * 4).order(ByteOrder.nativeOrder()); + bb.putFloat((float) width); + bb.putFloat((float) xpos); + bb.putFloat((float) height); + bb.putFloat((float) ypos); + try (var data = Data.makeFromBytes(bb.array()); + var paint = new Paint(); + var shader = _effect.makeShader(data, new Shader[] { _texture }, null, true);) + { + paint.setShader(shader); + canvas.drawPaint(paint); + } + } +} diff --git a/examples/scenes/src/Scenes.java b/examples/scenes/src/Scenes.java index 40abf5f2..32ee174c 100644 --- a/examples/scenes/src/Scenes.java +++ b/examples/scenes/src/Scenes.java @@ -6,7 +6,7 @@ public class Scenes { public static TreeMap scenes; - public static String currentScene = "Bitmap"; + public static String currentScene = "Runtime Effect"; public static HUD hud = new HUD(); public static boolean stats = true; @@ -43,6 +43,7 @@ public class Scenes { scenes.put("Pythagoras", null); scenes.put("Run Handler", null); scenes.put("Run Iterator", null); + scenes.put("Runtime Effect", null); scenes.put("SVG", null); scenes.put("SVG Scaling", null); scenes.put("Shaders", null); diff --git a/platform/cc/RuntimeEffect.cc b/platform/cc/RuntimeEffect.cc new file mode 100644 index 00000000..85d6e340 --- /dev/null +++ b/platform/cc/RuntimeEffect.cc @@ -0,0 +1,60 @@ +#include + +#include "SkRuntimeEffect.h" +#include "interop.hh" + +extern "C" JNIEXPORT jlong JNICALL +Java_org_jetbrains_skija_RuntimeEffect__1nMakeShader(JNIEnv* env, + jclass jclass, + jlong ptr, + jlong uniformPtr, + jlongArray childrenPtrsArr, + jfloatArray localMatrixArr, + jboolean isOpaque) { + SkRuntimeEffect* runtimeEffect = jlongToPtr(ptr); + SkData* uniform = jlongToPtr(uniformPtr); + std::unique_ptr localMatrix = skMatrix(env, localMatrixArr); + + jsize childCount = env->GetArrayLength(childrenPtrsArr); + jlong* childrenPtrs = env->GetLongArrayElements(childrenPtrsArr, 0); + std::vector> children(childCount); + for (size_t i = 0; i < childCount; i++) { + SkShader* si = jlongToPtr(childrenPtrs[i]); + children[i] = sk_ref_sp(si); + } + env->ReleaseLongArrayElements(childrenPtrsArr, childrenPtrs, 0); + + sk_sp shader = runtimeEffect->makeShader(sk_ref_sp(uniform), + children.data(), + childCount, + localMatrix.get(), + isOpaque); + return ptrToJlong(shader.release()); +} + +extern "C" JNIEXPORT jlong JNICALL +Java_org_jetbrains_skija_RuntimeEffect__1nMakeForShader(JNIEnv* env, jclass jclass, jstring sksl) { + SkString skslProper = skString(env, sksl); + SkRuntimeEffect::Result result = SkRuntimeEffect::MakeForShader(skslProper); + if (result.errorText.isEmpty()) { + sk_sp effect = result.effect; + return ptrToJlong(effect.release()); + } else { + env->ThrowNew(java::lang::RuntimeException::cls, result.errorText.c_str()); + return 0; + } +} + +extern "C" JNIEXPORT jlong JNICALL +Java_org_jetbrains_skija_RuntimeEffect__1nMakeForColorFilter(JNIEnv* env, + jclass jclass, + jstring sksl) { + SkString skslProper = skString(env, sksl); + SkRuntimeEffect::Result result = SkRuntimeEffect::MakeForColorFilter(skslProper); + if (result.errorText.isEmpty()) { + return ptrToJlong(result.effect.release()); + } else { + env->ThrowNew(java::lang::RuntimeException::cls, result.errorText.c_str()); + return 0; + } +} \ No newline at end of file diff --git a/shared/java/RuntimeEffect.java b/shared/java/RuntimeEffect.java new file mode 100644 index 00000000..fb29a101 --- /dev/null +++ b/shared/java/RuntimeEffect.java @@ -0,0 +1,45 @@ +package org.jetbrains.skija; + +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.skija.impl.*; + +public class RuntimeEffect extends RefCnt { + static { + Library.staticLoad(); + } + + public Shader makeShader(@Nullable Data uniforms, @Nullable Shader[] children, @Nullable Matrix33 localMatrix, + boolean isOpaque) { + Stats.onNativeCall(); + int childCount = children == null ? 0 : children.length; + long[] childrenPtrs = new long[childCount]; + for (int i = 0; i < childCount; i++) { + childrenPtrs[i] = Native.getPtr(children[i]); + } + float[] matrix = localMatrix == null ? null : localMatrix._mat; + return new Shader(_nMakeShader(_ptr, Native.getPtr(uniforms), childrenPtrs, matrix, isOpaque)); + } + + public static RuntimeEffect makeForShader(String sksl) { + Stats.onNativeCall(); + return new RuntimeEffect(_nMakeForShader(sksl)); + } + + public static RuntimeEffect makeForColorFilter(String sksl) { + Stats.onNativeCall(); + return new RuntimeEffect(_nMakeForColorFilter(sksl)); + } + + @ApiStatus.Internal + public RuntimeEffect(long ptr) { + super(ptr); + } + + public static native long _nMakeShader(long runtimeEffectPtr, long uniformPtr, long[] childrenPtrs, + float[] localMatrix, boolean isOpaque); + + public static native long _nMakeForShader(String sksl); + + public static native long _nMakeForColorFilter(String sksl); +} \ No newline at end of file