1use std::ffi;
2
3use libc;
4
5#[allow(dead_code)]
6
7#[link(name="wfc")]
8extern {
9 fn wfc_init(wfc: *mut std::ffi::c_void);
10
11 fn wfc_run(wfc: *mut std::ffi::c_void, max_collapse_cnt: libc::c_int) -> libc::c_int;
12
13 fn wfc_export(wfc: *const std::ffi::c_void, filename: *const libc::c_char) -> libc::c_int;
14
15 fn wfc_destroy(wfc: *mut std::ffi::c_void);
16
17 fn wfc_img_copy(image: *const WfcImageRaw) -> *mut WfcImageRaw;
18
19 fn wfc_img_destroy(image: *mut WfcImageRaw);
20
21 fn wfc_output_image(wfc: *mut std::ffi::c_void) -> *mut WfcImageRaw;
22
23 fn wfc_img_load(filename: *const libc::c_char) -> *mut WfcImageRaw;
24
25 fn wfc_img_create(width: libc::c_int, height: libc::c_int, component_cnt: libc::c_int) -> *mut WfcImageRaw;
26
27 fn wfc_overlapping(output_width: libc::c_int,
28 output_height: libc::c_int,
29 image: *mut WfcImageRaw,
30 tile_width: libc::c_int,
31 tile_height: libc::c_int,
32 expand_input: libc::c_int,
33 xflip_tiles: libc::c_int,
34 yflip_tiles: libc::c_int,
35 rotate_tiles: libc::c_int) -> *mut std::ffi::c_void;
36}
37
38#[repr(C)]
39pub struct WfcImageRaw {
40 pub data: *mut i8,
41 pub component_cnt: libc::c_int,
42 pub width: libc::c_int,
43 pub height: libc::c_int,
44}
45
46pub struct WfcImage {
47 pub img: *mut WfcImageRaw,
48}
49
50impl WfcImage {
51 pub fn new(data: *mut i8,
52 component_cnt: libc::c_int,
53 width: libc::c_int,
54 height: libc::c_int) -> WfcImage {
55 unsafe {
56 let layout = std::alloc::Layout::new::<WfcImageRaw>();
57 let raw_img: *mut WfcImageRaw = std::alloc::alloc(layout) as *mut WfcImageRaw;
58
59 (*raw_img).data = data;
60 (*raw_img).component_cnt = component_cnt;
61 (*raw_img).width = width;
62 (*raw_img).height = height;
63
64 return WfcImage { img: raw_img };
65 }
66 }
67
68 pub fn empty() -> WfcImage {
69 return WfcImage { img: std::ptr::null_mut() };
70 }
71
72 pub fn from_vec(width: i32, height: i32, component_cnt: i32, data: Vec<u8>) -> WfcImage {
73 unsafe {
74 let image_ptr = wfc_img_create(width, height, component_cnt);
75 let length = data.len();
76 std::ptr::copy_nonoverlapping(data.as_ptr() as *mut u8, (*image_ptr).data as *mut u8, length);
77
78 return WfcImage { img: image_ptr };
79 }
80 }
81
82 pub fn from_file(filename: &str) -> Option<WfcImage> {
83 unsafe {
84 let c_filename = ffi::CString::new(filename).ok()?;
85 let image: WfcImage = WfcImage { img: wfc_img_load(c_filename.as_ptr()) };
86 return Some(image);
87 }
88 }
89
90 pub fn vec(&self) -> Vec<u8> {
91 unsafe {
92 let length = self.num_bytes();
93 let data: *mut u8 = libc::malloc(length) as *mut u8;
94 std::ptr::copy_nonoverlapping((*self.img).data as *mut u8, data, length);
95
96 std::mem::forget(data);
97
98 return Vec::from_raw_parts(data, length, length);
99 }
100 }
101
102 pub fn num_bytes(&self) -> usize {
103 unsafe {
104 return ((*self.img).width * (*self.img).height * (*self.img).component_cnt) as usize;
105 }
106 }
107
108 pub fn component_cnt(&self) -> libc::c_int {
109 unsafe {
110 return (*self.img).component_cnt;
111 }
112 }
113
114 pub fn width(&self) -> libc::c_int {
115 unsafe {
116 return(*self.img).width;
117 }
118 }
119
120 pub fn height(&self) -> libc::c_int {
121 unsafe {
122 return(*self.img).height;
123 }
124 }
125}
126
127impl Drop for WfcImage {
128 fn drop(&mut self) {
129 unsafe {
130 wfc_img_destroy(self.img as *mut WfcImageRaw);
131 }
132 }
133}
134
135pub struct Wfc {
141 pub wfc: *mut libc::c_void,
142 pub image: WfcImage,
143}
144
145impl Wfc {
146 pub fn from_raw_parts(wfc: *mut libc::c_void, image: WfcImage) -> Wfc {
147 return Wfc { wfc, image };
148 }
149
150 pub fn overlapping(output_width: i32,
151 output_height: i32,
152 image: WfcImage,
153 tile_width: i32,
154 tile_height: i32,
155 expand_input: bool,
156 xflip_tiles: bool,
157 yflip_tiles: bool,
158 rotate_tiles: bool) -> Option<Wfc> {
159 unsafe {
160 let wfc = wfc_overlapping(output_width,
161 output_height,
162 image.img.as_mut()?,
163 tile_width,
164 tile_height,
165 expand_input as i32,
166 xflip_tiles as i32,
167 yflip_tiles as i32,
168 rotate_tiles as i32);
169
170 if wfc.is_null() {
171 return None;
172 }
173
174 return Some(Wfc::from_raw_parts(wfc, image));
175 }
176 }
177
178 pub fn run(&mut self, max_collapse_cnt: Option<i32>, seed: Option<u32>) -> Result<(), &str> {
179 unsafe {
180 let wfc_ptr = self.wfc.as_mut().ok_or("Wfc pointer invalid")?;
181 wfc_init(wfc_ptr);
182
183 if let Some(seed) = seed {
186 libc::srand(seed)
187 }
188
189 let max_cnt = max_collapse_cnt.unwrap_or(-1);
190 let result: libc::c_int = wfc_run(wfc_ptr, max_cnt);
191
192 if result == 0 {
193 return Err("wfc_run returned an error!");
194 } else {
195 return Ok(());
196 }
197 }
198 }
199
200 pub fn export(&mut self, filename: &str) -> Result<(), &str> {
201 unsafe {
202 let c_filename = ffi::CString::new(filename).map_err(|_| "Filename to CString error")?;
203 let wfc_ptr = self.wfc.as_mut().ok_or("Wfc pointer invalid")?;
204 let result = wfc_export(wfc_ptr, c_filename.as_ptr());
205
206 if result == 0 {
207 return Err("wfc_export returned an error!");
208 } else {
209 return Ok(());
210 }
211 }
212 }
213
214 pub fn output_image(&mut self) -> Option<WfcImage> {
215 unsafe {
216 let img = wfc_output_image(self.wfc.as_mut()?);
217 if img.is_null() {
218 return Some(WfcImage { img: img });
219 } else {
220 return None;
221 }
222 };
223 }
224
225 pub fn vec(&mut self) -> Vec<u8> {
228 return self.image.vec();
229 }
230}
231
232impl Drop for Wfc {
233 fn drop(&mut self) {
234 unsafe {
235 let _image = std::mem::replace(&mut self.image, WfcImage::empty());
238
239 if let Some(wfc_ptr) = self.wfc.as_mut() {
240 wfc_destroy(wfc_ptr);
241 }
242 }
243 }
244}
245
246#[test]
247pub fn test_overlapping() {
248 {
249 let image = WfcImage::from_file("data/cave.png").unwrap();
250 let _wfc = Wfc::overlapping(32, 32, image, 3, 3, true, true, true, true);
251 }
252 {
253 let image = WfcImage::from_file("data/cave.png").unwrap();
254 let _wfc = Wfc::overlapping(32, 32, image, 3, 3, true, true, true, true);
255 }
256 {
257 let image = WfcImage::from_file("data/cave.png").unwrap();
258 let _wfc = Wfc::overlapping(32, 32, image, 3, 3, true, true, true, true);
259 }
260}
261
262#[test]
263pub fn test_run() {
264 let image = WfcImage::from_file("data/cave.png").unwrap();
265
266 let mut wfc = Wfc::overlapping(32, 32, image, 3, 3, true, true, true, true).unwrap();
267
268 let result = wfc.run(Some(10), Some(1));
269 assert_eq!(Ok(()), result);
270}
271
272#[test]
273pub fn test_export() {
274 let image = WfcImage::from_file("data/cave.png").unwrap();
275
276 let mut wfc = Wfc::overlapping(32, 32, image, 3, 3, true, true, true, true).unwrap();
277 let result = wfc.run(Some(100), Some(1));
278 assert_eq!(Ok(()), result);
279
280 wfc.export("output.png").unwrap();
281 std::fs::remove_file("output.png").unwrap();
282}
283
284#[test]
285pub fn test_image() {
286 let image = WfcImage::from_file("data/cave.png").unwrap();
287
288 let bytes = image.vec();
289 assert_eq!(image.num_bytes(), bytes.len());
290}
291