1 /*
2     Inochi2D Mask
3 
4     Copyright © 2020, Inochi2D Project
5     Distributed under the 2-Clause BSD License, see LICENSE file.
6     
7     Authors: Luna Nielsen
8 */
9 module inochi2d.core.nodes.mask;
10 import inochi2d.core.nodes.drawable;
11 import inochi2d.core;
12 import inochi2d.math;
13 import bindbc.opengl;
14 import std.exception;
15 import std.algorithm.mutation : copy;
16 
17 public import inochi2d.core.meshdata;
18 
19 
20 package(inochi2d) {
21     private {
22         Shader maskShader;
23     }
24 
25     /* GLSL Uniforms (Normal) */
26     GLint mvp;
27     GLint offset;
28 
29     void inInitMask() {
30         inRegisterNodeType!Mask;
31         version(InDoesRender) {
32             maskShader = new Shader(import("mask.vert"), import("mask.frag"));
33             offset = maskShader.getUniformLocation("offset");
34             mvp = maskShader.getUniformLocation("mvp");
35         }
36     }
37 }
38 
39 /**
40     Dynamic Mask Part
41 */
42 @TypeId("Mask")
43 class Mask : Drawable {
44 private:
45     this() { }
46 
47     /*
48         RENDERING
49     */
50     void drawSelf() {
51 
52         // Bind the vertex array
53         incDrawableBindVAO();
54 
55         maskShader.use();
56         maskShader.setUniform(offset, data.origin);
57         maskShader.setUniform(mvp, inGetCamera().matrix * transform.matrix());
58         
59         // Enable points array
60         glEnableVertexAttribArray(0);
61         glBindBuffer(GL_ARRAY_BUFFER, vbo);
62         glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, null);
63 
64         // Bind index buffer
65         this.bindIndex();
66 
67         // Disable the vertex attribs after use
68         glDisableVertexAttribArray(0);
69     }
70 
71 protected:
72     override
73     void renderMask(bool dodge = false) {
74         
75         // Enable writing to stencil buffer and disable writing to color buffer
76         glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
77         glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
78         glStencilFunc(GL_ALWAYS, dodge ? 0 : 1, 0xFF);
79         glStencilMask(0xFF);
80 
81         // Draw ourselves to the stencil buffer
82         drawSelf();
83 
84         // Disable writing to stencil buffer and enable writing to color buffer
85         glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
86     }
87 
88     override
89     string typeId() { return "Mask"; }
90 
91 public:
92     /**
93         Constructs a new mask
94     */
95     this(Node parent = null) {
96         MeshData empty;
97         this(empty, inCreateUUID(), parent);
98     }
99 
100     /**
101         Constructs a new mask
102     */
103     this(MeshData data, Node parent = null) {
104         this(data, inCreateUUID(), parent);
105     }
106 
107     /**
108         Constructs a new mask
109     */
110     this(MeshData data, uint uuid, Node parent = null) {
111         super(data, uuid, parent);
112     }
113 
114     override
115     void rebuffer(ref MeshData data) {
116         super.rebuffer(data);
117     }
118 
119     override
120     void drawOne() {
121         super.drawOne();
122     }
123 
124     override
125     void drawOneDirect(bool forMasking) {
126         this.drawSelf();
127     }
128 
129     override
130     void draw() {
131         if (!enabled) return;
132         foreach(child; children) {
133             child.draw();
134         }
135     }
136 
137 }