1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
pub mod glyph_cs { vulkano_shaders::shader!{ ty: "compute", src: " #version 450 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; layout(set = 0, binding = 0) readonly buffer SampleData { highp vec4 offset[]; } samples; layout(set = 0, binding = 1) readonly buffer RayData { highp vec4 direction[]; } rays; layout(set = 0, binding = 2) readonly buffer LineData { highp vec4 point[]; } lines; layout(set = 0, binding = 3) buffer BitmapData { highp float data[]; } bitmap; layout(set = 0, binding = 4) readonly buffer GlyphData { uint samples; uint rays; uint lines; highp float scaler; uint width; uint height; highp vec4 bounds; highp vec2 offset; } glyph; bool ray_intersects(highp vec2 l1p1, highp vec2 l1p2, highp vec2 l2p1, highp vec2 l2p2, out highp vec2 point) { highp vec2 r = l1p2 - l1p1; highp vec2 s = l2p2 - l2p1; highp float det = r.x * s.y - r.y * s.x; highp float u = ((l2p1.x - l1p1.x) * r.y - (l2p1.y - l1p1.y) * r.x) / det; highp float t = ((l2p1.x - l1p1.x) * s.y - (l2p1.y - l1p1.y) * s.x) / det; if ((t >= 0. && t <= 1.) && (u >= 0. && u <= 1.)) { point = l1p1 + r * t; return true; } else { return false; } } bool sample_filled(highp vec2 ray_src, highp float ray_len, out highp float fill_amt) { int least_hits = -1; bool intersects = false; highp float ray_min_dist_sum = 0.0; highp vec2 intersect_point = vec2(0.0); for(uint ray_dir_i = 0; ray_dir_i < glyph.rays; ray_dir_i++) { int hits = 0; highp vec2 ray_dest = ray_src + (rays.direction[ray_dir_i].xy * ray_len); highp float cell_height = (glyph.scaler / sqrt(glyph.samples)); highp float cell_width = cell_height / 3.0; highp float ray_angle = atan(rays.direction[ray_dir_i].y / rays.direction[ray_dir_i].x); highp float ray_max_dist = (cell_width / 2.0) / cos(ray_angle); if(ray_max_dist > (cell_height / 2.0)) { ray_max_dist = (cell_height / 2.0) / cos(1.570796327 - ray_angle); } highp float ray_min_dist = ray_max_dist; for(uint line_i = 0; line_i < glyph.lines; line_i ++) { if(ray_intersects(ray_src, ray_dest, lines.point[line_i].xy, lines.point[line_i].zw, intersect_point)) { highp float dist = distance(ray_src, intersect_point); if(dist < ray_min_dist) { ray_min_dist = dist; } hits++; } } ray_min_dist_sum += ray_min_dist / ray_max_dist; if(least_hits == -1 || hits < least_hits) { least_hits = hits; } } fill_amt = ray_min_dist_sum / float(glyph.rays); return least_hits % 2 != 0; } highp vec2 transform_coords(uint offset_i, vec2 offset) { highp vec2 coords = vec2(float(gl_GlobalInvocationID.x), float(gl_GlobalInvocationID.y) * -1.0); coords -= glyph.offset; // Apply the pixel offset for sampling coords += samples.offset[offset_i].xy; coords += offset; // Convert to font units coords /= glyph.scaler; // Bearing adjustment coords += vec2(glyph.bounds.x, glyph.bounds.w); return coords; } highp float get_value(highp vec2 offset, highp float ray_len) { highp float fill_amt = 0.0; highp float fill_amt_sum = 0.0; for(uint i = 0; i < glyph.samples; i++) { if(sample_filled(transform_coords(i, offset), ray_len, fill_amt)) { fill_amt_sum += fill_amt; } } return pow(fill_amt_sum / float(glyph.samples), 1.2); } void main() { highp float ray_len = sqrt( pow(float(glyph.width) / glyph.scaler, 2) + pow(float(glyph.height) / glyph.scaler, 2) ); uint rindex = ((gl_GlobalInvocationID.y * glyph.width) + gl_GlobalInvocationID.x) * 4; bitmap.data[rindex] = get_value(vec2(1.0 / 6.0, 0.0), ray_len); bitmap.data[rindex + 1] = get_value(vec2(3.0 / 6.0, 0.0), ray_len); bitmap.data[rindex + 2] = get_value(vec2(5.0 / 6.0, 0.0), ray_len); bitmap.data[rindex + 3] = (bitmap.data[rindex] + bitmap.data[rindex + 1] + bitmap.data[rindex + 2]) / 3.0; } "} }