2025-07-01
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
Copyright (C) 2023 CG Cookie
|
||||
http://cgcookie.com
|
||||
hello@cgcookie.com
|
||||
|
||||
Created by Jonathan Denning
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
struct Options {
|
||||
mat4 uMVPMatrix;
|
||||
float uInOut;
|
||||
}
|
||||
|
||||
uniform Options options;
|
||||
|
||||
in vec4 vPos;
|
||||
in vec4 vFrom;
|
||||
in vec4 vInColor;
|
||||
in vec4 vOutColor;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// vertex shader
|
||||
|
||||
#version 330
|
||||
|
||||
out float aRot;
|
||||
out vec4 aInColor;
|
||||
out vec4 aOutColor;
|
||||
|
||||
float angle(vec2 d) { return atan(d.y, d.x); }
|
||||
|
||||
void main() {
|
||||
vec4 p0 = options.uMVPMatrix * vFrom;
|
||||
vec4 p1 = options.uMVPMatrix * vPos;
|
||||
gl_Position = p1;
|
||||
aRot = angle((p1.xy / p1.w) - (p0.xy / p0.w));
|
||||
aInColor = vInColor;
|
||||
aOutColor = vOutColor;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// fragment shader
|
||||
|
||||
#version 330
|
||||
|
||||
in float aRot;
|
||||
in vec4 aInColor;
|
||||
in vec4 aOutColor;
|
||||
|
||||
out vec4 outColor;
|
||||
|
||||
float alpha(vec2 dir) {
|
||||
vec2 d0 = dir - vec2(1,1);
|
||||
vec2 d1 = dir - vec2(1,-1);
|
||||
|
||||
float d0v = -d0.x/2.0 - d0.y;
|
||||
float d1v = -d1.x/2.0 + d1.y;
|
||||
float dv0 = length(dir);
|
||||
float dv1 = distance(dir, vec2(-2,0));
|
||||
|
||||
if(d0v < 1.0 || d1v < 1.0) return -1.0;
|
||||
// if(dv0 > 1.0) return -1.0;
|
||||
if(dv1 < 1.3) return -1.0;
|
||||
|
||||
if(d0v - 1.0 < (1.0 - options.uInOut) || d1v - 1.0 < (1.0 - options.uInOut)) return 0.0;
|
||||
//if(dv0 > options.uInOut) return 0.0;
|
||||
if(dv1 - 1.3 < (1.0 - options.uInOut)) return 0.0;
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec2 d = 2.0 * (gl_PointCoord - vec2(0.5, 0.5));
|
||||
vec2 dr = vec2(cos(aRot)*d.x - sin(aRot)*d.y, sin(aRot)*d.x + cos(aRot)*d.y);
|
||||
float a = alpha(dr);
|
||||
if(a < 0.0) { discard; return; }
|
||||
outColor = mix(aOutColor, aInColor, a);
|
||||
// https://wiki.blender.org/wiki/Reference/Release_Notes/2.83/Python_API
|
||||
outColor = blender_srgb_to_framebuffer_space(outColor);
|
||||
}
|
||||
@@ -0,0 +1,211 @@
|
||||
/*
|
||||
Copyright (C) 2023 CG Cookie
|
||||
http://cgcookie.com
|
||||
hello@cgcookie.com
|
||||
|
||||
Created by Jonathan Denning
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "bmesh_render_prefix.glsl"
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// vertex shader
|
||||
|
||||
in vec4 vert_pos0; // position wrt model
|
||||
in vec4 vert_pos1; // position wrt model
|
||||
in vec2 vert_offset;
|
||||
in vec4 vert_norm; // normal wrt model
|
||||
in float selected; // is edge selected? 0=no; 1=yes
|
||||
in float warning; // is edge warning? 0=no; 1=yes
|
||||
in float pinned; // is edge pinned? 0=no; 1=yes
|
||||
in float seam; // is edge on seam? 0=no; 1=yes
|
||||
|
||||
out vec4 vPPosition; // final position (projected)
|
||||
out vec4 vCPosition; // position wrt camera
|
||||
out vec4 vWPosition; // position wrt world
|
||||
out vec4 vMPosition; // position wrt model
|
||||
out vec4 vTPosition; // position wrt target
|
||||
out vec4 vWTPosition_x; // position wrt target world
|
||||
out vec4 vWTPosition_y; // position wrt target world
|
||||
out vec4 vWTPosition_z; // position wrt target world
|
||||
out vec4 vCTPosition_x; // position wrt target camera
|
||||
out vec4 vCTPosition_y; // position wrt target camera
|
||||
out vec4 vCTPosition_z; // position wrt target camera
|
||||
out vec4 vPTPosition_x; // position wrt target projected
|
||||
out vec4 vPTPosition_y; // position wrt target projected
|
||||
out vec4 vPTPosition_z; // position wrt target projected
|
||||
out vec3 vCNormal; // normal wrt camera
|
||||
out vec3 vWNormal; // normal wrt world
|
||||
out vec3 vMNormal; // normal wrt model
|
||||
out vec3 vTNormal; // normal wrt target
|
||||
out vec4 vColorIn; // color of geometry inside
|
||||
out vec4 vColorOut; // color of geometry outside (considers selection)
|
||||
out vec2 vPCPosition;
|
||||
|
||||
bool is_warning() { return use_warning() && warning > 0.5; }
|
||||
bool is_pinned() { return use_pinned() && pinned > 0.5; }
|
||||
bool is_seam() { return use_seam() && seam > 0.5; }
|
||||
bool is_selection() { return use_selection() && selected > 0.5; }
|
||||
|
||||
void main() {
|
||||
vec4 pos0 = get_pos(vec3(vert_pos0));
|
||||
vec4 pos1 = get_pos(vec3(vert_pos1));
|
||||
vec2 ppos0 = xyz4(options.matrix_p * options.matrix_v * options.matrix_m * pos0).xy;
|
||||
vec2 ppos1 = xyz4(options.matrix_p * options.matrix_v * options.matrix_m * pos1).xy;
|
||||
vec2 pdir0 = normalize(ppos1 - ppos0);
|
||||
vec2 pdir1 = vec2(-pdir0.y, pdir0.x);
|
||||
vec4 off = vec4((options.radius.x + options.radius.y + 2.0) * pdir1 * 2.0 * (vert_offset.y-0.5) / options.screen_size.xy, 0, 0);
|
||||
|
||||
vec4 pos = pos0 + vert_offset.x * (pos1 - pos0);
|
||||
vec3 norm = normalize(vec3(vert_norm) * vec3(options.vert_scale));
|
||||
|
||||
vec4 wpos = push_pos(options.matrix_m * pos);
|
||||
vec3 wnorm = normalize(mat3(options.matrix_mn) * norm);
|
||||
|
||||
vec4 tpos = options.matrix_ti * wpos;
|
||||
vec3 tnorm = vec3(
|
||||
dot(wnorm, vec3(options.mirror_x)),
|
||||
dot(wnorm, vec3(options.mirror_y)),
|
||||
dot(wnorm, vec3(options.mirror_z)));
|
||||
|
||||
vMPosition = pos;
|
||||
vWPosition = wpos;
|
||||
vCPosition = options.matrix_v * wpos;
|
||||
vPPosition = off + xyz4(options.matrix_p * options.matrix_v * wpos);
|
||||
vPCPosition = xyz4(options.matrix_p * options.matrix_v * wpos).xy;
|
||||
|
||||
vMNormal = norm;
|
||||
vWNormal = wnorm;
|
||||
vCNormal = normalize(mat3(options.matrix_vn) * wnorm);
|
||||
|
||||
vTPosition = tpos;
|
||||
vWTPosition_x = options.matrix_t * vec4(0.0, tpos.y, tpos.z, 1.0);
|
||||
vWTPosition_y = options.matrix_t * vec4(tpos.x, 0.0, tpos.z, 1.0);
|
||||
vWTPosition_z = options.matrix_t * vec4(tpos.x, tpos.y, 0.0, 1.0);
|
||||
vCTPosition_x = options.matrix_v * vWTPosition_x;
|
||||
vCTPosition_y = options.matrix_v * vWTPosition_y;
|
||||
vCTPosition_z = options.matrix_v * vWTPosition_z;
|
||||
vPTPosition_x = options.matrix_p * vCTPosition_x;
|
||||
vPTPosition_y = options.matrix_p * vCTPosition_y;
|
||||
vPTPosition_z = options.matrix_p * vCTPosition_z;
|
||||
vTNormal = tnorm;
|
||||
|
||||
gl_Position = vPPosition;
|
||||
|
||||
vColorIn = options.color_normal;
|
||||
vColorOut = vec4(options.color_normal.rgb, 0.0);
|
||||
|
||||
if(is_selection()) {
|
||||
vColorIn = color_over(options.color_selected, vColorIn);
|
||||
vColorOut = vec4(options.color_selected.rgb, 0.0);
|
||||
}
|
||||
if(is_warning()) vColorOut = color_over(options.color_warning, vColorOut);
|
||||
if(is_pinned()) vColorOut = color_over(options.color_pinned, vColorOut);
|
||||
if(is_seam()) vColorOut = color_over(options.color_seam, vColorOut);
|
||||
|
||||
vColorIn.a *= 1.0 - options.hidden.x;
|
||||
vColorOut.a *= 1.0 - options.hidden.x;
|
||||
|
||||
if(debug_invert_backfacing && vCNormal.z < 0.0) {
|
||||
vColorIn = vec4(vec3(1,1,1) - vColorIn.rgb, vColorIn.a);
|
||||
vColorOut = vec4(vec3(1,1,1) - vColorOut.rgb, vColorOut.a);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// fragment shader
|
||||
|
||||
in vec4 vPPosition; // final position (projected)
|
||||
in vec4 vCPosition; // position wrt camera
|
||||
in vec4 vWPosition; // position wrt world
|
||||
in vec4 vMPosition; // position wrt model
|
||||
in vec4 vTPosition; // position wrt target
|
||||
in vec4 vWTPosition_x; // position wrt target world
|
||||
in vec4 vWTPosition_y; // position wrt target world
|
||||
in vec4 vWTPosition_z; // position wrt target world
|
||||
in vec4 vCTPosition_x; // position wrt target camera
|
||||
in vec4 vCTPosition_y; // position wrt target camera
|
||||
in vec4 vCTPosition_z; // position wrt target camera
|
||||
in vec4 vPTPosition_x; // position wrt target projected
|
||||
in vec4 vPTPosition_y; // position wrt target projected
|
||||
in vec4 vPTPosition_z; // position wrt target projected
|
||||
in vec3 vCNormal; // normal wrt camera
|
||||
in vec3 vWNormal; // normal wrt world
|
||||
in vec3 vMNormal; // normal wrt model
|
||||
in vec3 vTNormal; // normal wrt target
|
||||
in vec4 vColorIn; // color of geometry inside (considers selection)
|
||||
in vec4 vColorOut; // color of geometry outside
|
||||
in vec2 vPCPosition;
|
||||
|
||||
out vec4 outColor;
|
||||
out float gl_FragDepth;
|
||||
|
||||
void main() {
|
||||
float clip = options.clip[1] - options.clip[0];
|
||||
float focus = (view_distance() - options.clip[0]) / clip + 0.04;
|
||||
|
||||
float dist_from_center = length(options.screen_size.xy * (vPCPosition - vPPosition.xy));
|
||||
float alpha_mult = 1.0 - (dist_from_center - (options.radius.x + options.radius.y));
|
||||
if(alpha_mult <= 0) {
|
||||
discard;
|
||||
return;
|
||||
}
|
||||
|
||||
float mix_in_out = clamp(dist_from_center - options.radius.x, 0.0, 1.0);
|
||||
vec4 vColor = mix(vColorIn, vColorOut, mix_in_out);
|
||||
vec3 rgb = vColor.rgb;
|
||||
float alpha = vColor.a * min(1.0, alpha_mult);
|
||||
|
||||
if(is_view_perspective()) {
|
||||
// perspective projection
|
||||
vec3 v = xyz3(vCPosition);
|
||||
float l = length(v);
|
||||
float l_clip = (l - options.clip[0]) / clip;
|
||||
float d = -dot(vCNormal, v) / l;
|
||||
if(d <= 0.0) {
|
||||
if(cull_backfaces()) {
|
||||
alpha = 0.0;
|
||||
discard;
|
||||
return;
|
||||
} else {
|
||||
alpha *= min(1.0, alpha_backface());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// orthographic projection
|
||||
vec3 v = vec3(0, 0, clip * 0.5); // + vCPosition.xyz / vCPosition.w;
|
||||
float l = length(v);
|
||||
float l_clip = (l - options.clip[0]) / clip;
|
||||
float d = dot(vCNormal, v) / l;
|
||||
if(d <= 0.0) {
|
||||
if(cull_backfaces()) {
|
||||
alpha = 0.0;
|
||||
discard;
|
||||
return;
|
||||
} else {
|
||||
alpha *= min(1.0, alpha_backface());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
alpha *= min(1.0, pow(max(vCNormal.z, 0.01), 0.25));
|
||||
outColor = coloring(vec4(rgb, alpha));
|
||||
// https://wiki.blender.org/wiki/Reference/Release_Notes/2.83/Python_API
|
||||
outColor = blender_srgb_to_framebuffer_space(outColor);
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
Copyright (C) 2023 CG Cookie
|
||||
http://cgcookie.com
|
||||
hello@cgcookie.com
|
||||
|
||||
Created by Jonathan Denning
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define BMESH_FACE
|
||||
|
||||
#include "bmesh_render_prefix.glsl"
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// vertex shader
|
||||
|
||||
in vec4 vert_pos; // position wrt model
|
||||
in vec4 vert_norm; // normal wrt model
|
||||
in float selected; // is face selected? 0=no; 1=yes
|
||||
in float pinned; // is face pinned? 0=no; 1=yes
|
||||
|
||||
out vec4 vPPosition; // final position (projected)
|
||||
out vec4 vCPosition; // position wrt camera
|
||||
out vec4 vTPosition; // position wrt target
|
||||
out vec4 vCTPosition_x; // position wrt target camera
|
||||
out vec4 vCTPosition_y; // position wrt target camera
|
||||
out vec4 vCTPosition_z; // position wrt target camera
|
||||
out vec4 vPTPosition_x; // position wrt target projected
|
||||
out vec4 vPTPosition_y; // position wrt target projected
|
||||
out vec4 vPTPosition_z; // position wrt target projected
|
||||
out vec3 vCNormal; // normal wrt camera
|
||||
out vec4 vColor; // color of geometry (considers selection)
|
||||
|
||||
void main() {
|
||||
//vec4 off = vec4(radius * (vert_dir0 * vert_offset.x + vert_dir1 * vert_offset.y) / screen_size, 0, 0);
|
||||
|
||||
vec4 pos = get_pos(vec3(vert_pos));
|
||||
vec3 norm = normalize(vec3(vert_norm) * vec3(options.vert_scale));
|
||||
|
||||
vec4 wpos = push_pos(options.matrix_m * pos);
|
||||
vec3 wnorm = normalize(mat3(options.matrix_mn) * norm);
|
||||
|
||||
vec4 tpos = options.matrix_ti * wpos;
|
||||
vec3 tnorm = vec3(
|
||||
dot(wnorm, vec3(options.mirror_x)),
|
||||
dot(wnorm, vec3(options.mirror_y)),
|
||||
dot(wnorm, vec3(options.mirror_z)));
|
||||
|
||||
vCPosition = options.matrix_v * wpos;
|
||||
vPPosition = xyz4(options.matrix_p * options.matrix_v * wpos);
|
||||
|
||||
vCNormal = normalize(mat3(options.matrix_vn) * wnorm);
|
||||
|
||||
vTPosition = tpos;
|
||||
vCTPosition_x = options.matrix_v * options.matrix_t * vec4(0.0, tpos.y, tpos.z, 1.0);
|
||||
vCTPosition_y = options.matrix_v * options.matrix_t * vec4(tpos.x, 0.0, tpos.z, 1.0);
|
||||
vCTPosition_z = options.matrix_v * options.matrix_t * vec4(tpos.x, tpos.y, 0.0, 1.0);
|
||||
vPTPosition_x = options.matrix_p * vCTPosition_x;
|
||||
vPTPosition_y = options.matrix_p * vCTPosition_y;
|
||||
vPTPosition_z = options.matrix_p * vCTPosition_z;
|
||||
|
||||
gl_Position = vPPosition;
|
||||
|
||||
vColor = options.color_normal;
|
||||
|
||||
if(use_selection() && selected > 0.5) vColor = mix(vColor, options.color_selected, 0.75);
|
||||
if(use_pinned() && pinned > 0.5) vColor = mix(vColor, options.color_pinned, 0.75);
|
||||
|
||||
vColor.a *= 1.0 - options.hidden.x;
|
||||
|
||||
if(debug_invert_backfacing && vCNormal.z < 0.0) {
|
||||
vColor = vec4(vec3(1,1,1) - vColor.rgb, vColor.a);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// fragment shader
|
||||
|
||||
in vec4 vPPosition; // final position (projected)
|
||||
in vec4 vCPosition; // position wrt camera
|
||||
in vec4 vTPosition; // position wrt target
|
||||
in vec4 vCTPosition_x; // position wrt target camera
|
||||
in vec4 vCTPosition_y; // position wrt target camera
|
||||
in vec4 vCTPosition_z; // position wrt target camera
|
||||
in vec4 vPTPosition_x; // position wrt target projected
|
||||
in vec4 vPTPosition_y; // position wrt target projected
|
||||
in vec4 vPTPosition_z; // position wrt target projected
|
||||
in vec3 vCNormal; // normal wrt camera
|
||||
in vec4 vColor; // color of geometry (considers selection)
|
||||
|
||||
out vec4 outColor;
|
||||
out float gl_FragDepth;
|
||||
|
||||
void main() {
|
||||
float clip = options.clip[1] - options.clip[0];
|
||||
float focus = (view_distance() - options.clip[0]) / clip + 0.04;
|
||||
vec3 rgb = vColor.rgb;
|
||||
float alpha = vColor.a;
|
||||
|
||||
if(vCNormal.z < 0) { discard; return; }
|
||||
|
||||
if(is_view_perspective()) {
|
||||
// perspective projection
|
||||
vec3 v = xyz3(vCPosition);
|
||||
float l = length(v);
|
||||
float l_clip = (l - options.clip[0]) / clip;
|
||||
float d = -dot(vCNormal, v) / l;
|
||||
if(d <= 0.0) {
|
||||
if(cull_backfaces()) {
|
||||
alpha = 0.0;
|
||||
discard;
|
||||
return;
|
||||
} else {
|
||||
alpha *= min(1.0, alpha_backface());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// orthographic projection
|
||||
vec3 v = vec3(0, 0, clip * 0.5); // + vCPosition.xyz / vCPosition.w;
|
||||
float l = length(v);
|
||||
float l_clip = (l - options.clip[0]) / clip;
|
||||
float d = dot(vCNormal, v) / l;
|
||||
if(d <= 0.0) {
|
||||
if(cull_backfaces()) {
|
||||
alpha = 0.0;
|
||||
discard;
|
||||
return;
|
||||
} else {
|
||||
alpha *= min(1.0, alpha_backface());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
alpha *= min(1.0, pow(max(vCNormal.z, 0.01), 0.25));
|
||||
outColor = coloring(vec4(rgb, alpha));
|
||||
// https://wiki.blender.org/wiki/Reference/Release_Notes/2.83/Python_API
|
||||
outColor = blender_srgb_to_framebuffer_space(outColor);
|
||||
}
|
||||
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
Copyright (C) 2023 CG Cookie
|
||||
http://cgcookie.com
|
||||
hello@cgcookie.com
|
||||
|
||||
Created by Jonathan Denning
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// common shader
|
||||
|
||||
struct Options {
|
||||
mat4 matrix_m; // model xform matrix
|
||||
mat4 matrix_mn; // model xform matrix for normal (inv transpose of matrix_m)
|
||||
mat4 matrix_t; // target xform matrix
|
||||
mat4 matrix_ti; // target xform matrix inverse
|
||||
mat4 matrix_v; // view xform matrix
|
||||
mat4 matrix_vn; // view xform matrix for normal
|
||||
mat4 matrix_p; // projection matrix
|
||||
|
||||
vec4 clip;
|
||||
vec4 screen_size;
|
||||
vec4 view_settings0; // [ view_distance, perspective, focus_mult, alpha_backface ]
|
||||
vec4 view_settings1; // [ cull_backfaces, unit_scaling_factor, normal_offset (how far to push geo along normal), constrain_offset (should constrain by focus) ]
|
||||
vec4 view_settings2; // [ view push, xxx, xxx, xxx ]
|
||||
vec4 view_position;
|
||||
|
||||
vec4 color_normal; // color of geometry if not selected
|
||||
vec4 color_selected; // color of geometry if selected
|
||||
vec4 color_warning; // color of geometry if warning
|
||||
vec4 color_pinned; // color of geometry if pinned
|
||||
vec4 color_seam; // color of geometry if seam
|
||||
|
||||
vec4 use_settings0; // [ selection, warning, pinned, seam ]
|
||||
vec4 use_settings1; // [ rounding, xxx, xxx, xxx ]
|
||||
|
||||
vec4 mirror_settings; // [ view (0=none; 1=edge at plane; 2=color faces on far side of plane), effect (0=no effect, 1=full), xxx, xxx ]
|
||||
vec4 mirroring; // mirror along axis: 0=false, 1=true
|
||||
vec4 mirror_o; // mirroring origin wrt world
|
||||
vec4 mirror_x; // mirroring x-axis wrt world
|
||||
vec4 mirror_y; // mirroring y-axis wrt world
|
||||
vec4 mirror_z; // mirroring z-axis wrt world
|
||||
|
||||
vec4 vert_scale; // used for mirroring
|
||||
|
||||
vec4 hidden; // affects alpha for geometry below surface. 0=opaque, 1=transparent
|
||||
vec4 offset;
|
||||
vec4 dotoffset;
|
||||
|
||||
vec4 radius;
|
||||
};
|
||||
uniform Options options;
|
||||
|
||||
const bool srgbTarget = true;
|
||||
const bool debug_invert_backfacing = false;
|
||||
|
||||
int mirror_view() {
|
||||
float v = options.mirror_settings[0];
|
||||
if(v > 1.5) return 2;
|
||||
if(v > 0.5) return 1;
|
||||
return 0;
|
||||
}
|
||||
float mirror_effect() { return options.mirror_settings[1]; }
|
||||
|
||||
float view_distance() { return options.view_settings0[0]; }
|
||||
bool is_view_perspective() { return options.view_settings0[1] > 0.5; }
|
||||
float focus_mult() { return options.view_settings0[2]; }
|
||||
float alpha_backface() { return options.view_settings0[3]; }
|
||||
bool cull_backfaces() { return options.view_settings1[0] > 0.5; }
|
||||
float unit_scaling_factor() { return options.view_settings1[1]; }
|
||||
float normal_offset() { return options.view_settings1[2]; }
|
||||
bool constrain_offset() { return options.view_settings1[3] > 0.5; }
|
||||
float view_push() { return options.view_settings2[0]; }
|
||||
vec4 view_position() { return options.view_position; }
|
||||
|
||||
float clip_near() { return options.clip[0]; }
|
||||
float clip_far() { return options.clip[1]; }
|
||||
|
||||
bool use_selection() { return options.use_settings0[0] > 0.5; }
|
||||
bool use_warning() { return options.use_settings0[1] > 0.5; }
|
||||
bool use_pinned() { return options.use_settings0[2] > 0.5; }
|
||||
bool use_seam() { return options.use_settings0[3] > 0.5; }
|
||||
bool use_rounding() { return options.use_settings1[0] > 0.5; }
|
||||
|
||||
float magic_offset() { return options.offset.x; }
|
||||
float magic_dotoffset() { return options.dotoffset.x; }
|
||||
|
||||
vec4 color_over(vec4 top, vec4 bottom) {
|
||||
float a = top.a + (1.0 - top.a) * bottom.a;
|
||||
vec3 c = (top.rgb * top.a + (1.0 - top.a) * bottom.a * bottom.rgb) / a;
|
||||
return vec4(c, a);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// vertex shader
|
||||
|
||||
vec4 get_pos(vec3 p) {
|
||||
float mult = 1.0;
|
||||
if(constrain_offset()) {
|
||||
mult = 1.0;
|
||||
} else {
|
||||
float clip_dist = clip_far() - clip_near();
|
||||
float focus = (view_distance() - clip_near()) / clip_dist + 0.04;
|
||||
mult = focus;
|
||||
}
|
||||
vec3 norm_offset = vec3(vert_norm) * normal_offset() * mult;
|
||||
vec3 mirror = vec3(options.vert_scale);
|
||||
return vec4((p + norm_offset) * mirror, 1.0);
|
||||
}
|
||||
|
||||
vec4 push_pos(vec4 p) {
|
||||
float clip_dist = clip_far() - clip_near();
|
||||
float focus = (1.0 - clamp((view_distance() - clip_near()) / clip_dist, 0.0, 1.0)) * 0.1;
|
||||
return vec4( mix(view_position().xyz, p.xyz, view_push()), p.w);
|
||||
}
|
||||
|
||||
vec4 xyz4(vec4 v) { return vec4(v.xyz / abs(v.w), sign(v.w)); }
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// fragment shader
|
||||
|
||||
vec3 xyz3(vec4 v) { return v.xyz / v.w; }
|
||||
|
||||
// adjusts color based on mirroring settings and fragment position
|
||||
vec4 coloring(vec4 orig) {
|
||||
vec4 mixer = vec4(0.6, 0.6, 0.6, 0.0);
|
||||
if(mirror_view() == 0) {
|
||||
// NO SYMMETRY VIEW
|
||||
} else if(mirror_view() == 1) {
|
||||
// EDGE VIEW
|
||||
float edge_width = 5.0 / options.screen_size.y;
|
||||
vec3 viewdir;
|
||||
if(is_view_perspective()) {
|
||||
viewdir = normalize(xyz3(vCPosition));
|
||||
} else {
|
||||
viewdir = vec3(0,0,1);
|
||||
}
|
||||
vec3 diffc_x = xyz3(vCTPosition_x) - xyz3(vCPosition);
|
||||
vec3 diffc_y = xyz3(vCTPosition_y) - xyz3(vCPosition);
|
||||
vec3 diffc_z = xyz3(vCTPosition_z) - xyz3(vCPosition);
|
||||
vec3 dirc_x = normalize(diffc_x);
|
||||
vec3 dirc_y = normalize(diffc_y);
|
||||
vec3 dirc_z = normalize(diffc_z);
|
||||
vec3 diffp_x = xyz3(vPTPosition_x) - xyz3(vPPosition);
|
||||
vec3 diffp_y = xyz3(vPTPosition_y) - xyz3(vPPosition);
|
||||
vec3 diffp_z = xyz3(vPTPosition_z) - xyz3(vPPosition);
|
||||
vec3 aspect = vec3(1.0, options.screen_size.y / options.screen_size.x, 0.0);
|
||||
|
||||
float s = 0.0;
|
||||
if(options.mirroring.x > 0.5 && length(diffp_x * aspect) < edge_width * (1.0 - pow(abs(dot(viewdir,dirc_x)), 10.0))) {
|
||||
mixer.r = 1.0;
|
||||
s = max(s, (vTPosition.x < 0.0) ? 1.0 : 0.1);
|
||||
}
|
||||
if(options.mirroring.y > 0.5 && length(diffp_y * aspect) < edge_width * (1.0 - pow(abs(dot(viewdir,dirc_y)), 10.0))) {
|
||||
mixer.g = 1.0;
|
||||
s = max(s, (vTPosition.y > 0.0) ? 1.0 : 0.1);
|
||||
}
|
||||
if(options.mirroring.z > 0.5 && length(diffp_z * aspect) < edge_width * (1.0 - pow(abs(dot(viewdir,dirc_z)), 10.0))) {
|
||||
mixer.b = 1.0;
|
||||
s = max(s, (vTPosition.z < 0.0) ? 1.0 : 0.1);
|
||||
}
|
||||
mixer.a = mirror_effect() * s + mixer.a * (1.0 - s);
|
||||
} else if(mirror_view() == 2) {
|
||||
// FACE VIEW
|
||||
if(options.mirroring.x > 0.5 && vTPosition.x < 0.0) {
|
||||
mixer.r = 1.0;
|
||||
mixer.a = mirror_effect();
|
||||
}
|
||||
if(options.mirroring.y > 0.5 && vTPosition.y > 0.0) {
|
||||
mixer.g = 1.0;
|
||||
mixer.a = mirror_effect();
|
||||
}
|
||||
if(options.mirroring.z > 0.5 && vTPosition.z < 0.0) {
|
||||
mixer.b = 1.0;
|
||||
mixer.a = mirror_effect();
|
||||
}
|
||||
}
|
||||
|
||||
float m0 = mixer.a, m1 = 1.0 - mixer.a;
|
||||
|
||||
#ifdef BMESH_FACE
|
||||
return vec4(mixer.rgb * m0 + orig.rgb * orig.a * m1, m0 + orig.a * m1);
|
||||
#else
|
||||
return vec4(mixer.rgb * m0 + orig.rgb * m1, m0 + orig.a * m1);
|
||||
#endif
|
||||
}
|
||||
|
||||
vec4 blender_srgb_to_framebuffer_space(vec4 in_color)
|
||||
{
|
||||
if (srgbTarget) {
|
||||
vec3 c = max(in_color.rgb, vec3(0.0));
|
||||
vec3 c1 = c * (1.0 / 12.92);
|
||||
vec3 c2 = pow((c + 0.055) * (1.0 / 1.055), vec3(2.4));
|
||||
in_color.rgb = mix(c1, c2, step(vec3(0.04045), c));
|
||||
}
|
||||
return in_color;
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
Copyright (C) 2023 CG Cookie
|
||||
http://cgcookie.com
|
||||
hello@cgcookie.com
|
||||
|
||||
Created by Jonathan Denning
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "bmesh_render_prefix.glsl"
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// vertex shader
|
||||
|
||||
in vec4 vert_pos; // position wrt model
|
||||
in vec2 vert_offset;
|
||||
in vec4 vert_norm; // normal wrt model
|
||||
in float selected; // is vertex selected? 0=no; 1=yes
|
||||
in float warning; // is vertex warning? 0=no; 1=yes
|
||||
in float pinned; // is vertex pinned? 0=no; 1=yes
|
||||
in float seam; // is vertex along seam? 0=no; 1=yes
|
||||
|
||||
out vec4 vPPosition; // final position (projected)
|
||||
out vec4 vCPosition; // position wrt camera
|
||||
out vec4 vTPosition; // position wrt target
|
||||
out vec4 vCTPosition_x; // position wrt target camera
|
||||
out vec4 vCTPosition_y; // position wrt target camera
|
||||
out vec4 vCTPosition_z; // position wrt target camera
|
||||
out vec4 vPTPosition_x; // position wrt target projected
|
||||
out vec4 vPTPosition_y; // position wrt target projected
|
||||
out vec4 vPTPosition_z; // position wrt target projected
|
||||
out vec3 vCNormal; // normal wrt camera
|
||||
out vec4 vColor; // color of geometry (considers selection)
|
||||
out vec2 vPCPosition;
|
||||
|
||||
void main() {
|
||||
vec2 vo = vert_offset * 2 - vec2(1, 1);
|
||||
vec4 off = vec4((options.radius.x + 2) * vo / options.screen_size.xy, 0, 0);
|
||||
|
||||
vec4 pos = get_pos(vec3(vert_pos));
|
||||
vec3 norm = normalize(vec3(vert_norm) * vec3(options.vert_scale));
|
||||
|
||||
vec4 wpos = push_pos(options.matrix_m * pos);
|
||||
vec3 wnorm = normalize(mat3(options.matrix_mn) * norm);
|
||||
|
||||
vec4 tpos = options.matrix_ti * wpos;
|
||||
vec3 tnorm = vec3(
|
||||
dot(wnorm, vec3(options.mirror_x)),
|
||||
dot(wnorm, vec3(options.mirror_y)),
|
||||
dot(wnorm, vec3(options.mirror_z)));
|
||||
|
||||
vCPosition = options.matrix_v * wpos;
|
||||
vPPosition = off + xyz4(options.matrix_p * options.matrix_v * wpos);
|
||||
vPCPosition = xyz4(options.matrix_p * options.matrix_v * wpos).xy;
|
||||
|
||||
vCNormal = normalize(mat3(options.matrix_vn) * wnorm);
|
||||
|
||||
vTPosition = tpos;
|
||||
vCTPosition_x = options.matrix_v * options.matrix_t * vec4(0.0, tpos.y, tpos.z, 1.0);
|
||||
vCTPosition_y = options.matrix_v * options.matrix_t * vec4(tpos.x, 0.0, tpos.z, 1.0);
|
||||
vCTPosition_z = options.matrix_v * options.matrix_t * vec4(tpos.x, tpos.y, 0.0, 1.0);
|
||||
vPTPosition_x = options.matrix_p * vCTPosition_x;
|
||||
vPTPosition_y = options.matrix_p * vCTPosition_y;
|
||||
vPTPosition_z = options.matrix_p * vCTPosition_z;
|
||||
|
||||
gl_Position = vPPosition;
|
||||
|
||||
vColor = options.color_normal;
|
||||
|
||||
if(use_warning() && warning > 0.5) vColor = mix(vColor, options.color_warning, 0.75);
|
||||
if(use_selection() && selected > 0.5) vColor = mix(vColor, options.color_selected, 0.75);
|
||||
if(use_pinned() && pinned > 0.5) vColor = mix(vColor, options.color_pinned, 0.75);
|
||||
if(use_seam() && seam > 0.5) vColor = mix(vColor, options.color_seam, 0.75);
|
||||
|
||||
vColor.a *= 1.0 - options.hidden.x;
|
||||
|
||||
if(debug_invert_backfacing && vCNormal.z < 0.0) {
|
||||
vColor = vec4(vec3(1,1,1) - vColor.rgb, vColor.a);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// fragment shader
|
||||
|
||||
in vec4 vPPosition; // final position (projected)
|
||||
in vec4 vCPosition; // position wrt camera
|
||||
in vec4 vTPosition; // position wrt target
|
||||
in vec4 vCTPosition_x; // position wrt target camera
|
||||
in vec4 vCTPosition_y; // position wrt target camera
|
||||
in vec4 vCTPosition_z; // position wrt target camera
|
||||
in vec4 vPTPosition_x; // position wrt target projected
|
||||
in vec4 vPTPosition_y; // position wrt target projected
|
||||
in vec4 vPTPosition_z; // position wrt target projected
|
||||
in vec3 vCNormal; // normal wrt camera
|
||||
in vec4 vColor; // color of geometry (considers selection)
|
||||
in vec2 vPCPosition;
|
||||
|
||||
out vec4 outColor;
|
||||
out float gl_FragDepth;
|
||||
|
||||
void main() {
|
||||
float clip = options.clip[1] - options.clip[0];
|
||||
float focus = (view_distance() - options.clip[0]) / clip + 0.04;
|
||||
vec3 rgb = vColor.rgb;
|
||||
float alpha = vColor.a;
|
||||
|
||||
if(use_rounding()) {
|
||||
float dist_from_center = length(options.screen_size.xy * (vPCPosition - vPPosition.xy));
|
||||
float alpha_mult = 1.0 - (dist_from_center - options.radius.x);
|
||||
if(alpha_mult <= 0) {
|
||||
discard;
|
||||
return;
|
||||
}
|
||||
alpha *= min(1.0, alpha_mult);
|
||||
}
|
||||
|
||||
if(is_view_perspective()) {
|
||||
// perspective projection
|
||||
vec3 v = xyz3(vCPosition);
|
||||
float l = length(v);
|
||||
float l_clip = (l - options.clip[0]) / clip;
|
||||
float d = -dot(vCNormal, v) / l;
|
||||
if(d <= 0.0) {
|
||||
if(cull_backfaces()) {
|
||||
alpha = 0.0;
|
||||
discard;
|
||||
return;
|
||||
} else {
|
||||
alpha *= min(1.0, alpha_backface());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// orthographic projection
|
||||
vec3 v = vec3(0, 0, clip * 0.5); // + vCPosition.xyz / vCPosition.w;
|
||||
float l = length(v);
|
||||
float l_clip = (l - options.clip[0]) / clip;
|
||||
float d = dot(vCNormal, v) / l;
|
||||
if(d <= 0.0) {
|
||||
if(cull_backfaces()) {
|
||||
alpha = 0.0;
|
||||
discard;
|
||||
return;
|
||||
} else {
|
||||
alpha *= min(1.0, alpha_backface());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
alpha *= min(1.0, pow(max(vCNormal.z, 0.01), 0.25));
|
||||
outColor = coloring(vec4(rgb, alpha));
|
||||
// https://wiki.blender.org/wiki/Reference/Release_Notes/2.83/Python_API
|
||||
outColor = blender_srgb_to_framebuffer_space(outColor);
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
Copyright (C) 2023 CG Cookie
|
||||
http://cgcookie.com
|
||||
hello@cgcookie.com
|
||||
|
||||
Created by Jonathan Denning
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
draws an antialiased, stippled circle
|
||||
ex: stipple [3,2] color0 '=' color1 '-'
|
||||
produces '===--===--===--===-' (just wrapped as a circle!)
|
||||
*/
|
||||
|
||||
struct Options {
|
||||
mat4 MVPMatrix; // pixel matrix
|
||||
vec4 screensize; // width,height of screen (for antialiasing)
|
||||
vec4 center; // center of circle
|
||||
vec4 color0; // color of on stipple
|
||||
vec4 color1; // color of off stipple
|
||||
vec4 radius_width; // radius of circle, line width (perp to line)
|
||||
vec4 stipple_data; // stipple lengths, offset
|
||||
};
|
||||
|
||||
uniform Options options;
|
||||
|
||||
const bool srgbTarget = true;
|
||||
const float TAU = 6.28318530718;
|
||||
|
||||
float radius() { return options.radius_width.x; }
|
||||
float width() { return options.radius_width.y; }
|
||||
vec2 stipple_lengths() { return options.stipple_data.xy; }
|
||||
float stipple_offset() { return options.stipple_data.z; }
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// vertex shader
|
||||
|
||||
in vec2 pos; // x: [0,1], ratio of circumference. y: [0,1], inner/outer radius (width)
|
||||
|
||||
noperspective out vec2 vpos; // position scaled by screensize
|
||||
noperspective out vec2 cpos; // center of line, scaled by screensize
|
||||
noperspective out float offset; // stipple offset of individual fragment
|
||||
|
||||
|
||||
void main() {
|
||||
float circumference = TAU * radius();
|
||||
float ang = TAU * pos.x;
|
||||
float r = radius() + (pos.y - 0.5) * (width() + 2.0);
|
||||
vec2 v = vec2(cos(ang), sin(ang));
|
||||
vec2 p = options.center.xy + vec2(0.5,0.5) + r * v;
|
||||
vec2 cp = options.center.xy + vec2(0.5,0.5) + radius() * v;
|
||||
vec4 pcp = options.MVPMatrix * vec4(cp, 0.0, 1.0);
|
||||
gl_Position = options.MVPMatrix * vec4(p, 0.0, 1.0);
|
||||
vpos = vec2(gl_Position.x * options.screensize.x, gl_Position.y * options.screensize.y);
|
||||
cpos = vec2(pcp.x * options.screensize.x, pcp.y * options.screensize.y);
|
||||
offset = circumference * pos.x + stipple_offset();
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// fragment shader
|
||||
|
||||
noperspective in vec2 vpos;
|
||||
noperspective in vec2 cpos;
|
||||
noperspective in float offset;
|
||||
|
||||
out vec4 outColor;
|
||||
|
||||
vec4 blender_srgb_to_framebuffer_space(vec4 in_color)
|
||||
{
|
||||
if (srgbTarget) {
|
||||
vec3 c = max(in_color.rgb, vec3(0.0));
|
||||
vec3 c1 = c * (1.0 / 12.92);
|
||||
vec3 c2 = pow((c + 0.055) * (1.0 / 1.055), vec3(2.4));
|
||||
in_color.rgb = mix(c1, c2, step(vec3(0.04045), c));
|
||||
}
|
||||
return in_color;
|
||||
}
|
||||
|
||||
void main() {
|
||||
// stipple
|
||||
if(stipple_lengths().y <= 0) { // stipple disabled
|
||||
outColor = options.color0;
|
||||
} else {
|
||||
float t = stipple_lengths().x + stipple_lengths().y;
|
||||
float s = mod(offset, t);
|
||||
float sd = s - stipple_lengths().x;
|
||||
if(s <= 0.5 || s >= t - 0.5) {
|
||||
outColor = mix(options.color1, options.color0, mod(s + 0.5, t));
|
||||
} else if(s >= stipple_lengths().x - 0.5 && s <= stipple_lengths().x + 0.5) {
|
||||
outColor = mix(options.color0, options.color1, s - (stipple_lengths().x - 0.5));
|
||||
} else if(s < stipple_lengths().x) {
|
||||
outColor = options.color0;
|
||||
} else {
|
||||
outColor = options.color1;
|
||||
}
|
||||
}
|
||||
// antialias along edge of line
|
||||
float cdist = length(cpos - vpos);
|
||||
if(cdist > width()) {
|
||||
outColor.a *= clamp(1.0 - (cdist - width()), 0.0, 1.0);
|
||||
}
|
||||
// https://wiki.blender.org/wiki/Reference/Release_Notes/2.83/Python_API
|
||||
outColor = blender_srgb_to_framebuffer_space(outColor);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
Copyright (C) 2023 CG Cookie
|
||||
http://cgcookie.com
|
||||
hello@cgcookie.com
|
||||
|
||||
Created by Jonathan Denning
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
struct Options {
|
||||
mat4 MVPMatrix; // pixel matrix
|
||||
vec4 screensize; // [ width, height, _, _ ] of screen (for antialiasing)
|
||||
vec4 center; // center of circle
|
||||
vec4 color; // color of circle
|
||||
vec4 plane_x; // x direction in plane the circle lies in
|
||||
vec4 plane_y; // y direction in plane the circle lies in
|
||||
vec4 settings; // [ radius, line width (perp to line in plane), depth range near for drawover, depth range far ]
|
||||
};
|
||||
|
||||
uniform Options options;
|
||||
|
||||
const float TAU = 6.28318530718;
|
||||
const bool srgbTarget = true;
|
||||
|
||||
float radius() { return options.settings[0]; }
|
||||
float width() { return options.settings[1]; }
|
||||
float depth_near() { return options.settings[2]; }
|
||||
float depth_far() { return options.settings[3]; }
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// vertex shader
|
||||
|
||||
in vec2 pos; // x: [0,1], ratio of circumference. y: [0,1], inner/outer radius (width)
|
||||
|
||||
noperspective out vec2 vpos; // position scaled by screensize
|
||||
noperspective out vec2 cpos; // center of line, scaled by screensize
|
||||
|
||||
void main() {
|
||||
float ang = TAU * pos.x;
|
||||
float r = radius() + (pos.y - 0.5) * width();
|
||||
vec3 v = options.plane_x.xyz * cos(ang) + options.plane_y.xyz * sin(ang);
|
||||
vec3 p = options.center.xyz + r * v;
|
||||
vec3 cp = options.center.xyz + radius() * v;
|
||||
vec4 pcp = options.MVPMatrix * vec4(cp, 1.0);
|
||||
gl_Position = options.MVPMatrix * vec4(p, 1.0);
|
||||
vpos = vec2(gl_Position.x * options.screensize.x, gl_Position.y * options.screensize.y);
|
||||
cpos = vec2(pcp.x * options.screensize.x, pcp.y * options.screensize.y);
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// fragment shader
|
||||
|
||||
noperspective in vec2 vpos;
|
||||
noperspective in vec2 cpos;
|
||||
|
||||
out vec4 outColor;
|
||||
out float gl_FragDepth;
|
||||
|
||||
vec4 blender_srgb_to_framebuffer_space(vec4 in_color)
|
||||
{
|
||||
if (srgbTarget) {
|
||||
vec3 c = max(in_color.rgb, vec3(0.0));
|
||||
vec3 c1 = c * (1.0 / 12.92);
|
||||
vec3 c2 = pow((c + 0.055) * (1.0 / 1.055), vec3(2.4));
|
||||
in_color.rgb = mix(c1, c2, step(vec3(0.04045), c));
|
||||
}
|
||||
return in_color;
|
||||
}
|
||||
|
||||
void main() {
|
||||
outColor = options.color;
|
||||
|
||||
// antialias along edge of line.... NOT WORKING!
|
||||
float cdist = length(cpos - vpos);
|
||||
if(cdist > width()) {
|
||||
outColor.a *= clamp(1.0 - (cdist - width()), 1.0, 1.0);
|
||||
}
|
||||
|
||||
// https://wiki.blender.org/wiki/Reference/Release_Notes/2.83/Python_API
|
||||
outColor = blender_srgb_to_framebuffer_space(outColor);
|
||||
gl_FragDepth = mix(depth_near(), depth_far(), gl_FragCoord.z);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
Copyright (C) 2023 CG Cookie
|
||||
http://cgcookie.com
|
||||
hello@cgcookie.com
|
||||
|
||||
Created by Jonathan Denning
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
draws an antialiased, stippled line
|
||||
ex: stipple [3,2] color0 '=' color1 '-'
|
||||
produces '===--===--===--===-'
|
||||
| |
|
||||
\_pos0 pos1_/
|
||||
*/
|
||||
|
||||
struct Options {
|
||||
mat4 MVPMatrix; // pixel matrix
|
||||
vec4 screensize; // width,height of screen (for antialiasing)
|
||||
vec4 pos0; // front end of line
|
||||
vec4 pos1; // back end of line
|
||||
vec4 color0; // color of on stipple
|
||||
vec4 color1; // color of off stipple
|
||||
vec4 stipple_width; // lengths for stipple (x: color0, y: color1, z: initial shift) and line width (perp to line)
|
||||
};
|
||||
uniform Options options;
|
||||
|
||||
const bool srgbTarget = true;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// vertex shader
|
||||
|
||||
in vec2 pos; // which corner of line ([0,0], [0,1], [1,1], [1,0])
|
||||
|
||||
noperspective out vec2 vpos; // position scaled by screensize
|
||||
noperspective out vec2 cpos; // center of line, scaled by screensize
|
||||
noperspective out float offset; // stipple offset of individual fragment
|
||||
|
||||
void main() {
|
||||
vec2 v01 = options.pos1.xy - options.pos0.xy;
|
||||
vec2 d01 = normalize(v01);
|
||||
vec2 perp = vec2(-d01.y, d01.x);
|
||||
vec2 cp = options.pos0.xy + vec2(0.5,0.5) + (pos.x * v01);
|
||||
vec2 p = cp + ((options.stipple_width.w + 2.0) * (pos.y - 0.5) * perp);
|
||||
vec4 pcp = options.MVPMatrix * vec4(cp, 0.0, 1.0);
|
||||
gl_Position = options.MVPMatrix * vec4(p, 0.0, 1.0);
|
||||
offset = length(v01) * pos.x + options.stipple_width.z;
|
||||
vpos = vec2(gl_Position.x * options.screensize.x, gl_Position.y * options.screensize.y);
|
||||
cpos = vec2(pcp.x * options.screensize.x, pcp.y * options.screensize.y);
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// fragment shader
|
||||
|
||||
noperspective in vec2 vpos;
|
||||
noperspective in vec2 cpos;
|
||||
noperspective in float offset;
|
||||
|
||||
out vec4 outColor;
|
||||
|
||||
vec4 blender_srgb_to_framebuffer_space(vec4 in_color)
|
||||
{
|
||||
if (srgbTarget) {
|
||||
vec3 c = max(in_color.rgb, vec3(0.0));
|
||||
vec3 c1 = c * (1.0 / 12.92);
|
||||
vec3 c2 = pow((c + 0.055) * (1.0 / 1.055), vec3(2.4));
|
||||
in_color.rgb = mix(c1, c2, step(vec3(0.04045), c));
|
||||
}
|
||||
return in_color;
|
||||
}
|
||||
|
||||
|
||||
void main() {
|
||||
// stipple
|
||||
if(options.stipple_width.y <= 0) { // stipple disabled
|
||||
outColor = options.color0;
|
||||
} else {
|
||||
float t = options.stipple_width.x + options.stipple_width.y;
|
||||
float s = mod(offset, t);
|
||||
float sd = s - options.stipple_width.x;
|
||||
vec4 colors = options.color1;
|
||||
if(colors.a < (1.0/255.0)) colors.rgb = options.color0.rgb;
|
||||
if(s <= 0.5 || s >= t - 0.5) {
|
||||
outColor = mix(colors, options.color0, mod(s + 0.5, t));
|
||||
} else if(s >= options.stipple_width.x - 0.5 && s <= options.stipple_width.x + 0.5) {
|
||||
outColor = mix(options.color0, colors, s - (options.stipple_width.x - 0.5));
|
||||
} else if(s < options.stipple_width.x) {
|
||||
outColor = options.color0;
|
||||
} else {
|
||||
outColor = colors;
|
||||
}
|
||||
}
|
||||
// antialias along edge of line
|
||||
float cdist = length(cpos - vpos);
|
||||
if(cdist > options.stipple_width.w) {
|
||||
outColor.a *= clamp(1.0 - (cdist - options.stipple_width.w), 0.0, 1.0);
|
||||
}
|
||||
// https://wiki.blender.org/wiki/Reference/Release_Notes/2.83/Python_API
|
||||
outColor = blender_srgb_to_framebuffer_space(outColor);
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
Copyright (C) 2023 CG Cookie
|
||||
http://cgcookie.com
|
||||
hello@cgcookie.com
|
||||
|
||||
Created by Jonathan Denning
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
struct Options {
|
||||
mat4 mvpmatrix; // pixel matrix
|
||||
vec4 screensize; // width,height of screen (for antialiasing)
|
||||
vec4 center; // center of point
|
||||
vec4 radius_border;
|
||||
vec4 color; // color point
|
||||
vec4 colorBorder; // color of border
|
||||
};
|
||||
|
||||
uniform Options options;
|
||||
|
||||
const bool srgbTarget = true;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// vertex shader
|
||||
|
||||
in vec2 pos; // four corners of point ([0,0], [0,1], [1,1], [1,0])
|
||||
|
||||
noperspective out vec2 vpos; // position scaled by screensize
|
||||
|
||||
void main() {
|
||||
float radius_border = options.radius_border.x + options.radius_border.y;
|
||||
vec2 p = options.center.xy + (pos - vec2(0.5, 0.5)) * radius_border;
|
||||
gl_Position = options.mvpmatrix * vec4(p, 0.0, 1.0);
|
||||
vpos = gl_Position.xy * options.screensize.xy; // just p?
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// fragment shader
|
||||
|
||||
noperspective in vec2 vpos;
|
||||
|
||||
out vec4 outColor;
|
||||
|
||||
vec4 blender_srgb_to_framebuffer_space(vec4 in_color)
|
||||
{
|
||||
if (srgbTarget) {
|
||||
vec3 c = max(in_color.rgb, vec3(0.0));
|
||||
vec3 c1 = c * (1.0 / 12.92);
|
||||
vec3 c2 = pow((c + 0.055) * (1.0 / 1.055), vec3(2.4));
|
||||
in_color.rgb = mix(c1, c2, step(vec3(0.04045), c));
|
||||
}
|
||||
return in_color;
|
||||
}
|
||||
|
||||
void main() {
|
||||
float radius_border = options.radius_border.x + options.radius_border.y;
|
||||
vec4 colorb = options.colorBorder;
|
||||
if(colorb.a < (1.0/255.0)) colorb.rgb = options.color.rgb;
|
||||
vec2 ctr = (options.mvpmatrix * vec4(options.center.xy, 0.0, 1.0)).xy;
|
||||
float d = distance(vpos, ctr.xy * options.screensize.xy);
|
||||
if(d > radius_border) { discard; return; }
|
||||
if(d <= options.radius_border.x) {
|
||||
float d2 = options.radius_border.x - d;
|
||||
outColor = mix(colorb, options.color, clamp(d2 - options.radius_border.y/2.0, 0.0, 1.0));
|
||||
} else {
|
||||
float d2 = d - options.radius_border.x;
|
||||
outColor = mix(colorb, vec4(colorb.rgb,0), clamp(d2 - options.radius_border.y/2.0, 0.0, 1.0));
|
||||
}
|
||||
// https://wiki.blender.org/wiki/Reference/Release_Notes/2.83/Python_API
|
||||
outColor = blender_srgb_to_framebuffer_space(outColor);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
Copyright (C) 2023 CG Cookie
|
||||
http://cgcookie.com
|
||||
hello@cgcookie.com
|
||||
|
||||
Created by Jonathan Denning
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
struct Options {
|
||||
mat4 MVPMatrix; // pixel matrix
|
||||
vec4 pos0;
|
||||
vec4 color0;
|
||||
vec4 pos1;
|
||||
vec4 color1;
|
||||
vec4 pos2;
|
||||
vec4 color2;
|
||||
};
|
||||
|
||||
uniform Options options;
|
||||
|
||||
const bool srgbTarget = true;
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// vertex shader
|
||||
|
||||
in vec2 pos; // x: [0,1], alpha. y: [0,1], beta
|
||||
|
||||
out vec4 color;
|
||||
|
||||
void main() {
|
||||
float a = clamp(pos.x, 0.0, 1.0);
|
||||
float b = clamp(pos.y, 0.0, 1.0);
|
||||
float c = 1.0 - a - b;
|
||||
vec2 p = (options.pos0 * a + options.pos1 * b + options.pos2 * c).xy;
|
||||
gl_Position = options.MVPMatrix * vec4(p, 0.0, 1.0);
|
||||
color = options.color0 * a + options.color1 * b + options.color2 * c;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// fragment shader
|
||||
|
||||
in vec4 color;
|
||||
|
||||
out vec4 outColor;
|
||||
|
||||
vec4 blender_srgb_to_framebuffer_space(vec4 in_color)
|
||||
{
|
||||
if (srgbTarget) {
|
||||
vec3 c = max(in_color.rgb, vec3(0.0));
|
||||
vec3 c1 = c * (1.0 / 12.92);
|
||||
vec3 c2 = pow((c + 0.055) * (1.0 / 1.055), vec3(2.4));
|
||||
in_color.rgb = mix(c1, c2, step(vec3(0.04045), c));
|
||||
}
|
||||
return in_color;
|
||||
}
|
||||
|
||||
void main() {
|
||||
outColor = color;
|
||||
// https://wiki.blender.org/wiki/Reference/Release_Notes/2.83/Python_API
|
||||
outColor = blender_srgb_to_framebuffer_space(outColor);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
Copyright (C) 2023 CG Cookie
|
||||
http://cgcookie.com
|
||||
hello@cgcookie.com
|
||||
|
||||
Created by Jonathan Denning
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
struct Options {
|
||||
mat4 MVPMatrix; // view matrix
|
||||
vec4 pos0;
|
||||
vec4 color0;
|
||||
vec4 pos1;
|
||||
vec4 color1;
|
||||
vec4 pos2;
|
||||
vec4 color2;
|
||||
};
|
||||
|
||||
uniform Options options;
|
||||
|
||||
const bool srgbTarget = true;
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// vertex shader
|
||||
|
||||
in vec2 pos; // x: [0,1], alpha. y: [0,1], beta
|
||||
|
||||
out vec4 color;
|
||||
|
||||
void main() {
|
||||
float a = clamp(pos.x, 0.0, 1.0);
|
||||
float b = clamp(pos.y, 0.0, 1.0);
|
||||
float c = 1.0 - a - b;
|
||||
vec3 p = vec3(options.pos0) * a + vec3(options.pos1) * b + vec3(options.pos2) * c;
|
||||
gl_Position = options.MVPMatrix * vec4(p, 1.0);
|
||||
color = options.color0 * a + options.color1 * b + options.color2 * c;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// fragment shader
|
||||
|
||||
in vec4 color;
|
||||
|
||||
out vec4 outColor;
|
||||
|
||||
vec4 blender_srgb_to_framebuffer_space(vec4 in_color)
|
||||
{
|
||||
if (srgbTarget) {
|
||||
vec3 c = max(in_color.rgb, vec3(0.0));
|
||||
vec3 c1 = c * (1.0 / 12.92);
|
||||
vec3 c2 = pow((c + 0.055) * (1.0 / 1.055), vec3(2.4));
|
||||
in_color.rgb = mix(c1, c2, step(vec3(0.04045), c));
|
||||
}
|
||||
return in_color;
|
||||
}
|
||||
|
||||
|
||||
void main() {
|
||||
outColor = color;
|
||||
// https://wiki.blender.org/wiki/Reference/Release_Notes/2.83/Python_API
|
||||
outColor = blender_srgb_to_framebuffer_space(outColor);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,440 @@
|
||||
/*
|
||||
Copyright (C) 2023 CG Cookie
|
||||
http://cgcookie.com
|
||||
hello@cgcookie.com
|
||||
|
||||
Created by Jonathan Denning
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#version 330
|
||||
|
||||
// // the following two lines are an attempt to solve issues #1025, #879, #753
|
||||
// precision mediump float;
|
||||
// precision lowp int; // only used to represent enum or bool
|
||||
|
||||
struct Options {
|
||||
mat4 uMVPMatrix;
|
||||
|
||||
vec4 lrtb;
|
||||
vec4 wh;
|
||||
|
||||
vec4 depth;
|
||||
|
||||
vec4 margin_lrtb;
|
||||
vec4 padding_lrtb;
|
||||
|
||||
vec4 border_width_radius;
|
||||
vec4 border_left_color;
|
||||
vec4 border_right_color;
|
||||
vec4 border_top_color;
|
||||
vec4 border_bottom_color;
|
||||
|
||||
vec4 background_color;
|
||||
|
||||
// see IMAGE_SCALE_XXX values below
|
||||
ivec4 image_settings;
|
||||
};
|
||||
|
||||
uniform Options options;
|
||||
uniform sampler2D image;
|
||||
|
||||
|
||||
const bool srgbTarget = true;
|
||||
|
||||
bool image_use() { return options.image_settings[0] != 0; }
|
||||
int image_fit() { return options.image_settings[1]; }
|
||||
|
||||
float pos_l() { return options.lrtb[0]; }
|
||||
float pos_r() { return options.lrtb[1]; }
|
||||
float pos_t() { return options.lrtb[2]; }
|
||||
float pos_b() { return options.lrtb[3]; }
|
||||
|
||||
float size_w() { return options.wh[0]; }
|
||||
float size_h() { return options.wh[1]; }
|
||||
|
||||
float depth() { return options.depth[0]; }
|
||||
|
||||
float margin_l() { return options.margin_lrtb[0]; }
|
||||
float margin_r() { return options.margin_lrtb[1]; }
|
||||
float margin_t() { return options.margin_lrtb[2]; }
|
||||
float margin_b() { return options.margin_lrtb[3]; }
|
||||
float padding_l() { return options.padding_lrtb[0]; }
|
||||
float padding_r() { return options.padding_lrtb[1]; }
|
||||
float padding_t() { return options.padding_lrtb[2]; }
|
||||
float padding_b() { return options.padding_lrtb[3]; }
|
||||
|
||||
float border_width() { return options.border_width_radius[0]; }
|
||||
float border_radius() { return options.border_width_radius[1]; }
|
||||
vec4 border_left_color() { return options.border_left_color; }
|
||||
vec4 border_right_color() { return options.border_right_color; }
|
||||
vec4 border_top_color() { return options.border_top_color; }
|
||||
vec4 border_bottom_color() { return options.border_bottom_color; }
|
||||
|
||||
vec4 background_color() { return options.background_color; }
|
||||
|
||||
|
||||
////////////////////////////////////////
|
||||
// vertex shader
|
||||
|
||||
in vec2 pos;
|
||||
|
||||
out vec2 screen_pos;
|
||||
|
||||
void main() {
|
||||
// set vertex to bottom-left, top-left, top-right, or bottom-right location, depending on pos
|
||||
vec2 p = vec2(
|
||||
(pos.x < 0.5) ? (pos_l() - 1.0) : (pos_r() + 1.0),
|
||||
(pos.y < 0.5) ? (pos_b() - 1.0) : (pos_t() + 1.0)
|
||||
);
|
||||
|
||||
// convert depth to z-order
|
||||
float zorder = 1.0 - depth() / 1000.0;
|
||||
|
||||
screen_pos = p;
|
||||
gl_Position = options.uMVPMatrix * vec4(p, zorder, 1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////
|
||||
// fragment shader
|
||||
|
||||
in vec2 screen_pos;
|
||||
|
||||
out vec4 outColor;
|
||||
out float gl_FragDepth;
|
||||
|
||||
float sqr(float s) { return s * s; }
|
||||
float sumsqr(float a, float b) { return sqr(a) + sqr(b); }
|
||||
float min4(float a, float b, float c, float d) { return min(min(min(a, b), c) ,d); }
|
||||
|
||||
vec4 mix_over(vec4 above, vec4 below) {
|
||||
vec3 a_ = above.rgb * above.a;
|
||||
vec3 b_ = below.rgb * below.a;
|
||||
float alpha = above.a + (1.0 - above.a) * below.a;
|
||||
return vec4((a_ + b_ * (1.0 - above.a)) / alpha, alpha);
|
||||
}
|
||||
|
||||
int get_margin_region(float dist_left, float dist_right, float dist_top, float dist_bottom) {
|
||||
float dist_min = min4(dist_left, dist_right, dist_top, dist_bottom);
|
||||
if(dist_min == dist_left) return REGION_MARGIN_LEFT;
|
||||
if(dist_min == dist_right) return REGION_MARGIN_RIGHT;
|
||||
if(dist_min == dist_top) return REGION_MARGIN_TOP;
|
||||
if(dist_min == dist_bottom) return REGION_MARGIN_BOTTOM;
|
||||
return REGION_ERROR; // this should never happen
|
||||
}
|
||||
|
||||
int get_region() {
|
||||
/* this function determines which region the fragment is in wrt properties of UI element,
|
||||
specifically: position, size, border width, border radius, margins
|
||||
|
||||
v top-left
|
||||
+-----------------+
|
||||
| \ / | <- margin regions
|
||||
| +---------+ |
|
||||
| |\ /| | <- border regions
|
||||
| | +-----+ | |
|
||||
| | | | | | <- inside border region (content area + padding)
|
||||
| | +-----+ | |
|
||||
| |/ \| |
|
||||
| +---------+ |
|
||||
| / \ |
|
||||
+-----------------+
|
||||
^ bottom-right
|
||||
|
||||
- margin regions
|
||||
- broken into top, right, bottom, left
|
||||
- each TRBL margin size can be different size
|
||||
- border regions
|
||||
- broken into top, right, bottom, left
|
||||
- each can have different colors, but all same size (TODO!)
|
||||
- inside border region
|
||||
- where content is drawn (image)
|
||||
- NOTE: padding takes up this space
|
||||
- ERROR region _should_ never happen, but can be returned from this fn if something goes wrong
|
||||
*/
|
||||
|
||||
float dist_left = screen_pos.x - (pos_l() + margin_l());
|
||||
float dist_right = (pos_r() - margin_r() + 1.0) - screen_pos.x;
|
||||
float dist_bottom = screen_pos.y - (pos_b() + margin_b() - 1.0);
|
||||
float dist_top = (pos_t() - margin_t()) - screen_pos.y;
|
||||
float radwid = max(border_radius(), border_width());
|
||||
float rad = max(0.0, border_radius() - border_width());
|
||||
float radwid2 = sqr(radwid);
|
||||
float rad2 = sqr(rad);
|
||||
|
||||
if(dist_left < 0 || dist_right < 0 || dist_top < 0 || dist_bottom < 0) return REGION_OUTSIDE;
|
||||
|
||||
// margin
|
||||
int margin_region = get_margin_region(dist_left, dist_right, dist_top, dist_bottom);
|
||||
|
||||
// within top and bottom, might be left or right side
|
||||
if(dist_bottom > radwid && dist_top > radwid) {
|
||||
if(dist_left > border_width() && dist_right > border_width()) return REGION_BACKGROUND;
|
||||
if(dist_left < dist_right) return REGION_BORDER_LEFT;
|
||||
return REGION_BORDER_RIGHT;
|
||||
}
|
||||
|
||||
// within left and right, might be bottom or top
|
||||
if(dist_left > radwid && dist_right > radwid) {
|
||||
if(dist_bottom > border_width() && dist_top > border_width()) return REGION_BACKGROUND;
|
||||
if(dist_bottom < dist_top) return REGION_BORDER_BOTTOM;
|
||||
return REGION_BORDER_TOP;
|
||||
}
|
||||
|
||||
// top-left
|
||||
if(dist_top <= radwid && dist_left <= radwid) {
|
||||
float r2 = sumsqr(dist_left - radwid, dist_top - radwid);
|
||||
if(r2 > radwid2) return margin_region;
|
||||
if(r2 < rad2) return REGION_BACKGROUND;
|
||||
if(dist_left < dist_top) return REGION_BORDER_LEFT;
|
||||
return REGION_BORDER_TOP;
|
||||
}
|
||||
// top-right
|
||||
if(dist_top <= radwid && dist_right <= radwid) {
|
||||
float r2 = sumsqr(dist_right - radwid, dist_top - radwid);
|
||||
if(r2 > radwid2) return margin_region;
|
||||
if(r2 < rad2) return REGION_BACKGROUND;
|
||||
if(dist_right < dist_top) return REGION_BORDER_RIGHT;
|
||||
return REGION_BORDER_TOP;
|
||||
}
|
||||
// bottom-left
|
||||
if(dist_bottom <= radwid && dist_left <= radwid) {
|
||||
float r2 = sumsqr(dist_left - radwid, dist_bottom - radwid);
|
||||
if(r2 > radwid2) return margin_region;
|
||||
if(r2 < rad2) return REGION_BACKGROUND;
|
||||
if(dist_left < dist_bottom) return REGION_BORDER_LEFT;
|
||||
return REGION_BORDER_BOTTOM;
|
||||
}
|
||||
// bottom-right
|
||||
if(dist_bottom <= radwid && dist_right <= radwid) {
|
||||
float r2 = sumsqr(dist_right - radwid, dist_bottom - radwid);
|
||||
if(r2 > radwid2) return margin_region;
|
||||
if(r2 < rad2) return REGION_BACKGROUND;
|
||||
if(dist_right < dist_bottom) return REGION_BORDER_RIGHT;
|
||||
return REGION_BORDER_BOTTOM;
|
||||
}
|
||||
|
||||
// something bad happened
|
||||
return REGION_ERROR;
|
||||
}
|
||||
|
||||
vec4 mix_image(vec4 bg) {
|
||||
vec4 c = bg;
|
||||
// drawing space
|
||||
float dw = size_w() - (margin_l() + border_width() + padding_l() + padding_r() + border_width() + margin_r());
|
||||
float dh = size_h() - (margin_t() + border_width() + padding_t() + padding_b() + border_width() + margin_b());
|
||||
float dx = screen_pos.x - (pos_l() + (margin_l() + border_width() + padding_l()));
|
||||
float dy = -(screen_pos.y - (pos_t() - (margin_t() + border_width() + padding_t())));
|
||||
float dsx = (dx + 0.5) / dw;
|
||||
float dsy = (dy + 0.5) / dh;
|
||||
// texture
|
||||
vec2 tsz = vec2(textureSize(image, 0));
|
||||
float tw = tsz.x, th = tsz.y;
|
||||
float tx, ty;
|
||||
|
||||
switch(image_fit()) {
|
||||
case IMAGE_SCALE_FILL:
|
||||
// object-fit: fill = stretch / squash to fill entire drawing space (non-uniform scale)
|
||||
// do nothing here
|
||||
tx = tw * dx / dw;
|
||||
ty = th * dy / dh;
|
||||
break;
|
||||
case IMAGE_SCALE_CONTAIN: {
|
||||
// object-fit: contain = uniformly scale texture to fit entirely in drawing space (will be letterboxed)
|
||||
// find smaller scaled dimension, and use that
|
||||
float _tw, _th;
|
||||
if(dw / dh < tw / th) {
|
||||
// scaling by height is too big, so scale by width
|
||||
_tw = tw;
|
||||
_th = tw * dh / dw;
|
||||
} else {
|
||||
_tw = th * dw / dh;
|
||||
_th = th;
|
||||
}
|
||||
tx = dsx * _tw - (_tw - tw) / 2.0;
|
||||
ty = dsy * _th - (_th - th) / 2.0;
|
||||
break; }
|
||||
case IMAGE_SCALE_COVER: {
|
||||
// object-fit: cover = uniformly scale texture to fill entire drawing space (will be cropped)
|
||||
// find larger scaled dimension, and use that
|
||||
float _tw, _th;
|
||||
if(dw / dh > tw / th) {
|
||||
// scaling by height is too big, so scale by width
|
||||
_tw = tw;
|
||||
_th = tw * dh / dw;
|
||||
} else {
|
||||
_tw = th * dw / dh;
|
||||
_th = th;
|
||||
}
|
||||
tx = dsx * _tw - (_tw - tw) / 2.0;
|
||||
ty = dsy * _th - (_th - th) / 2.0;
|
||||
break; }
|
||||
case IMAGE_SCALE_DOWN:
|
||||
// object-fit: scale-down = either none or contain, whichever is smaller
|
||||
if(dw >= tw && dh >= th) {
|
||||
// none
|
||||
tx = dx + (tw - dw) / 2.0;
|
||||
ty = dy + (th - dh) / 2.0;
|
||||
} else {
|
||||
float _tw, _th;
|
||||
if(dw / dh < tw / th) {
|
||||
// scaling by height is too big, so scale by width
|
||||
_tw = tw;
|
||||
_th = tw * dh / dw;
|
||||
} else {
|
||||
_tw = th * dw / dh;
|
||||
_th = th;
|
||||
}
|
||||
tx = dsx * _tw - (_tw - tw) / 2.0;
|
||||
ty = dsy * _th - (_th - th) / 2.0;
|
||||
}
|
||||
break;
|
||||
case IMAGE_SCALE_NONE:
|
||||
// object-fit: none (no resizing)
|
||||
tx = dx + (tw - dw) / 2.0;
|
||||
ty = dy + (th - dh) / 2.0;
|
||||
break;
|
||||
default: // error!
|
||||
tx = tw / 2.0;
|
||||
ty = th / 2.0;
|
||||
break;
|
||||
}
|
||||
|
||||
vec2 texcoord = vec2(tx / tw, 1 - ty / th);
|
||||
bool inside = 0.0 <= texcoord.x && texcoord.x <= 1.0 && 0.0 <= texcoord.y && texcoord.y <= 1.0;
|
||||
if(inside) {
|
||||
vec4 t = texture(image, texcoord) + COLOR_DEBUG_IMAGE;
|
||||
c = mix_over(t, c);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_IMAGE_CHECKER
|
||||
if(inside) {
|
||||
// generate checker pattern to test scaling
|
||||
switch((int(32.0 * texcoord.x) + 4 * int(32.0 * texcoord.y)) % 16) {
|
||||
case 0: c = COLOR_CHECKER_00; break;
|
||||
case 1: c = COLOR_CHECKER_01; break;
|
||||
case 2: c = COLOR_CHECKER_02; break;
|
||||
case 3: c = COLOR_CHECKER_03; break;
|
||||
case 4: c = COLOR_CHECKER_04; break;
|
||||
case 5: c = COLOR_CHECKER_05; break;
|
||||
case 6: c = COLOR_CHECKER_06; break;
|
||||
case 7: c = COLOR_CHECKER_07; break;
|
||||
case 8: c = COLOR_CHECKER_08; break;
|
||||
case 9: c = COLOR_CHECKER_09; break;
|
||||
case 10: c = COLOR_CHECKER_10; break;
|
||||
case 11: c = COLOR_CHECKER_11; break;
|
||||
case 12: c = COLOR_CHECKER_12; break;
|
||||
case 13: c = COLOR_CHECKER_13; break;
|
||||
case 14: c = COLOR_CHECKER_14; break;
|
||||
case 15: c = COLOR_CHECKER_15; break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_IMAGE_OUTSIDE
|
||||
if(!inside) {
|
||||
c = vec4(
|
||||
1.0 - (1.0 - c.r) * 0.5,
|
||||
1.0 - (1.0 - c.g) * 0.5,
|
||||
1.0 - (1.0 - c.b) * 0.5,
|
||||
c.a
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
vec4 blender_srgb_to_framebuffer_space(vec4 in_color)
|
||||
{
|
||||
if (srgbTarget) {
|
||||
vec3 c = max(in_color.rgb, vec3(0.0));
|
||||
vec3 c1 = c * (1.0 / 12.92);
|
||||
vec3 c2 = pow((c + 0.055) * (1.0 / 1.055), vec3(2.4));
|
||||
in_color.rgb = mix(c1, c2, step(vec3(0.04045), c));
|
||||
}
|
||||
return in_color;
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec4 c = vec4(0,0,0,0);
|
||||
|
||||
int region = get_region();
|
||||
|
||||
// workaround switched-discard (issue #1042)
|
||||
#ifndef DEBUG_DONT_DISCARD
|
||||
#ifndef DEBUG_COLOR_REGIONS
|
||||
#ifndef DEBUG_COLOR_MARGINS
|
||||
if(region == REGION_MARGIN_TOP) { discard; return; }
|
||||
if(region == REGION_MARGIN_RIGHT) { discard; return; }
|
||||
if(region == REGION_MARGIN_BOTTOM) { discard; return; }
|
||||
if(region == REGION_MARGIN_LEFT) { discard; return; }
|
||||
#endif
|
||||
if(region == REGION_OUTSIDE) { discard; return; }
|
||||
#endif
|
||||
#endif
|
||||
|
||||
switch(region) {
|
||||
case REGION_BORDER_TOP: c = border_top_color(); break;
|
||||
case REGION_BORDER_RIGHT: c = border_right_color(); break;
|
||||
case REGION_BORDER_BOTTOM: c = border_bottom_color(); break;
|
||||
case REGION_BORDER_LEFT: c = border_left_color(); break;
|
||||
case REGION_BACKGROUND: c = background_color(); break;
|
||||
|
||||
// following colors show only if DEBUG settings allow or something really unexpected happens
|
||||
case REGION_MARGIN_TOP: c = COLOR_MARGIN_TOP; break;
|
||||
case REGION_MARGIN_RIGHT: c = COLOR_MARGIN_RIGHT; break;
|
||||
case REGION_MARGIN_BOTTOM: c = COLOR_MARGIN_BOTTOM; break;
|
||||
case REGION_MARGIN_LEFT: c = COLOR_MARGIN_LEFT; break;
|
||||
case REGION_OUTSIDE: c = COLOR_OUTSIDE; break; // keep transparent
|
||||
case REGION_ERROR: c = COLOR_ERROR; break; // should never hit here
|
||||
default: c = COLOR_ERROR_NEVER; // should **really** never hit here
|
||||
}
|
||||
|
||||
// DEBUG_COLOR_REGIONS will mix over other colors
|
||||
#ifdef DEBUG_COLOR_REGIONS
|
||||
switch(region) {
|
||||
case REGION_BORDER_TOP: c = mix_over(COLOR_BORDER_TOP, c); break;
|
||||
case REGION_BORDER_RIGHT: c = mix_over(COLOR_BORDER_RIGHT, c); break;
|
||||
case REGION_BORDER_BOTTOM: c = mix_over(COLOR_BORDER_BOTTOM, c); break;
|
||||
case REGION_BORDER_LEFT: c = mix_over(COLOR_BORDER_LEFT, c); break;
|
||||
case REGION_BACKGROUND: c = mix_over(COLOR_BACKGROUND, c); break;
|
||||
}
|
||||
#endif
|
||||
|
||||
// apply image if used
|
||||
if(image_use()) c = mix_image(c);
|
||||
|
||||
c = vec4(c.rgb * c.a, c.a);
|
||||
|
||||
// https://wiki.blender.org/wiki/Reference/Release_Notes/2.83/Python_API
|
||||
c = blender_srgb_to_framebuffer_space(c);
|
||||
|
||||
#ifdef DEBUG_SNAP_ALPHA
|
||||
if(c.a < 0.25) {
|
||||
c.a = 0.0;
|
||||
#ifndef DEBUG_DONT_DISCARD
|
||||
discard; return;
|
||||
#endif
|
||||
}
|
||||
else c.a = 1.0;
|
||||
#endif
|
||||
|
||||
outColor = c;
|
||||
//gl_FragDepth = gl_FragDepth * 0.999999;
|
||||
gl_FragDepth = gl_FragCoord.z * 0.999999; // fix for issue #915?
|
||||
}
|
||||
Reference in New Issue
Block a user