Fix everything except for casts
This commit is contained in:
		
							parent
							
								
									8396aa4613
								
							
						
					
					
						commit
						c466b8eb2a
					
				| @ -5,5 +5,7 @@ fn main() -> u32 { | |||||||
|   let value = 0b110; |   let value = 0b110; | ||||||
|   let other = 0o17; |   let other = 0o17; | ||||||
| 
 | 
 | ||||||
|   return value * other + 7 * -value; |   let b = [5.0, 0.0 -5.0]; | ||||||
|  | 
 | ||||||
|  |   return value -1; | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										469
									
								
								foo.reid
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										469
									
								
								foo.reid
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,469 @@ | |||||||
|  | import std::concat_strings; | ||||||
|  | import std::print; | ||||||
|  | import std::from_str; | ||||||
|  | import std::free_string; | ||||||
|  | import std::add_num_to_str; | ||||||
|  | 
 | ||||||
|  | /////////////////// | ||||||
|  | /// SDL externs /// | ||||||
|  | /////////////////// | ||||||
|  | 
 | ||||||
|  | // Helper struct for stack allocated const sized strings, because structs are | ||||||
|  | // easier to create uninit than arrays. | ||||||
|  | struct SDL_Window {} | ||||||
|  | struct SDL_Renderer {} | ||||||
|  | struct SDL_Texture {} | ||||||
|  | struct SDL_Event { type: u32, reserved: [u8; 124] } | ||||||
|  | struct SDL_FRect { x: f32, y: f32, w: f32, h: f32 } | ||||||
|  | struct SDL_Rect { x: i32, y: i32, w: i32, h: i32 } | ||||||
|  | extern fn SDL_malloc(size: u64) -> *u8; | ||||||
|  | extern fn SDL_Init(flags: u32) -> bool; | ||||||
|  | extern fn SDL_Quit(); | ||||||
|  | extern fn SDL_CreateWindowAndRenderer(title: *char, width: i32, height: i32, flags: i32, | ||||||
|  |     window_out: &mut *SDL_Window, renderer_out: &mut *SDL_Renderer) -> bool; | ||||||
|  | extern fn SDL_Delay(ms: u32); | ||||||
|  | extern fn SDL_SetRenderDrawColor(renderer: *SDL_Renderer, r: u8, g: u8, b: u8, a: u8); | ||||||
|  | extern fn SDL_RenderClear(renderer: *SDL_Renderer); | ||||||
|  | extern fn SDL_RenderPresent(renderer: *SDL_Renderer); | ||||||
|  | extern fn SDL_HasEvent(event_type: u32) -> bool; | ||||||
|  | extern fn SDL_PollEvent(event: &mut SDL_Event) -> bool; | ||||||
|  | extern fn SDL_PumpEvents(); | ||||||
|  | extern fn SDL_FlushEvents(min_type: u32, max_type: u32); | ||||||
|  | extern fn SDL_GetTicks() -> u64; | ||||||
|  | extern fn SDL_SetWindowTitle(window: *SDL_Window, title: *char) -> bool; | ||||||
|  | extern fn SDL_CreateTexture(renderer: *SDL_Renderer,  | ||||||
|  |     pixel_format: u32, texture_access: u32, width: u32, height: u32) -> *SDL_Texture; | ||||||
|  | extern fn SDL_RenderTexture(renderer: *SDL_Renderer, | ||||||
|  |     texture: *SDL_Texture, srcfrect: &SDL_FRect, dstfrect: &SDL_FRect) -> bool; | ||||||
|  | extern fn SDL_UpdateTexture(texture: *SDL_Texture, rect: &SDL_Rect, pixels: *u8, pitch: u32) -> bool; | ||||||
|  | extern fn SDL_GetError() -> *char; | ||||||
|  | extern fn SDL_GetWindowSize(window: *SDL_Window, w: &mut i32, h: &mut i32) -> bool; | ||||||
|  | extern fn SDL_rand(max_exclusive: u32) -> u32; | ||||||
|  | extern fn SDL_SetTextureScaleMode(texture: *SDL_Texture, scale_mode: i32) -> bool; | ||||||
|  | extern fn SDL_sqrtf(value: f32) -> f32; | ||||||
|  | extern fn SDL_randf() -> f32; | ||||||
|  | extern fn SDL_powf(value: f32, power: f32) -> f32; | ||||||
|  | 
 | ||||||
|  | // SDL error reporting helper | ||||||
|  | fn print_sdl_error(context: *char) { | ||||||
|  |     let mut message = from_str(context); | ||||||
|  | 
 | ||||||
|  |     let delim = from_str(": "); | ||||||
|  |     concat_strings(&mut message, delim); | ||||||
|  |     free_string(&delim); | ||||||
|  | 
 | ||||||
|  |     let error_msg = from_str(SDL_GetError()); | ||||||
|  |     concat_strings(&mut message, error_msg); | ||||||
|  |     free_string(&error_msg); | ||||||
|  | 
 | ||||||
|  |     print(message); | ||||||
|  | 
 | ||||||
|  |     free_string(&message); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ///////////////////////////////// | ||||||
|  | /// Main setup and frame loop /// | ||||||
|  | ///////////////////////////////// | ||||||
|  | 
 | ||||||
|  | struct GameState { | ||||||
|  |     renderer: *SDL_Renderer, | ||||||
|  |     window: *SDL_Window, | ||||||
|  |     render_texture: *SDL_Texture, | ||||||
|  |     frame_counter: u32, | ||||||
|  |     last_fps_reset: u64, | ||||||
|  |     pixels: *u8, | ||||||
|  |     pixels_w: u32, | ||||||
|  |     pixels_h: u32, | ||||||
|  |     pixels_bpp: u32, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn main() -> i32 { | ||||||
|  |     let SDL_INIT_VIDEO = 32; | ||||||
|  |     let SDL_WINDOW_RESIZABLE = 32; | ||||||
|  |     let SDL_PIXELFORMAT_RGBA8888 = 373694468; | ||||||
|  |     let SDL_PIXELFORMAT_ABGR8888 = 376840196; | ||||||
|  |     let SDL_PIXELFORMAT_RGB24 = 386930691; | ||||||
|  |     let SDL_PIXELFORMAT_BGR24 = 390076419; | ||||||
|  |     let SDL_PIXELFORMAT_RGB96_FLOAT = 454057996; | ||||||
|  |     let SDL_PIXELFORMAT_BGR96_FLOAT = 457203724; | ||||||
|  |     let SDL_TEXTUREACCESS_STREAMING = 1; | ||||||
|  |     let SDL_SCALEMODE_NEAREST = 0; | ||||||
|  |     let SDL_SCALEMODE_LINEAR = 1; | ||||||
|  |     let SDL_SCALEMODE_PIXELART = 2; | ||||||
|  | 
 | ||||||
|  |     let init_success = SDL_Init(SDL_INIT_VIDEO); | ||||||
|  |     if init_success == false { | ||||||
|  |         print_sdl_error("SDL init failed"); | ||||||
|  |         return 1; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     let mut window = SDL_malloc(1) as *SDL_Window; | ||||||
|  |     let mut renderer = SDL_malloc(1) as *SDL_Renderer; | ||||||
|  |     let gfx_init_success = SDL_CreateWindowAndRenderer( | ||||||
|  |         "graphical reid program", 640, 480, SDL_WINDOW_RESIZABLE, | ||||||
|  |         &mut window, &mut renderer | ||||||
|  |     ); | ||||||
|  |     if gfx_init_success == false { | ||||||
|  |         print_sdl_error("SDL renderer and window creation failed"); | ||||||
|  |         return 1; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     let width = 320; | ||||||
|  |     let height = 240; | ||||||
|  |     let bpp = 4; | ||||||
|  |     let render_texture = SDL_CreateTexture(renderer,  | ||||||
|  |         SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STREAMING, width, height); | ||||||
|  |     SDL_SetTextureScaleMode(render_texture, SDL_SCALEMODE_NEAREST); | ||||||
|  | 
 | ||||||
|  |     let pixels_len = (width * height * bpp) as u64; | ||||||
|  |     let pixels = SDL_malloc(pixels_len); | ||||||
|  |     let mut game_state = GameState { | ||||||
|  |         renderer: renderer, | ||||||
|  |         window: window, | ||||||
|  |         render_texture: render_texture, | ||||||
|  |         frame_counter: 0, | ||||||
|  |         last_fps_reset: 0, | ||||||
|  |         pixels: pixels, | ||||||
|  |         pixels_w: width, | ||||||
|  |         pixels_h: height, | ||||||
|  |         pixels_bpp: bpp, | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     while frame_loop(&mut game_state) {} | ||||||
|  | 
 | ||||||
|  |     SDL_Quit(); | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn frame_loop(game_state: &mut GameState) -> bool { | ||||||
|  |     let mut event = SDL_Event {}; | ||||||
|  |     while (SDL_PollEvent(&mut event)) { | ||||||
|  |         if event.type == 256 { // SDL_EVENT_QUIT | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     let mut screen_width = 0; | ||||||
|  |     let mut screen_height = 0; | ||||||
|  |     SDL_GetWindowSize(*game_state.window, &mut screen_width, &mut screen_height); | ||||||
|  | 
 | ||||||
|  |     let renderer = *game_state.renderer; | ||||||
|  |     SDL_SetRenderDrawColor(renderer, 0, 50, 90, 255); | ||||||
|  |     SDL_RenderClear(renderer); | ||||||
|  | 
 | ||||||
|  |     let w = *game_state.pixels_w; | ||||||
|  |     let h = *game_state.pixels_h; | ||||||
|  |     let bpp = *game_state.pixels_bpp; | ||||||
|  |     for y in 0..h { | ||||||
|  |         for x in 0..w { | ||||||
|  |             render_pixel(x, y, game_state); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     let texture_area = SDL_Rect { x: 0, y: 0, w: w as i32, h: h as i32 }; | ||||||
|  |     if SDL_UpdateTexture(*game_state.render_texture, &texture_area, *game_state.pixels as *u8, bpp * w) == false { | ||||||
|  |         print_sdl_error("UpdateTexture error"); | ||||||
|  |     } | ||||||
|  |     let src = SDL_FRect { x: 0.0, y: 0.0, w: w as f32, h: h as f32 }; | ||||||
|  |     let aspect_ratio = src.w / src.h; | ||||||
|  |     let scaled_width = screen_height as f32 * aspect_ratio; | ||||||
|  |     let dst = SDL_FRect { x: (screen_width as f32 - scaled_width) / 2.0, y: 0.0, w: scaled_width, h: screen_height as f32 }; | ||||||
|  |     if SDL_RenderTexture(renderer, *game_state.render_texture, &src, &dst) == false { | ||||||
|  |         print_sdl_error("RenderTexture error"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     SDL_RenderPresent(renderer); | ||||||
|  |     SDL_Delay(1); | ||||||
|  | 
 | ||||||
|  |     *game_state.frame_counter = *game_state.frame_counter + 1; | ||||||
|  |     let t = SDL_GetTicks(); | ||||||
|  |     if (t - *game_state.last_fps_reset) >= 1000 { | ||||||
|  |         let mut title = from_str("graphical reid program "); | ||||||
|  |         add_num_to_str(&mut title, *game_state.frame_counter as u64); | ||||||
|  |         let fps_unit = from_str(" fps"); | ||||||
|  |         concat_strings(&mut title, fps_unit); | ||||||
|  |         free_string(&fps_unit); | ||||||
|  |         SDL_SetWindowTitle(*game_state.window, title.inner); | ||||||
|  |         free_string(&title); | ||||||
|  |         *game_state.frame_counter = 0; | ||||||
|  |         *game_state.last_fps_reset = t; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn render_pixel(x: u32, y: u32, game_state: &mut GameState) { | ||||||
|  |     let w = *game_state.pixels_w; | ||||||
|  |     let h = *game_state.pixels_h; | ||||||
|  |     let bpp = *game_state.pixels_bpp; | ||||||
|  | 
 | ||||||
|  |     let samples = 1; | ||||||
|  |     let old_sample_weight = 0.75; | ||||||
|  |     let new_sample_weight = 0.25 / samples as f32; | ||||||
|  |     let mut rgb = vec_mul_scalar(old_sample_weight, [ | ||||||
|  |         srgb_to_linear(*game_state.pixels[(x + y * w) * bpp + 0]), | ||||||
|  |         srgb_to_linear(*game_state.pixels[(x + y * w) * bpp + 1]), | ||||||
|  |         srgb_to_linear(*game_state.pixels[(x + y * w) * bpp + 2]) | ||||||
|  |     ]); | ||||||
|  |     for sample in 0..samples { | ||||||
|  |         rgb = vec_add(rgb, vec_mul_scalar(new_sample_weight, shade(x, y, *game_state.frame_counter, w, h))); | ||||||
|  |     } | ||||||
|  |     *game_state.pixels[(x + y * w) * bpp + 0] = linear_to_srgb(rgb[0]); | ||||||
|  |     *game_state.pixels[(x + y * w) * bpp + 1] = linear_to_srgb(rgb[1]); | ||||||
|  |     *game_state.pixels[(x + y * w) * bpp + 2] = linear_to_srgb(rgb[2]); | ||||||
|  |     *game_state.pixels[(x + y * w) * bpp + 3] = 255; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | ///////////////// | ||||||
|  | /// Rendering /// | ||||||
|  | ///////////////// | ||||||
|  | 
 | ||||||
|  | struct Ray { | ||||||
|  |     origin: [f32; 3], | ||||||
|  |     direction: [f32; 3], | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | struct Material { | ||||||
|  |     // 0 = lambertian diffuse | ||||||
|  |     // 1 = mirror | ||||||
|  |     type: u32, | ||||||
|  |     // Generally the "color" of the surface (linear factors of how much of each | ||||||
|  |     // color channel this surface does not absorb), but the idea is that the | ||||||
|  |     // type governs what this means. | ||||||
|  |     linear_color: [f32; 3], | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | struct Hit { | ||||||
|  |     hit: bool, | ||||||
|  |     front_face: bool, | ||||||
|  |     distance: f32, | ||||||
|  |     normal: [f32; 3], | ||||||
|  |     position: [f32; 3], | ||||||
|  |     material: Material, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | struct Sphere { | ||||||
|  |     center: [f32; 3], | ||||||
|  |     radius: f32, | ||||||
|  |     material: Material, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn shade(x: u32, y: u32, t: u32, w: u32, h: u32) -> [f32; 3] { | ||||||
|  |     let jitter_x = SDL_randf() - 0.5; | ||||||
|  |     let jitter_y = SDL_randf() - 0.5; | ||||||
|  | 
 | ||||||
|  |     let pixel_scale = 1.0 / h as f32; | ||||||
|  |     let pixel_pos = [ | ||||||
|  |         (x as f32 + jitter_x) * pixel_scale,  | ||||||
|  |         1.0 - (y as f32 + jitter_y) * pixel_scale, | ||||||
|  |         0.0 - 1.0 | ||||||
|  |     ]; | ||||||
|  |     let camera_pos = [w as f32 * 0.5f32 * pixel_scale, h as f32 * 0.5f32 * pixel_scale, 0.0f32]; | ||||||
|  |     let dir = vec_normalize(vec_sub(pixel_pos, camera_pos)); | ||||||
|  |     let ray = Ray { origin: camera_pos, direction: dir }; | ||||||
|  |     let beige_lambertian = Material { type: 0, linear_color: [0.3, 0.2, 0.1] }; | ||||||
|  |     let green_lambertian = Material { type: 0, linear_color: [0.1, 0.5, 0.06] }; | ||||||
|  |     let greenish_mirror = Material { type: 1, linear_color: [0.9, 1.0, 0.95] }; | ||||||
|  |     let spheres = [ | ||||||
|  |         // Ground | ||||||
|  |         Sphere { center: vec_sub(camera_pos, [0.0, 100001.0, 0.0]), radius: 100000.0, material: beige_lambertian }, | ||||||
|  |         // Centered unit sphere | ||||||
|  |         Sphere { center: vec_add(camera_pos, [0.0, 0.0, 0.0 - 5.0]), radius: 1.0, material: green_lambertian }, | ||||||
|  |         // The unit sphere on the right | ||||||
|  |         Sphere { center: vec_add(camera_pos, [2.0, 0.0, 0.0 - 6.0]), radius: 1.0, material: greenish_mirror } | ||||||
|  |     ]; | ||||||
|  |     return shade_world(ray, &spheres, 3); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn shade_world(ray: Ray, spheres: &[Sphere; 3], bounces_left: u8) -> [f32; 3] { | ||||||
|  |     if bounces_left == 0 { | ||||||
|  |         return [0.0, 0.0, 0.0]; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     let ray_distance = 100.0; | ||||||
|  |     let mut closest_hit = Hit { hit: false, front_face: false, distance: ray_distance }; | ||||||
|  |     for i in 0..3 { | ||||||
|  |         let sphere_hit = ray_sphere_closest_hit(ray, *spheres[i], [0.001, closest_hit.distance]); | ||||||
|  |         if sphere_hit.hit { | ||||||
|  |             closest_hit = sphere_hit; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if closest_hit.hit { | ||||||
|  |         //return vec_mul_scalar(0.5, vec_add(closest_hit.normal, [1.0, 1.0, 1.0])); // normal | ||||||
|  |         //return vec_mul_scalar(closest_hit.distance / 10.0, [1.0, 1.0, 1.0]); // depth | ||||||
|  |         if closest_hit.material.type == 0 { | ||||||
|  |             let bounce_dir = vec_normalize(vec_add(closest_hit.normal, random_unit_vec())); | ||||||
|  |             let bounce_ray = Ray { origin: closest_hit.position, direction: bounce_dir }; | ||||||
|  |             return vec_mul_componentwise( | ||||||
|  |                 closest_hit.material.linear_color,  | ||||||
|  |                 shade_world(bounce_ray, spheres, bounces_left - 1) | ||||||
|  |             ); | ||||||
|  |         } else if closest_hit.material.type == 1 { | ||||||
|  |             let bounce_dir = vec_reflect(ray.direction, closest_hit.normal); | ||||||
|  |             let bounce_ray = Ray { origin: closest_hit.position, direction: bounce_dir }; | ||||||
|  |             return vec_mul_componentwise( | ||||||
|  |                 closest_hit.material.linear_color,  | ||||||
|  |                 shade_world(bounce_ray, spheres, bounces_left - 1) | ||||||
|  |             ); | ||||||
|  |         } else { | ||||||
|  |             return [1.0, 0.0, 1.0]; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return shade_sky(ray); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn shade_sky(ray: Ray) -> [f32; 3] { | ||||||
|  |     let a = 0.5 * (ray.direction[1] + 1.0); | ||||||
|  |     return vec_add( | ||||||
|  |         vec_mul_scalar(1.0 - a, [1.0, 1.0, 1.0]), | ||||||
|  |         vec_mul_scalar(a, [0.5, 0.7, 1.0]) | ||||||
|  |     ); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Returns the distance from the ray origin to the sphere, or -1.0 if the ray doesn't hit. | ||||||
|  | fn ray_sphere_closest_hit(ray: Ray, sphere: Sphere, interval: [f32; 2]) -> Hit { | ||||||
|  |     let to_sphere = vec_sub(sphere.center, ray.origin); | ||||||
|  |     let h = vec_dot(ray.direction, to_sphere); | ||||||
|  |     let c = vec_length_squared(to_sphere) - sphere.radius * sphere.radius; | ||||||
|  |     let discriminant = h * h - c; | ||||||
|  |     if discriminant < 0.0 { | ||||||
|  |         return Hit { hit: false }; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     let discriminant_sqrt = SDL_sqrtf(discriminant); | ||||||
|  |     let mut distance = h - discriminant_sqrt; | ||||||
|  |     if interval_surrounds(interval, distance) == false { | ||||||
|  |         distance = h - discriminant_sqrt; | ||||||
|  |         if interval_surrounds(interval, distance) == false { | ||||||
|  |             return Hit { hit: false }; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     let hit_position = vec_add(ray.origin, vec_mul_scalar(distance, ray.direction)); | ||||||
|  |     let mut front_face = true; | ||||||
|  |     let mut normal = vec_normalize(vec_sub(hit_position, sphere.center)); | ||||||
|  |     if vec_dot(normal, ray.direction) > 0.0 { | ||||||
|  |         normal = vec_mul_scalar(0.0 - 1.0, normal); | ||||||
|  |         front_face = false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return Hit { | ||||||
|  |         hit: true,  | ||||||
|  |         front_face: front_face, | ||||||
|  |         distance: distance, | ||||||
|  |         normal: normal, | ||||||
|  |         position: hit_position, | ||||||
|  |         material: sphere.material, | ||||||
|  |     }; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | ////////////////// | ||||||
|  | /// Other math /// | ||||||
|  | ////////////////// | ||||||
|  | 
 | ||||||
|  | fn clamp(min: f32, max: f32, value: f32) -> f32 { | ||||||
|  |     if value > max { | ||||||
|  |         return max; | ||||||
|  |     } | ||||||
|  |     if value < min { | ||||||
|  |         return min; | ||||||
|  |     } | ||||||
|  |     return value; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn abs(f: f32) -> f32 { | ||||||
|  |     if f < 0.0 { | ||||||
|  |         return f * (0.0 - 1.0); | ||||||
|  |     } | ||||||
|  |     return f; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn vec_add(lhs: [f32; 3], rhs: [f32; 3]) -> [f32; 3] { | ||||||
|  |     return [lhs[0] + rhs[0], lhs[1] + rhs[1], lhs[2] + rhs[2]]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn vec_sub(lhs: [f32; 3], rhs: [f32; 3]) -> [f32; 3] { | ||||||
|  |     return [lhs[0] - rhs[0], lhs[1] - rhs[1], lhs[2] - rhs[2]]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn vec_dot(lhs: [f32; 3], rhs: [f32; 3]) -> f32 { | ||||||
|  |     return lhs[0] * rhs[0] + lhs[1] * rhs[1] + lhs[2] * rhs[2]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn vec_mul_componentwise(lhs: [f32; 3], rhs: [f32; 3]) -> [f32; 3] { | ||||||
|  |     return [lhs[0] * rhs[0], lhs[1] * rhs[1], lhs[2] * rhs[2]]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn vec_mul_scalar(lhs: f32, rhs: [f32; 3]) -> [f32; 3] { | ||||||
|  |     return [lhs * rhs[0], lhs * rhs[1], lhs * rhs[2]]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn vec_normalize(v: [f32; 3]) -> [f32; 3] { | ||||||
|  |     let len_reciprocal = 1.0f32 / SDL_sqrtf(vec_length_squared(v)); | ||||||
|  |     return vec_mul_scalar(len_reciprocal, v); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn vec_length_squared(v: [f32; 3]) -> f32 { | ||||||
|  |     return v[0] * v[0] + v[1] * v[1] + v[2] * v[2]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn vec_abs(v: [f32; 3]) -> [f32; 3] { | ||||||
|  |     return [abs(v[0]), abs(v[1]), abs(v[2])]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn vec_reflect(direction: [f32; 3], normal: [f32; 3]) -> [f32; 3] { | ||||||
|  |     return vec_sub(direction, vec_mul_scalar(2.0f32 * vec_dot(direction, normal), normal)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn interval_surrounds(interval: [f32; 2], value: f32) -> bool { | ||||||
|  |     return (interval[0] < value) && (value < interval[1]); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn random_unit_vec() -> [f32; 3] { | ||||||
|  |     let mut point = [ | ||||||
|  |         SDL_randf() * 2.0f32 - 1.0f32, | ||||||
|  |         SDL_randf() * 2.0f32 - 1.0f32, | ||||||
|  |         SDL_randf() * 2.0f32 - 1.0f32 | ||||||
|  |     ]; | ||||||
|  |     let mut lensq = vec_length_squared(point); | ||||||
|  |     while lensq > 1.0 { | ||||||
|  |         point = [ | ||||||
|  |             SDL_randf() * 2.0f32 - 1.0f32, | ||||||
|  |             SDL_randf() * 2.0f32 - 1.0f32, | ||||||
|  |             SDL_randf() * 2.0f32 - 1.0f32 | ||||||
|  |         ]; | ||||||
|  |         lensq = vec_length_squared(point); | ||||||
|  |     } | ||||||
|  |     let len_reciprocal = 1.0f32 / SDL_sqrtf(lensq); | ||||||
|  |     return vec_mul_scalar(len_reciprocal, point); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn random_unit_vec_on_hemi(normal: [f32; 3]) -> [f32; 3] { | ||||||
|  |     let rand_vec = random_unit_vec(); | ||||||
|  |     if vec_dot(rand_vec, normal) < 0.0f32 { | ||||||
|  |         return vec_mul_scalar(0.0f32 - 1.0f32, rand_vec); | ||||||
|  |     } | ||||||
|  |     return rand_vec; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn linear_to_srgb(linear: f32) -> u8 { | ||||||
|  |     let mut floating_srgb = 0.0; | ||||||
|  |     if linear <= 0.0031308f32 { | ||||||
|  |         floating_srgb = 12.92f32 * linear; | ||||||
|  |     } else { | ||||||
|  |         floating_srgb = SDL_powf(linear as f32, 1.0 / 2.4) * 1.055f32 - 0.055f32; | ||||||
|  |     } | ||||||
|  |     let clamped = clamp(0.0, 1.0, floating_srgb); | ||||||
|  |     return (clamped * 255.999) as u8; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn srgb_to_linear(srgb: u8) -> f32 { | ||||||
|  |     let floating_srgb = srgb as f32 / 255.0; | ||||||
|  |     if floating_srgb <= 0.04045f32 { | ||||||
|  |         return floating_srgb / 12.92f32; | ||||||
|  |     } | ||||||
|  |     return SDL_powf((floating_srgb as f32 + 0.055) / 1.055, 2.4); | ||||||
|  | } | ||||||
| @ -38,7 +38,7 @@ pub fn new_string() -> String { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn from_str(str: *char) -> String { | pub fn from_str(str: *char) -> String { | ||||||
|     let length = str_length(str); |     let length = str_length(str) as u64; | ||||||
|     let mut new = new_string(); |     let mut new = new_string(); | ||||||
|     let static = String { |     let static = String { | ||||||
|         inner: str, |         inner: str, | ||||||
|  | |||||||
| @ -131,6 +131,14 @@ pub fn form_intrinsic_binops() -> Vec<BinopDefinition> { | |||||||
|         intrinsics.push(simple_binop_def(BinaryOperator::Minus, &ty, |scope, lhs, rhs| { |         intrinsics.push(simple_binop_def(BinaryOperator::Minus, &ty, |scope, lhs, rhs| { | ||||||
|             scope.block.build(Instr::FSub(lhs, rhs)).unwrap() |             scope.block.build(Instr::FSub(lhs, rhs)).unwrap() | ||||||
|         })); |         })); | ||||||
|  |         intrinsics.push(simple_binop_def(Div, &ty, |scope, lhs, rhs| { | ||||||
|  |             scope.block.build(Instr::FDiv(lhs, rhs)).unwrap() | ||||||
|  |         })); | ||||||
|  |         intrinsics.push(simple_binop_def(Mod, &ty, |scope, lhs, rhs| { | ||||||
|  |             let div = scope.block.build(Instr::FDiv(lhs, rhs)).unwrap(); | ||||||
|  |             let mul = scope.block.build(Instr::Mul(rhs, div)).unwrap(); | ||||||
|  |             scope.block.build(Instr::Sub(lhs, mul)).unwrap() | ||||||
|  |         })); | ||||||
|         intrinsics.push(boolean_binop_def(Cmp(CmpOperator::EQ), &ty, |scope, lhs, rhs| { |         intrinsics.push(boolean_binop_def(Cmp(CmpOperator::EQ), &ty, |scope, lhs, rhs| { | ||||||
|             scope.block.build(Instr::FCmp(CmpPredicate::EQ, lhs, rhs)).unwrap() |             scope.block.build(Instr::FCmp(CmpPredicate::EQ, lhs, rhs)).unwrap() | ||||||
|         })); |         })); | ||||||
| @ -151,6 +159,10 @@ pub fn form_intrinsic_binops() -> Vec<BinopDefinition> { | |||||||
|         })); |         })); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     intrinsics.push(boolean_binop_def(And, &TypeKind::Bool, |scope, lhs, rhs| { | ||||||
|  |         scope.block.build(Instr::And(lhs, rhs)).unwrap() | ||||||
|  |     })); | ||||||
|  | 
 | ||||||
|     intrinsics |     intrinsics | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -217,9 +217,10 @@ impl Block { | |||||||
|                         variable_reference.2, |                         variable_reference.2, | ||||||
|                     ); |                     ); | ||||||
| 
 | 
 | ||||||
|  |                     dbg!(&var_t_resolved); | ||||||
|  | 
 | ||||||
|                     // Typecheck (and coerce) expression with said type
 |                     // Typecheck (and coerce) expression with said type
 | ||||||
|                     let res = expression.typecheck(&mut state, &typerefs, Some(&var_t_resolved)); |                     let res = expression.typecheck(&mut state, &typerefs, Some(&var_t_resolved)); | ||||||
| 
 |  | ||||||
|                     // If expression resolution itself was erronous, resolve as
 |                     // If expression resolution itself was erronous, resolve as
 | ||||||
|                     // Unknown and note error.
 |                     // Unknown and note error.
 | ||||||
|                     let res = state.or_else(res, TypeKind::Vague(Vague::Unknown), expression.1); |                     let res = state.or_else(res, TypeKind::Vague(Vague::Unknown), expression.1); | ||||||
| @ -413,10 +414,18 @@ impl Expression { | |||||||
|             ExprKind::BinOp(op, lhs, rhs, ret_ty) => { |             ExprKind::BinOp(op, lhs, rhs, ret_ty) => { | ||||||
|                 // First find unfiltered parameters to binop
 |                 // First find unfiltered parameters to binop
 | ||||||
|                 let lhs_res = lhs.typecheck(state, &typerefs, None); |                 let lhs_res = lhs.typecheck(state, &typerefs, None); | ||||||
|                 let lhs_type = state.or_else(lhs_res, TypeKind::Vague(Vague::Unknown), lhs.1); |  | ||||||
|                 let rhs_res = rhs.typecheck(state, &typerefs, None); |                 let rhs_res = rhs.typecheck(state, &typerefs, None); | ||||||
|  |                 let lhs_type = state.or_else(lhs_res, TypeKind::Vague(Vague::Unknown), lhs.1); | ||||||
|                 let rhs_type = state.or_else(rhs_res, TypeKind::Vague(Vague::Unknown), rhs.1); |                 let rhs_type = state.or_else(rhs_res, TypeKind::Vague(Vague::Unknown), rhs.1); | ||||||
|                 let expected_return_ty = ret_ty.resolve_ref(typerefs); | 
 | ||||||
|  |                 let mut expected_return_ty = ret_ty.resolve_ref(typerefs); | ||||||
|  |                 if let Some(hint_t) = hint_t { | ||||||
|  |                     expected_return_ty = state.or_else( | ||||||
|  |                         expected_return_ty.narrow_into(hint_t), | ||||||
|  |                         TypeKind::Vague(VagueType::Unknown), | ||||||
|  |                         self.1, | ||||||
|  |                     ); | ||||||
|  |                 }; | ||||||
| 
 | 
 | ||||||
|                 let binops = state.scope.binops.filter(&pass::ScopeBinopKey { |                 let binops = state.scope.binops.filter(&pass::ScopeBinopKey { | ||||||
|                     params: (lhs_type.clone(), rhs_type.clone()), |                     params: (lhs_type.clone(), rhs_type.clone()), | ||||||
| @ -433,11 +442,6 @@ impl Expression { | |||||||
|                     *ret_ty = binop.narrow(&lhs_type, &rhs_type).unwrap().2; |                     *ret_ty = binop.narrow(&lhs_type, &rhs_type).unwrap().2; | ||||||
|                     Ok(ret_ty.clone()) |                     Ok(ret_ty.clone()) | ||||||
|                 } else { |                 } else { | ||||||
|                     dbg!(&binops); |  | ||||||
|                     dbg!(&op, &lhs, &rhs); |  | ||||||
|                     dbg!(&lhs_type); |  | ||||||
|                     dbg!(&rhs_type); |  | ||||||
|                     dbg!(&expected_return_ty); |  | ||||||
|                     panic!() |                     panic!() | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| @ -537,7 +541,7 @@ impl Expression { | |||||||
|                 }); |                 }); | ||||||
| 
 | 
 | ||||||
|                 // Typecheck and narrow index-expression
 |                 // Typecheck and narrow index-expression
 | ||||||
|                 let idx_expr_res = idx_expr.typecheck(state, typerefs, Some(&TypeKind::U32)); |                 let idx_expr_res = idx_expr.typecheck(state, typerefs, Some(&TypeKind::Vague(VagueType::Integer))); | ||||||
|                 state.ok(idx_expr_res, idx_expr.1); |                 state.ok(idx_expr_res, idx_expr.1); | ||||||
| 
 | 
 | ||||||
|                 // TODO it could be possible to check length against constants..
 |                 // TODO it could be possible to check length against constants..
 | ||||||
| @ -559,7 +563,7 @@ impl Expression { | |||||||
|             ExprKind::Array(expressions) => { |             ExprKind::Array(expressions) => { | ||||||
|                 // Try to unwrap hint type from array if possible
 |                 // Try to unwrap hint type from array if possible
 | ||||||
|                 let hint_t = hint_t.map(|t| match t { |                 let hint_t = hint_t.map(|t| match t { | ||||||
|                     TypeKind::Array(type_kind, _) => &type_kind, |                     TypeKind::Array(type_kind, _) => type_kind, | ||||||
|                     _ => t, |                     _ => t, | ||||||
|                 }); |                 }); | ||||||
| 
 | 
 | ||||||
| @ -704,7 +708,7 @@ impl Expression { | |||||||
|                 Ok(*inner) |                 Ok(*inner) | ||||||
|             } |             } | ||||||
|             ExprKind::CastTo(expression, type_kind) => { |             ExprKind::CastTo(expression, type_kind) => { | ||||||
|                 let expr = expression.typecheck(state, typerefs, Some(&type_kind))?; |                 let expr = expression.typecheck(state, typerefs, None)?; | ||||||
|                 expr.resolve_ref(typerefs).cast_into(type_kind) |                 expr.resolve_ref(typerefs).cast_into(type_kind) | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -197,6 +197,9 @@ impl Block { | |||||||
|         let mut state = state.inner(); |         let mut state = state.inner(); | ||||||
|         let inner_refs = outer_refs.inner(); |         let inner_refs = outer_refs.inner(); | ||||||
| 
 | 
 | ||||||
|  |         // Keep track of variables created in this scope
 | ||||||
|  |         let mut scope_variables = Vec::new(); | ||||||
|  | 
 | ||||||
|         for statement in &mut self.statements { |         for statement in &mut self.statements { | ||||||
|             match &mut statement.0 { |             match &mut statement.0 { | ||||||
|                 StmtKind::Let(var, mutable, expr) => { |                 StmtKind::Let(var, mutable, expr) => { | ||||||
| @ -217,6 +220,9 @@ impl Block { | |||||||
|                     if let (Some(var_ref), Some(expr_ty_ref)) = (var_ref.as_mut(), expr_ty_ref.as_mut()) { |                     if let (Some(var_ref), Some(expr_ty_ref)) = (var_ref.as_mut(), expr_ty_ref.as_mut()) { | ||||||
|                         var_ref.narrow(&expr_ty_ref); |                         var_ref.narrow(&expr_ty_ref); | ||||||
|                     } |                     } | ||||||
|  | 
 | ||||||
|  |                     // Add variable to list of tracked variables
 | ||||||
|  |                     scope_variables.push(var.clone()); | ||||||
|                 } |                 } | ||||||
|                 StmtKind::Set(lhs, rhs) => { |                 StmtKind::Set(lhs, rhs) => { | ||||||
|                     // Infer hints for the expression itself
 |                     // Infer hints for the expression itself
 | ||||||
| @ -266,6 +272,12 @@ impl Block { | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         // if variables aren't known at this time, they will never be. Default
 | ||||||
|  |         // their types.
 | ||||||
|  |         for variable in scope_variables { | ||||||
|  |             inner_refs.try_default_deep(&variable.0); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         Ok((kind, ret_type_ref)) |         Ok((kind, ret_type_ref)) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -328,15 +340,9 @@ impl Expression { | |||||||
|                         widened_rhs = widened_rhs.widen_into(&binop.hands.1); |                         widened_rhs = widened_rhs.widen_into(&binop.hands.1); | ||||||
|                     } |                     } | ||||||
|                     let binop_res = type_refs.from_binop(*op, &lhs_ref, &rhs_ref); |                     let binop_res = type_refs.from_binop(*op, &lhs_ref, &rhs_ref); | ||||||
|                     dbg!(&type_refs.types.type_refs); |  | ||||||
|                     dbg!(&type_refs.types.hints); |  | ||||||
|                     lhs_ref.narrow(&type_refs.from_type(&widened_lhs).unwrap()); |                     lhs_ref.narrow(&type_refs.from_type(&widened_lhs).unwrap()); | ||||||
|                     rhs_ref.narrow(&type_refs.from_type(&widened_rhs).unwrap()); |                     rhs_ref.narrow(&type_refs.from_type(&widened_rhs).unwrap()); | ||||||
|                     dbg!(&lhs_ref, &rhs_ref); |  | ||||||
|                     *return_ty = binop_res.as_type(); |                     *return_ty = binop_res.as_type(); | ||||||
|                     dbg!(&type_refs.types.hints, &type_refs.types.type_refs); |  | ||||||
|                     dbg!(&return_ty); |  | ||||||
|                     dbg!(&type_refs.from_type(&return_ty)); |  | ||||||
|                     Ok(binop_res) |                     Ok(binop_res) | ||||||
|                 } else { |                 } else { | ||||||
|                     Err(ErrorKind::InvalidBinop( |                     Err(ErrorKind::InvalidBinop( | ||||||
|  | |||||||
| @ -302,6 +302,27 @@ impl<'outer> ScopeTypeRefs<'outer> { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     pub fn try_default_deep(&self, ty: &TypeKind) -> Option<TypeKind> { | ||||||
|  |         Some(match &ty { | ||||||
|  |             TypeKind::Array(type_kind, _) => self.try_default_deep(type_kind)?, | ||||||
|  |             TypeKind::CustomType(_) => ty.clone(), | ||||||
|  |             TypeKind::Borrow(type_kind, _) => self.try_default_deep(type_kind)?, | ||||||
|  |             TypeKind::UserPtr(type_kind) => self.try_default_deep(type_kind)?, | ||||||
|  |             TypeKind::CodegenPtr(type_kind) => self.try_default_deep(type_kind)?, | ||||||
|  |             TypeKind::Vague(vague_type) => match vague_type { | ||||||
|  |                 VagueType::Unknown => ty.clone(), | ||||||
|  |                 VagueType::Integer => ty.or_default().unwrap(), | ||||||
|  |                 VagueType::Decimal => ty.or_default().unwrap(), | ||||||
|  |                 VagueType::TypeRef(idx) => { | ||||||
|  |                     let typeref = TypeRef(Rc::new(RefCell::new(*idx)), self); | ||||||
|  |                     self.narrow_to_type(&typeref, &self.try_default_deep(&typeref.resolve_deep()?)?)? | ||||||
|  |                         .resolve_deep()? | ||||||
|  |                 } | ||||||
|  |             }, | ||||||
|  |             _ => ty.clone(), | ||||||
|  |         }) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     fn combine_vars(&'outer self, hint1: &TypeRef, hint2: &TypeRef) -> Option<TypeRef<'outer>> { |     fn combine_vars(&'outer self, hint1: &TypeRef, hint2: &TypeRef) -> Option<TypeRef<'outer>> { | ||||||
|         unsafe { |         unsafe { | ||||||
|             let ty = self |             let ty = self | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user