| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230 |
- shader_type canvas_item;
- const float line_width = 1.0f;
- const float interval_step[8] = float[8](10.0, 50.0, 100.0, 200.0, 500.0, 1000.0, 5000.0, 10000.0);
- // 标尺参数
- uniform bool is_horizontal;
- uniform vec2 ruler_size;
- uniform vec4 ruler_range;
- uniform vec4 highlight_range;
- uniform vec2 mouse_pos;
- uniform vec4 mouse_line_color : source_color = vec4(0.5, 0.5, 0.5, 1.0);
- uniform vec4 line_color : source_color = vec4(0.5, 0.5, 0.5, 1.0);
- uniform vec4 highlight_color : source_color = vec4(0.5, 0.5, 0.5, 1.0);
- uniform vec4 bg_color : source_color = vec4(0.2, 0.2, 0.2, 1.0);
- varying vec2 pixel_pos;
- int quick_digit_count(int number) {
- int absNum = abs(number);
- int count = 0;
-
- if (absNum >= 100000) count = 6;
- else if (absNum >= 10000) count = 5;
- else if (absNum >= 1000) count = 4;
- else if (absNum >= 100) count = 3;
- else if (absNum >= 10) count = 2;
- else count = 1;
- if (number < 0) count++;
- return count;
- }
- // ###########################################################################
- // Printing numbers
- // Modify according to the https://www.shadertoy.com/view/XllSWl
- float DigitBin(const in int x) {
- return x==0?480599.0:x==1?139810.0:x==2?476951.0:x==3?476999.0:x==4?350020.0:x==5?464711.0:x==6?464727.0:x==7?476228.0:x==8?481111.0:x==9?481095.0:0.0;
- }
- float PrintValue(const in vec2 fragCoord, const in vec2 vPixelCoords, const in vec2 vFontSize, const in float fValue) {
- vec2 vStringCharCoords = (vec2(fragCoord.x, 1.0 - fragCoord.y).xy - vPixelCoords) / vFontSize;
- if ((vStringCharCoords.y < 0.0) || (vStringCharCoords.y >= 1.0)) return 0.0;
-
- float fLog10Value = log2(abs(fValue)) / log2(10.0);
- float fBiggestIndex = max(floor(fLog10Value), 0.0);
- float fDigitIndex = floor(vStringCharCoords.x);
- float fCharBin = 0.0;
- float fNumStartIndex = (fValue < 0.0) ? 1.0 : 0.0;
-
- if(fValue < 0.0 && fDigitIndex == 0.0) {
- fCharBin = 1792.0;
- }
- else if (fDigitIndex >= fNumStartIndex && fDigitIndex <= fBiggestIndex + fNumStartIndex) {
- float fActualDigitIndex = fBiggestIndex - (fDigitIndex - fNumStartIndex);
- float fDigitValue = abs(fValue / pow(10.0, fActualDigitIndex));
- fCharBin = DigitBin(int(floor(mod(0.0001 + fDigitValue, 10.0))));
- } else {
- return 0.0;
- }
- return floor(mod((fCharBin / pow(2.0, floor(fract(vStringCharCoords.x) * 4.0) + (floor(vStringCharCoords.y * 5.0) * 4.0))), 2.0));
- }
- // ###########################################################################
- float affine_transform(float x, float a, float b, float p, float q) {
- return p + (x - a) * (q - p) / (b - a);
- }
- float grid_align_floor(float x, int step_size) {
- return floor(x / float(step_size)) * float(step_size);
- }
- float interval_round(float input_value) {
- float closest = interval_step[0];
- for (int i = 1; i < 8; i++) {
- if (abs(input_value - interval_step[i]) < abs(input_value - closest)) {
- closest = interval_step[i];
- }
- }
- return closest;
- }
- int in_line(vec2 p1, vec2 p2, vec2 m) {
- vec2 v = p2 - p1, w = m - p1;
- float sq_len = dot(v, v);
- if (sq_len < 0.001) return length(w) <= line_width ? 0 : -1;
- float t = clamp(dot(w, v) / sq_len, 0.0, 1.0);
- return length(m - (p1 + t * v)) <= line_width ? 0 : -1;
- }
- float[21] get_mark_line_1(float min_value, float max_value, float interval) {
- float result[21];
- float pin = grid_align_floor(min_value - interval, int(interval));
- for(int i = 0; i < 21; i++) {
- result[i] = pin + interval * float(i);
- }
- return result;
- }
- float[20] get_mark_line_2(float[21] mark_line_1) {
- float result[20];
- for(int i = 0; i < 20; i++) {
- result[i] = (mark_line_1[i] + mark_line_1[i + 1]) / 2.0;
- }
- return result;
- }
- float[160] get_mark_line_3(float[21] mark_line_1, float[20] mark_line_2) {
- float mark_line[41];
- int i = 0, j = 0, k = 0;
- while (i < 21 && j < 20) {
- if (mark_line_1[i] < mark_line_2[j]) {
- mark_line[k++] = mark_line_1[i++];
- } else {
- mark_line[k++] = mark_line_2[j++];
- }
- }
- while (i < 21) mark_line[k++] = mark_line_1[i++];
- while (j < 20) mark_line[k++] = mark_line_2[j++];
-
-
- float result[160];
- for(int i = 0; i < 40; i++) {
- result[i * 4] = mark_line[i] + (mark_line[i + 1] - mark_line[i]) * 0.2;
- result[i * 4 + 1] = mark_line[i] + (mark_line[i + 1] - mark_line[i]) * 0.4;
- result[i * 4 + 2] = mark_line[i] + (mark_line[i + 1] - mark_line[i]) * 0.6;
- result[i * 4 + 3] = mark_line[i] + (mark_line[i + 1] - mark_line[i]) * 0.8;
- }
- return result;
- }
- int detect_ruler_pixel(vec2 pos) {
- // 选择坐标轴相关的参数
- float mouse_coord = is_horizontal ? mouse_pos.x : mouse_pos.y;
- float range_start = is_horizontal ? ruler_range.x : ruler_range.y;
- float range_end = is_horizontal ? ruler_range.z : ruler_range.w;
- float ruler_length = is_horizontal ? ruler_size.x : ruler_size.y;
- float highlight_start = is_horizontal ? highlight_range.x : highlight_range.y;
- float highlight_end = is_horizontal ? highlight_range.z : highlight_range.w;
-
- // 鼠标位置线检测
- float t = affine_transform(mouse_coord, range_start, range_end, 0.0, ruler_length);
- if (is_horizontal) {
- if (in_line(vec2(t, 0.0), vec2(t, ruler_size.y), pos) >= 0) return 2;
- } else {
- if (in_line(vec2(0.0, t), vec2(ruler_size.x, t), pos) >= 0) return 2;
- }
-
- // 标记线检测, 标线间隔根据横向范围决定
- float interval = interval_round(abs(ruler_range.z - ruler_range.x) / 7.0);
- float detect_mark1[21] = get_mark_line_1(range_start, range_end, interval);
-
- for (int i = 0; i < 21; i++) {
- // 主线检测
- t = affine_transform(detect_mark1[i], range_start, range_end, 0.0, ruler_length);
- if (is_horizontal) {
- if (in_line(vec2(t, 0.0), vec2(t, ruler_size.y), pos) >= 0) return 1;
- } else {
- if (in_line(vec2(0.0, t), vec2(ruler_size.x, t), pos) >= 0) return 1;
- }
-
- // 标签检测
- float fIsDigit1;
- if (is_horizontal) {
- vec2 vFontSize = vec2(8.0, 15.0);
- fIsDigit1 = PrintValue(pos, vec2(t + 4.0, -vFontSize.y - 2.0), vFontSize, detect_mark1[i]);
- } else {
- int d = quick_digit_count(int(detect_mark1[i]));
- vec2 vFontSize;
- if (d <= 3) vFontSize = vec2(8.0, 15.0);
- else if (d <= 5) vFontSize = vec2(6.0, 15.0);
- else vFontSize = vec2(5.0, 15.0);
- fIsDigit1 = PrintValue(pos, vec2(2.0, -t - vFontSize.y - 2.0), vFontSize, detect_mark1[i]);
-
- }
- if (fIsDigit1 > 0.0) return 1;
- }
-
- // 二级标记线
- float detect_mark2[20] = get_mark_line_2(detect_mark1);
- for (int i = 0; i < 20; i++) {
- if (detect_mark2[i] < range_start || detect_mark2[i] > range_end) continue;
-
- t = affine_transform(detect_mark2[i], range_start, range_end, 0.0, ruler_length);
- if (is_horizontal) {
- if (in_line(vec2(t, ruler_size.y * 0.5), vec2(t, ruler_size.y), pos) >= 0) return 1;
- } else {
- if (in_line(vec2(ruler_size.x * 0.5, t), vec2(ruler_size.x, t), pos) >= 0) return 1;
- }
- }
-
- // 三级标记线
- float detect_mark3[160] = get_mark_line_3(detect_mark1, detect_mark2);
- for (int i = 0; i < 160; i++) {
- if (detect_mark3[i] < range_start || detect_mark3[i] > range_end) continue;
-
- t = affine_transform(detect_mark3[i], range_start, range_end, 0.0, ruler_length);
- if (is_horizontal) {
- if (in_line(vec2(t, ruler_size.y * 0.75), vec2(t, ruler_size.y), pos) >= 0) return 1;
- } else {
- if (in_line(vec2(ruler_size.x * 0.75, t), vec2(ruler_size.x, t), pos) >= 0) return 1;
- }
- }
-
- // 高亮区域检测
- float coord = is_horizontal ? affine_transform(pos.x, 0.0, ruler_size.x, range_start, range_end)
- : affine_transform(pos.y, 0.0, ruler_size.y, range_start, range_end);
- if (highlight_start <= coord && coord <= highlight_end) return 0;
-
- // 背景
- return -1;
- }
- // ###########################################################################
- // ###########################################################################
- // ###########################################################################
- // ###########################################################################
- void vertex() {
- pixel_pos = (CANVAS_MATRIX * vec4(VERTEX, 0.0, 1.0)).xy;
- }
- void fragment() {
- int point_mode = detect_ruler_pixel(pixel_pos);
- if (point_mode == 2) COLOR = mouse_line_color;
- else if (point_mode == 1) COLOR = line_color;
- else if (point_mode == 0) COLOR = highlight_color;
- else COLOR = bg_color;
- }
|