Edit Mesh: Simplify the overlay shader.
[blender.git] / source / blender / draw / modes / shaders / edit_mesh_overlay_geom_tri.glsl
1
2 /* Solid Wirefram implementation
3  * Mike Erwin, ClĂ©ment Foucault */
4
5 /* This shader follows the principles of
6  * http://developer.download.nvidia.com/SDK/10/direct3d/Source/SolidWireframe/Doc/SolidWireframe.pdf */
7
8 layout(triangles) in;
9
10 /* This is not perfect. Only a subset of intel gpus are affected.
11  * This fix have some performance impact.
12  * TODO Refine the range to only affect GPUs. */
13
14 #ifdef EDGE_FIX
15 /* To fix the edge artifacts, we render
16  * an outline strip around the screenspace
17  * triangle. Order is important.
18  * TODO diagram
19  */
20
21 #ifdef VERTEX_SELECTION
22 layout(triangle_strip, max_vertices=23) out;
23 #else
24 layout(triangle_strip, max_vertices=17) out;
25 #endif
26 #else
27 layout(triangle_strip, max_vertices=3) out;
28 #endif
29
30 uniform mat4 ProjectionMatrix;
31 uniform vec2 viewportSize;
32
33 in vec4 vPos[];
34 in vec4 pPos[];
35 in ivec4 vData[];
36 #ifdef VERTEX_FACING
37 in float vFacing[];
38 #endif
39
40 /* these are the same for all vertices
41  * and does not need interpolation */
42 flat out vec3 edgesCrease;
43 flat out vec3 edgesBweight;
44 flat out vec4 faceColor;
45 flat out ivec3 flag;
46 flat out int clipCase;
47 #ifdef VERTEX_SELECTION
48 out vec3 vertexColor;
49 #endif
50 #ifdef VERTEX_FACING
51 out float facing;
52 #endif
53
54 /* See fragment shader */
55 flat out vec2 ssPos[3];
56
57 #define FACE_ACTIVE     (1 << 2)
58 #define FACE_SELECTED   (1 << 3)
59
60 /* project to screen space */
61 vec2 proj(vec4 pos)
62 {
63         return (0.5 * (pos.xy / pos.w) + 0.5) * viewportSize;
64 }
65
66 void doVertex(int v)
67 {
68 #ifdef VERTEX_SELECTION
69         vertexColor = EDIT_MESH_vertex_color(vData[v].x).rgb;
70 #endif
71
72 #ifdef VERTEX_FACING
73         facing = vFacing[v];
74 #endif
75
76         gl_Position = pPos[v];
77
78         EmitVertex();
79 }
80
81 void doLoopStrip(int v, vec3 offset)
82 {
83         doVertex(v);
84
85         gl_Position.xyz += offset;
86
87         EmitVertex();
88 }
89
90 #ifdef ANTI_ALIASING
91 #define Z_OFFSET 0.008
92 #else
93 #define Z_OFFSET 0.0
94 #endif
95
96 void main()
97 {
98         /* Edge */
99         ivec3 eflag; vec3 ecrease, ebweight;
100         for (int v = 0; v < 3; ++v) {
101                 flag[v] = eflag[v] = vData[v].y | (vData[v].x << 8);
102                 edgesCrease[v] = ecrease[v] = vData[v].z / 255.0;
103                 edgesBweight[v] = ebweight[v] = vData[v].w / 255.0;
104         }
105
106         /* Face */
107         if ((vData[0].x & FACE_ACTIVE) != 0)
108                 faceColor = colorFaceSelect;
109         else if ((vData[0].x & FACE_SELECTED) != 0)
110                 faceColor = colorFaceSelect;
111         else
112                 faceColor = colorFace;
113
114         /* Vertex */
115         vec2 pos[3];
116         ssPos[0] = pos[0] = proj(pPos[0]);
117         ssPos[1] = pos[1] = proj(pPos[1]);
118         ssPos[2] = pos[2] = proj(pPos[2]);
119
120         doVertex(0);
121         doVertex(1);
122         doVertex(2);
123
124 #ifdef EDGE_FIX
125         vec2 fixvec[6];
126         vec2 fixvecaf[6];
127         vec2 cornervec[3];
128
129         /* This fix the case when 2 vertices are perfectly aligned
130          * and corner vectors have nowhere to go.
131          * ie: length(cornervec[i]) == 0 */
132         const float epsilon = 1e-2; /* in pixel so not that much */
133         const vec2 bias[3] = vec2[3](
134                 vec2( epsilon,  epsilon),
135                 vec2(-epsilon,  epsilon),
136                 vec2(     0.0, -epsilon)
137         );
138
139         for (int i = 0; i < 3; ++i) {
140                 int i1 = (i + 1) % 3;
141                 int i2 = (i + 2) % 3;
142
143                 vec2 v1 = ssPos[i] + bias[i];
144                 vec2 v2 = ssPos[i1] + bias[i1];
145                 vec2 v3 = ssPos[i2] + bias[i2];
146
147                 /* Edge normalized vector */
148                 vec2 dir = normalize(v2 - v1);
149                 vec2 dir2 = normalize(v3 - v1);
150
151                 cornervec[i] = -normalize(dir + dir2);
152
153                 /* perpendicular to dir */
154                 vec2 perp = vec2(-dir.y, dir.x);
155
156                 /* Backface case */
157                 if (dot(perp, dir2) > 0) {
158                         perp = -perp;
159                 }
160
161                 /* Make it view independent */
162                 perp *= sizeEdgeFix / viewportSize;
163                 cornervec[i] *= sizeEdgeFix / viewportSize;
164                 fixvec[i] = fixvecaf[i] = perp;
165
166                 /* Perspective */
167                 if (ProjectionMatrix[3][3] == 0.0) {
168                         /* vPos[i].z is negative and we don't want
169                          * our fixvec to be flipped */
170                         fixvec[i] *= -vPos[i].z;
171                         fixvecaf[i] *= -vPos[i1].z;
172                         cornervec[i] *= -vPos[i].z;
173                 }
174         }
175
176         /* to not let face color bleed */
177         faceColor.a = 0.0;
178
179         /* Start with the same last vertex to create a
180          * degenerate triangle in order to "create"
181          * a new triangle strip */
182         for (int i = 2; i < 5; ++i) {
183                 int vbe = (i - 1) % 3;
184                 int vaf = (i + 1) % 3;
185                 int v = i % 3;
186
187                 doLoopStrip(v, vec3(fixvec[v], Z_OFFSET));
188
189                 /* Only shade the edge that we are currently drawing.
190                  * (fix corner bleeding) */
191                 flag[vbe] |= (EDGE_EXISTS & eflag[vbe]);
192                 flag[vaf] &= ~EDGE_EXISTS;
193                 flag[v]   &= ~EDGE_EXISTS;
194                 doLoopStrip(vaf, vec3(fixvecaf[v], Z_OFFSET));
195
196                 /* corner vertices should not draw edges but draw point only */
197                 flag[vbe] &= ~EDGE_EXISTS;
198 #ifdef VERTEX_SELECTION
199                 doLoopStrip(vaf, vec3(cornervec[vaf], Z_OFFSET));
200 #endif
201         }
202
203         /* finish the loop strip */
204         doLoopStrip(2, vec3(fixvec[2], Z_OFFSET));
205 #endif
206
207         EndPrimitive();
208 }