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 
73     override
74     string typeId() { return "Mask"; }
75 
76 public:
77     /**
78         Constructs a new mask
79     */
80     this(Node parent = null) {
81         MeshData empty;
82         this(empty, inCreateUUID(), parent);
83     }
84 
85     /**
86         Constructs a new mask
87     */
88     this(MeshData data, Node parent = null) {
89         this(data, inCreateUUID(), parent);
90     }
91 
92     /**
93         Constructs a new mask
94     */
95     this(MeshData data, uint uuid, Node parent = null) {
96         super(data, uuid, parent);
97     }
98     
99     override
100     void renderMask(bool dodge = false) {
101         
102         // Enable writing to stencil buffer and disable writing to color buffer
103         glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
104         glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
105         glStencilFunc(GL_ALWAYS, dodge ? 0 : 1, 0xFF);
106         glStencilMask(0xFF);
107 
108         // Draw ourselves to the stencil buffer
109         drawSelf();
110 
111         // Disable writing to stencil buffer and enable writing to color buffer
112         glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
113     }
114 
115     override
116     void rebuffer(ref MeshData data) {
117         super.rebuffer(data);
118     }
119 
120     override
121     void drawOne() {
122         super.drawOne();
123     }
124 
125     override
126     void drawOneDirect(bool forMasking) {
127         this.drawSelf();
128     }
129 
130     override
131     void draw() {
132         if (!enabled) return;
133         foreach(child; children) {
134             child.draw();
135         }
136     }
137 
138 }