#![warn(clippy::pedantic)]
#![crate_name = "cloth_bumpmap"]
#[cfg(test)]
mod tests {
use super::cloth_bumpmap;
#[test]
#[allow(clippy::too_many_lines)]
fn it_works() {
if let Some(x) = cloth_bumpmap(30, 30, true) {
let k = x.into_raw().into_iter();
let oracle = vec![
147, 147, 147, 99, 99, 99, 88, 88, 88, 157, 157, 157, 116, 116, 116, 45, 45, 45,
151, 151, 151, 97, 97, 97, 126, 126, 126, 125, 125, 125, 117, 117, 117, 92, 92, 92,
87, 87, 87, 123, 123, 123, 126, 126, 126, 117, 117, 117, 149, 149, 149, 140, 140,
140, 144, 144, 144, 169, 169, 169, 219, 219, 219, 215, 215, 215, 211, 211, 211,
157, 157, 157, 152, 152, 152, 178, 178, 178, 255, 255, 255, 197, 197, 197, 208,
208, 208, 232, 232, 232, 95, 95, 95, 77, 77, 77, 77, 77, 77, 131, 131, 131, 163,
163, 163, 155, 155, 155, 171, 171, 171, 142, 142, 142, 139, 139, 139, 83, 83, 83,
70, 70, 70, 48, 48, 48, 74, 74, 74, 71, 71, 71, 127, 127, 127, 111, 111, 111, 160,
160, 160, 126, 126, 126, 175, 175, 175, 114, 114, 114, 179, 179, 179, 194, 194,
194, 181, 181, 181, 223, 223, 223, 172, 172, 172, 247, 247, 247, 239, 239, 239,
213, 213, 213, 210, 210, 210, 157, 157, 157, 47, 47, 47, 134, 134, 134, 146, 146,
146, 138, 138, 138, 138, 138, 138, 150, 150, 150, 112, 112, 112, 125, 125, 125,
141, 141, 141, 128, 128, 128, 101, 101, 101, 55, 55, 55, 75, 75, 75, 114, 114, 114,
140, 140, 140, 121, 121, 121, 135, 135, 135, 135, 135, 135, 113, 113, 113, 199,
199, 199, 141, 141, 141, 200, 200, 200, 150, 150, 150, 138, 138, 138, 136, 136,
136, 193, 193, 193, 190, 190, 190, 217, 217, 217, 160, 160, 160, 203, 203, 203,
117, 117, 117, 103, 103, 103, 122, 122, 122, 98, 98, 98, 90, 90, 90, 170, 170, 170,
102, 102, 102, 137, 137, 137, 125, 125, 125, 57, 57, 57, 77, 77, 77, 65, 65, 65,
19, 19, 19, 91, 91, 91, 92, 92, 92, 71, 71, 71, 105, 105, 105, 147, 147, 147, 82,
82, 82, 153, 153, 153, 143, 143, 143, 190, 190, 190, 142, 142, 142, 106, 106, 106,
119, 119, 119, 188, 188, 188, 200, 200, 200, 235, 235, 235, 123, 123, 123, 192,
192, 192, 82, 82, 82, 103, 103, 103, 114, 114, 114, 121, 121, 121, 160, 160, 160,
70, 70, 70, 140, 140, 140, 78, 78, 78, 86, 86, 86, 101, 101, 101, 62, 62, 62, 76,
76, 76, 66, 66, 66, 66, 66, 66, 79, 79, 79, 71, 71, 71, 96, 96, 96, 112, 112, 112,
142, 142, 142, 83, 83, 83, 161, 161, 161, 195, 195, 195, 156, 156, 156, 125, 125,
125, 90, 90, 90, 144, 144, 144, 169, 169, 169, 148, 148, 148, 200, 200, 200, 173,
173, 173, 55, 55, 55, 101, 101, 101, 206, 206, 206, 114, 114, 114, 115, 115, 115,
129, 129, 129, 155, 155, 155, 58, 58, 58, 148, 148, 148, 165, 165, 165, 43, 43, 43,
61, 61, 61, 40, 40, 40, 100, 100, 100, 133, 133, 133, 48, 48, 48, 102, 102, 102,
129, 129, 129, 97, 97, 97, 120, 120, 120, 175, 175, 175, 139, 139, 139, 156, 156,
156, 162, 162, 162, 176, 176, 176, 196, 196, 196, 177, 177, 177, 215, 215, 215,
159, 159, 159, 171, 171, 171, 136, 136, 136, 82, 82, 82, 151, 151, 151, 167, 167,
167, 116, 116, 116, 120, 120, 120, 157, 157, 157, 163, 163, 163, 108, 108, 108,
113, 113, 113, 104, 104, 104, 120, 120, 120, 105, 105, 105, 87, 87, 87, 91, 91, 91,
151, 151, 151, 133, 133, 133, 121, 121, 121, 111, 111, 111, 154, 154, 154, 166,
166, 166, 159, 159, 159, 166, 166, 166, 159, 159, 159, 187, 187, 187, 170, 170,
170, 134, 134, 134, 217, 217, 217, 199, 199, 199, 143, 143, 143, 77, 77, 77, 145,
145, 145, 107, 107, 107, 132, 132, 132, 175, 175, 175, 104, 104, 104, 89, 89, 89,
110, 110, 110, 144, 144, 144, 162, 162, 162, 107, 107, 107, 119, 119, 119, 82, 82,
82, 69, 69, 69, 95, 95, 95, 118, 118, 118, 90, 90, 90, 149, 149, 149, 76, 76, 76,
143, 143, 143, 177, 177, 177, 153, 153, 153, 191, 191, 191, 182, 182, 182, 182,
182, 182, 139, 139, 139, 179, 179, 179, 175, 175, 175, 181, 181, 181, 179, 179,
179, 37, 37, 37, 69, 69, 69, 91, 91, 91, 121, 121, 121, 103, 103, 103, 77, 77, 77,
100, 100, 100, 100, 100, 100, 88, 88, 88, 74, 74, 74, 96, 96, 96, 88, 88, 88, 97,
97, 97, 100, 100, 100, 82, 82, 82, 109, 109, 109, 170, 170, 170, 116, 116, 116, 99,
99, 99, 165, 165, 165, 168, 168, 168, 173, 173, 173, 146, 146, 146, 230, 230, 230,
161, 161, 161, 172, 172, 172, 200, 200, 200, 193, 193, 193, 183, 183, 183, 202,
202, 202, 7, 7, 7, 95, 95, 95, 84, 84, 84, 88, 88, 88, 110, 110, 110, 98, 98, 98,
75, 75, 75, 146, 146, 146, 108, 108, 108, 99, 99, 99, 51, 51, 51, 71, 71, 71, 68,
68, 68, 58, 58, 58, 132, 132, 132, 105, 105, 105, 166, 166, 166, 65, 65, 65, 137,
137, 137, 136, 136, 136, 139, 139, 139, 124, 124, 124, 186, 186, 186, 135, 135,
135, 239, 239, 239, 167, 167, 167, 137, 137, 137, 159, 159, 159, 227, 227, 227,
216, 216, 216, 53, 53, 53, 112, 112, 112, 87, 87, 87, 144, 144, 144, 113, 113, 113,
79, 79, 79, 106, 106, 106, 107, 107, 107, 110, 110, 110, 81, 81, 81, 106, 106, 106,
141, 141, 141, 93, 93, 93, 88, 88, 88, 109, 109, 109, 123, 123, 123, 127, 127, 127,
133, 133, 133, 155, 155, 155, 183, 183, 183, 142, 142, 142, 171, 171, 171, 159,
159, 159, 215, 215, 215, 181, 181, 181, 208, 208, 208, 170, 170, 170, 178, 178,
178, 231, 231, 231, 182, 182, 182, 125, 125, 125, 135, 135, 135, 109, 109, 109,
156, 156, 156, 167, 167, 167, 125, 125, 125, 154, 154, 154, 147, 147, 147, 179,
179, 179, 143, 143, 143, 144, 144, 144, 133, 133, 133, 89, 89, 89, 93, 93, 93, 169,
169, 169, 107, 107, 107, 180, 180, 180, 143, 143, 143, 128, 128, 128, 166, 166,
166, 155, 155, 155, 160, 160, 160, 150, 150, 150, 194, 194, 194, 195, 195, 195,
203, 203, 203, 214, 214, 214, 222, 222, 222, 228, 228, 228, 245, 245, 245, 206,
206, 206, 150, 150, 150, 177, 177, 177, 134, 134, 134, 148, 148, 148, 132, 132,
132, 125, 125, 125, 134, 134, 134, 123, 123, 123, 158, 158, 158, 121, 121, 121,
115, 115, 115, 153, 153, 153, 133, 133, 133, 188, 188, 188, 194, 194, 194, 179,
179, 179, 142, 142, 142, 189, 189, 189, 205, 205, 205, 175, 175, 175, 171, 171,
171, 197, 197, 197, 209, 209, 209, 210, 210, 210, 187, 187, 187, 221, 221, 221,
215, 215, 215, 215, 215, 215, 214, 214, 214, 88, 88, 88, 109, 109, 109, 120, 120,
120, 166, 166, 166, 114, 114, 114, 141, 141, 141, 154, 154, 154, 165, 165, 165,
132, 132, 132, 134, 134, 134, 143, 143, 143, 124, 124, 124, 108, 108, 108, 140,
140, 140, 171, 171, 171, 145, 145, 145, 167, 167, 167, 171, 171, 171, 159, 159,
159, 156, 156, 156, 134, 134, 134, 199, 199, 199, 165, 165, 165, 246, 246, 246,
167, 167, 167, 234, 234, 234, 186, 186, 186, 228, 228, 228, 225, 225, 225, 176,
176, 176, 113, 113, 113, 194, 194, 194, 96, 96, 96, 146, 146, 146, 129, 129, 129,
181, 181, 181, 121, 121, 121, 172, 172, 172, 123, 123, 123, 124, 124, 124, 62, 62,
62, 102, 102, 102, 92, 92, 92, 163, 163, 163, 137, 137, 137, 205, 205, 205, 141,
141, 141, 177, 177, 177, 167, 167, 167, 116, 116, 116, 175, 175, 175, 171, 171,
171, 167, 167, 167, 239, 239, 239, 181, 181, 181, 252, 252, 252, 232, 232, 232,
213, 213, 213, 236, 236, 236, 255, 255, 255, 122, 122, 122, 143, 143, 143, 131,
131, 131, 161, 161, 161, 151, 151, 151, 108, 108, 108, 122, 122, 122, 163, 163,
163, 142, 142, 142, 117, 117, 117, 163, 163, 163, 178, 178, 178, 99, 99, 99, 129,
129, 129, 135, 135, 135, 169, 169, 169, 167, 167, 167, 174, 174, 174, 202, 202,
202, 157, 157, 157, 139, 139, 139, 182, 182, 182, 227, 227, 227, 193, 193, 193,
193, 193, 193, 220, 220, 220, 239, 239, 239, 219, 219, 219, 255, 255, 255, 255,
255, 255, 202, 202, 202, 174, 174, 174, 138, 138, 138, 150, 150, 150, 175, 175,
175, 152, 152, 152, 188, 188, 188, 131, 131, 131, 128, 128, 128, 174, 174, 174,
149, 149, 149, 165, 165, 165, 146, 146, 146, 172, 172, 172, 149, 149, 149, 189,
189, 189, 177, 177, 177, 198, 198, 198, 201, 201, 201, 184, 184, 184, 183, 183,
183, 229, 229, 229, 167, 167, 167, 199, 199, 199, 210, 210, 210, 201, 201, 201,
255, 255, 255, 218, 218, 218, 212, 212, 212, 239, 239, 239, 180, 180, 180, 181,
181, 181, 208, 208, 208, 187, 187, 187, 193, 193, 193, 135, 135, 135, 196, 196,
196, 129, 129, 129, 199, 199, 199, 208, 208, 208, 181, 181, 181, 165, 165, 165,
180, 180, 180, 140, 140, 140, 128, 128, 128, 207, 207, 207, 168, 168, 168, 133,
133, 133, 132, 132, 132, 170, 170, 170, 184, 184, 184, 169, 169, 169, 197, 197,
197, 181, 181, 181, 223, 223, 223, 181, 181, 181, 207, 207, 207, 184, 184, 184,
226, 226, 226, 239, 239, 239, 153, 153, 153, 202, 202, 202, 192, 192, 192, 193,
193, 193, 135, 135, 135, 142, 142, 142, 140, 140, 140, 141, 141, 141, 178, 178,
178, 165, 165, 165, 173, 173, 173, 176, 176, 176, 188, 188, 188, 159, 159, 159,
178, 178, 178, 207, 207, 207, 166, 166, 166, 171, 171, 171, 145, 145, 145, 139,
139, 139, 117, 117, 117, 138, 138, 138, 125, 125, 125, 204, 204, 204, 161, 161,
161, 178, 178, 178, 145, 145, 145, 147, 147, 147, 209, 209, 209, 201, 201, 201,
155, 155, 155, 123, 123, 123, 162, 162, 162, 125, 125, 125, 138, 138, 138, 88, 88,
88, 159, 159, 159, 159, 159, 159, 165, 165, 165, 129, 129, 129, 131, 131, 131, 200,
200, 200, 175, 175, 175, 174, 174, 174, 156, 156, 156, 176, 176, 176, 198, 198,
198, 158, 158, 158, 148, 148, 148, 81, 81, 81, 109, 109, 109, 130, 130, 130, 151,
151, 151, 119, 119, 119, 228, 228, 228, 159, 159, 159, 176, 176, 176, 179, 179,
179, 205, 205, 205, 198, 198, 198, 93, 93, 93, 74, 74, 74, 117, 117, 117, 65, 65,
65, 81, 81, 81, 63, 63, 63, 66, 66, 66, 23, 23, 23, 154, 154, 154, 110, 110, 110,
106, 106, 106, 95, 95, 95, 178, 178, 178, 145, 145, 145, 165, 165, 165, 197, 197,
197, 163, 163, 163, 114, 114, 114, 80, 80, 80, 52, 52, 52, 148, 148, 148, 122, 122,
122, 136, 136, 136, 146, 146, 146, 97, 97, 97, 141, 141, 141, 195, 195, 195, 197,
197, 197, 228, 228, 228, 194, 194, 194, 82, 82, 82, 47, 47, 47, 64, 64, 64, 15, 15,
15, 88, 88, 88, 74, 74, 74, 61, 61, 61, 108, 108, 108, 67, 67, 67, 73, 73, 73, 140,
140, 140, 143, 143, 143, 90, 90, 90, 124, 124, 124, 165, 165, 165, 127, 127, 127,
138, 138, 138, 160, 160, 160, 78, 78, 78, 101, 101, 101, 99, 99, 99, 109, 109, 109,
157, 157, 157, 159, 159, 159, 124, 124, 124, 121, 121, 121, 153, 153, 153, 151,
151, 151, 195, 195, 195, 255, 255, 255, 0, 0, 0, 35, 35, 35, 42, 42, 42, 94, 94,
94, 32, 32, 32, 40, 40, 40, 44, 44, 44, 94, 94, 94, 70, 70, 70, 104, 104, 104, 96,
96, 96, 96, 96, 96, 175, 175, 175, 127, 127, 127, 144, 144, 144, 117, 117, 117,
128, 128, 128, 175, 175, 175, 97, 97, 97, 71, 71, 71, 47, 47, 47, 72, 72, 72, 105,
105, 105, 155, 155, 155, 142, 142, 142, 164, 164, 164, 193, 193, 193, 177, 177,
177, 189, 189, 189, 247, 247, 247, 81, 81, 81, 65, 65, 65, 69, 69, 69, 87, 87, 87,
50, 50, 50, 39, 39, 39, 72, 72, 72, 37, 37, 37, 110, 110, 110, 84, 84, 84, 135,
135, 135, 162, 162, 162, 141, 141, 141, 186, 186, 186, 149, 149, 149, 168, 168,
168, 188, 188, 188, 101, 101, 101, 98, 98, 98, 39, 39, 39, 51, 51, 51, 91, 91, 91,
84, 84, 84, 112, 112, 112, 136, 136, 136, 152, 152, 152, 179, 179, 179, 201, 201,
201, 154, 154, 154, 249, 249, 249, 128, 128, 128, 111, 111, 111, 105, 105, 105, 37,
37, 37, 36, 36, 36, 43, 43, 43, 88, 88, 88, 121, 121, 121, 84, 84, 84, 148, 148,
148, 141, 141, 141, 141, 141, 141, 117, 117, 117, 156, 156, 156, 191, 191, 191,
190, 190, 190, 148, 148, 148, 144, 144, 144, 116, 116, 116, 97, 97, 97, 121, 121,
121, 113, 113, 113, 92, 92, 92, 139, 139, 139, 186, 186, 186, 122, 122, 122, 137,
137, 137, 155, 155, 155, 220, 220, 220, 208, 208, 208, 168, 168, 168, 210, 210,
210, 109, 109, 109, 125, 125, 125, 168, 168, 168, 112, 112, 112, 133, 133, 133,
148, 148, 148, 140, 140, 140, 135, 135, 135, 174, 174, 174, 149, 149, 149, 211,
211, 211, 150, 150, 150, 119, 119, 119, 169, 169, 169, 171, 171, 171, 198, 198,
198, 90, 90, 90, 65, 65, 65, 42, 42, 42, 68, 68, 68, 69, 69, 69, 97, 97, 97, 57,
57, 57, 113, 113, 113, 59, 59, 59, 172, 172, 172, 171, 171, 171, 182, 182, 182,
244, 244, 244, 211, 211, 211, 222, 222, 222, 158, 158, 158, 155, 155, 155, 143,
143, 143, 139, 139, 139, 168, 168, 168, 194, 194, 194, 177, 177, 177, 255, 255,
255, 163, 163, 163, 219, 219, 219, 176, 176, 176, 139, 139, 139, 151, 151, 151,
199, 199, 199, 129, 129, 129, 91, 91, 91, 73, 73, 73, 67, 67, 67, 46, 46, 46, 9, 9,
9, 79, 79, 79, 51, 51, 51, 110, 110, 110, 44, 44, 44, 91, 91, 91, 179, 179, 179,
163, 163, 163, 255, 255, 255, 218, 218, 218, 186, 186, 186, 184, 184, 184, 202,
202, 202, 113, 113, 113, 157, 157, 157, 173, 173, 173, 122, 122, 122, 170, 170,
170, 193, 193, 193, 194, 194, 194, 163, 163, 163, 253, 253, 253, 208, 208, 208,
184, 184, 184, 161, 161, 161, 128, 128, 128, 114, 114, 114, 28, 28, 28, 9, 9, 9,
42, 42, 42, 37, 37, 37, 61, 61, 61, 7, 7, 7, 41, 41, 41, 114, 114, 114, 94, 94, 94,
116, 116, 116, 160, 160, 160, 224, 224, 224, 255, 255, 255, 174, 174, 174, 206,
206, 206, 178, 178, 178, 108, 108, 108, 96, 96, 96, 147, 147, 147, 179, 179, 179,
169, 169, 169, 162, 162, 162, 182, 182, 182, 193, 193, 193, 144, 144, 144, 145,
145, 145, 144, 144, 144, 133, 133, 133, 129, 129, 129, 50, 50, 50, 0, 0, 0, 46, 46,
46, 40, 40, 40, 33, 33, 33, 73, 73, 73, 69, 69, 69, 50, 50, 50, 69, 69, 69, 86, 86,
86, 110, 110, 110, 134, 134, 134, 253, 253, 253, 212, 212, 212, 200, 200, 200, 126,
126, 126, 149, 149, 149, 138, 138, 138, 135, 135, 135, 145, 145, 145, 148, 148,
148, 190, 190, 190, 199, 199, 199, 224, 224, 224, 136, 136, 136, 186, 186, 186,
177, 177, 177, 149, 149, 149, 180, 180, 180, 140, 140, 140, 131, 131, 131, 28, 28,
28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 22, 22, 8, 8, 8, 0, 0, 0, 71, 71, 71, 51, 51,
51, 117, 117, 117, 135, 135, 135,
];
for (ind, val) in k.enumerate() {
assert_eq!(val, oracle[ind]);
}
}
}
}
extern crate image;
use rand::prelude::*;
use rand::rngs::OsRng;
use rand_chacha::ChaChaRng;
use std::convert::TryInto;
fn gaussian_blur_asymmetric(
image: image::RgbImage,
blur_radius_horizontal: f32,
blur_radius_vertical: f32,
) -> Option<image::RgbImage> {
let (width, height) = image.dimensions();
let mut data = unflatten(&image.into_raw());
fastblur::gaussian_blur_asymmetric(
&mut data,
width.try_into().unwrap(),
height.try_into().unwrap(),
blur_radius_horizontal,
blur_radius_vertical,
);
image::RgbImage::from_raw(width, height, flatten(&data))
}
fn flatten(data: &[[u8; 3]]) -> Vec<u8> {
let mut a = vec![];
for rgb in data {
a.push(rgb[0]);
a.push(rgb[1]);
a.push(rgb[2]);
}
a
}
fn unflatten(data: &[u8]) -> Vec<[u8; 3]> {
let iter = data.chunks(3);
let mut a = vec![];
for rgb in iter {
a.push([rgb[0], rgb[1], rgb[2]]);
}
a
}
#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
fn clamp_to_u8(a: f32) -> u8 {
num::clamp(a, 0.0, 255.0) as u8
}
#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
fn multiply_channel(a: u8, b: u8) -> u8 {
(f32::from(a) * f32::from(b) / 255.0) as u8
}
#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
fn stretch_contrast(min: u8, max: u8, data: u8) -> u8 {
if min >= max {
panic!("max must be strictly greater than min")
}
if min <= data && data <= max {
(255.0 / f32::from(max - min) * f32::from(data - min)) as u8
} else {
panic!("data must lie between min and max")
}
}
fn multiply_pixel(a: image::Rgb<u8>, b: image::Rgb<u8>) -> image::Rgb<u8> {
let image::Rgb(a) = a;
let image::Rgb(b) = b;
image::Rgb([
multiply_channel(a[0], b[0]),
multiply_channel(a[1], b[1]),
multiply_channel(a[2], b[2]),
])
}
#[must_use]
pub fn cloth_bumpmap(width: u32, height: u32, fixed_seed: bool) -> Option<image::RgbImage> {
let mut rng = if fixed_seed {
rand_chacha::ChaCha20Rng::seed_from_u64(0x8c59_3df5_2946_01a6_u64)
} else {
ChaChaRng::from_rng(OsRng).ok()?
};
let mut layer_one = image::RgbImage::new(width, height);
let distr = rand_distr::Normal::new(0., 0.35).ok()?;
for (_, _, pixel) in layer_one.enumerate_pixels_mut() {
let v = rng.sample(distr);
let a = clamp_to_u8(255.0 * (1. + v));
*pixel = image::Rgb([a, a, a]);
}
let blur_strength = 9.0;
let layer_two = layer_one.clone();
let mut horizontal = gaussian_blur_asymmetric(layer_one, blur_strength, 1.0).unwrap();
let vertical = gaussian_blur_asymmetric(layer_two, 1.0, blur_strength).unwrap();
for (x, y, pixel) in horizontal.enumerate_pixels_mut() {
*pixel = multiply_pixel(*pixel, *vertical.get_pixel(x, y))
}
let mut merged = horizontal;
let (min, max) = get_min_max(&merged.clone().into_raw());
if min >= max {
panic!("zero fluctuation: impossible!")
}
for (_, _, pixel) in merged.enumerate_pixels_mut() {
let image::Rgb(data) = *pixel;
*pixel = image::Rgb([
stretch_contrast(min, max, data[0]),
stretch_contrast(min, max, data[1]),
stretch_contrast(min, max, data[2]),
]);
}
let distr = rand_distr::Normal::new(0., 0.1).ok()?;
for (_, _, pixel) in merged.enumerate_pixels_mut() {
let v = rng.sample(distr);
let image::Rgb(data) = *pixel;
*pixel = image::Rgb([
clamp_to_u8(f32::from(data[0]) + 255.0 * v),
clamp_to_u8(f32::from(data[1]) + 255.0 * v),
clamp_to_u8(f32::from(data[2]) + 255.0 * v),
]);
}
Some(merged)
}
fn get_min_max(vec: &[u8]) -> (u8, u8) {
let mut minmax = (255, 0);
for i in vec {
if i < &minmax.0 {
minmax.0 = *i;
}
if i > &minmax.1 {
minmax.1 = *i;
}
}
minmax
}