#import "Basic"; #import "Math"; #import "Window_Creation"; Input :: #import "Input"; Simp :: #import "Simp"; TIMESTEP: float = 1.0 / 60.0; window_width : s32 = 1280; window_height : s32 = 720; xy :: (x: int, y: int) -> Vector2 { return xy(cast(float)x, cast(float)y); } drawing_in_world_space: bool = false; WHITE :: Vector4.{1.0, 1.0, 1.0, 1.0}; GREEN :: Vector4.{0.0, 1.0, 0.0, 1.0}; drawing_color: Vector4 = WHITE; line_thickness: float = 1.0; line :: (_from: Vector2, _to: Vector2) { width := line_thickness; from := _from; to := _to; if drawing_in_world_space { from = world_to_screen(from); to = world_to_screen(to); } Simp.set_shader_for_color(); normal := rotate(unit_vector(to - from), PI/2.0); Simp.immediate_quad(from + normal*width, from - normal*width, to + normal*width, to - normal*width, color = drawing_color); } Rect :: struct { halfsize: Vector2; pos , vel , force : Vector2; // pos is in world space angle, angle_vel, torque: float; }; MASS :: 1.0; moment_of_inertia :: (using r: Rect) -> float { return MASS*(halfsize.y*halfsize.y + halfsize.x*halfsize.x)/12.0; } apply_force_at_point :: (r: *Rect, force: Vector2, point_world_space: Vector2) { r.force += force; offset_from_center_of_mass := point_world_space - r.pos; r.torque += offset_from_center_of_mass.x * force.y - offset_from_center_of_mass.y * force.x; } Manifold :: struct { count: int; depths: [2] float; contact_points: [2] Vector2; normal: Vector2; }; MAX_POLYGON_VERTS :: 8; Polygon :: struct { count: int; verts: [MAX_POLYGON_VERTS] Vector2; norms: [MAX_POLYGON_VERTS] Vector2; }; // a halfspace (aka plane, aka line) Halfspace :: struct { n: Vector2; d: float; } poly_from :: (using r: Rect) -> Polygon { to_return: Polygon; facing_to_right := rotate(xy(halfsize.x,0.0), angle); facing_to_up := rotate(xy(0.0,halfsize.y), angle); to_return.count = 4; to_return.verts[0] = -facing_to_right + facing_up; // upper left to_return.norms[0] = #run normalize(xy(-1.0, 1.0)); to_return.verts[1] = facing_to_right + facing_up; // upper right to_return.norms[1] = #run normalize(xy(1.0, 1.0)); to_return.verts[2] = facing_to_right + -facing_up; // lower right to_return.norms[2] = #run normalize(xy(1.0, -1.0)); to_return.verts[3] = -facing_to_right + -facing_up; // lower left to_return.norms[3] = #run normalize(xy(-1.0, -1.0)); return to_return; } rect_to_rect :: (a: Rect, b: Rect) -> Manifold { to_return : Manifold; check_faces :: (a: Polygon, b: Polygon) -> float { plane_at :: (p : Polygon, i: int) -> Halfspace { return .{n = p.norms[i], d = dot(p.norms[i], p.verts[i]}; } support :: (verts: [] Vector2, d: Vector2 { } sep : float = FLT_MAX; index: int = ~0; for 0..a.count-1 { h := plane_at(a, i); idx := } } } draw_rect :: (using r: Rect) { facing_to_right := rotate(xy(halfsize.x,0.0), angle); facing_to_up := rotate(xy(0.0,halfsize.y), angle); upper_right := pos + facing_to_right + facing_to_up; upper_left := pos - facing_to_right + facing_to_up; lower_left := pos - facing_to_right - facing_to_up; lower_right := pos + facing_to_right - facing_to_up; line(upper_left, upper_right); line(upper_right, lower_right); line(lower_right, lower_left); line(lower_left, upper_left); } mouse :: () -> Vector2 { x, y := get_mouse_pointer_position(); pos: Vector2 = xy(cast(float)x, cast(float)y); // simp is lower left is (0, 0) and y+ is up pos.y = window_height - pos.y; return pos; } Camera :: struct { pos: Vector2; zoom: float = 1.0; }; camera : Camera; screen_to_world :: (screen: Vector2) -> Vector2 { using camera; return (screen + pos)*zoom; } world_to_screen :: (world: Vector2) -> Vector2 { using camera; // world = (screen + pos)*zoom; // world/zoom = screen + pos; // world/zoom - pos = screen; return (world/zoom) - pos; } main :: () { window := create_window(window_width, window_height, "A Window"); // Actual render size in pixels can be different from the window dimensions we specified above (for example on high-resolution displays on macOS/iOS). window_width, window_height = Simp.get_render_dimensions(window); camera.pos = -xy(window_width, window_height)/2.0; camera.zoom = 0.01; Simp.set_render_target(window); rects: [..]Rect; array_add(*rects, .{pos = #run xy(0.0, 0.0), halfsize = #run xy(0.3)}); array_add(*rects, .{pos = #run xy(2.5, 0.0), halfsize = #run xy(0.3)}); quit := false; last_time := get_time(); panning: bool = false; last_mouse_pos := mouse(); unprocessed_time: float = 0.0; while !quit { dt := cast(float)(get_time() - last_time); last_time = get_time(); Input.update_window_events(); mouse_delta := mouse() - last_mouse_pos; // using Input.mouse_delta_x seems to incorrectly accumulate last_mouse_pos = mouse(); for Input.get_window_resizes() { Simp.update_window(it.window); // Simp will do nothing if it doesn't care about this window. if it.window == window { should_reinit := (it.width != window_width) || (it.height != window_height); window_width = it.width; window_height = it.height; //if should_reinit my_init_fonts(); // Resize the font for the new window size. } } camera.zoom *= 1.0 - 0.1*Input.mouse_delta_z/120.0; if panning { camera.pos -= mouse_delta; // this doesn't fix it //Input.mouse_delta_x = 0; //Input.mouse_delta_y = 0; } // process physics unprocessed_time += dt; { dt: string = "do not use"; while unprocessed_time > TIMESTEP { defer unprocessed_time -= TIMESTEP; if get_time() < 0.5 { apply_force_at_point(*rects[0], xy(3, 0), rects[0].pos + xy(-0.1, 0.03)); } for * rects { defer { it.force = .{}; it.torque = 0.0; }; it.vel += (it.force/MASS) * TIMESTEP; it.pos += it.vel * TIMESTEP; it.angle_vel += (it.torque / moment_of_inertia(it)) * TIMESTEP; it.angle += it.angle_vel * TIMESTEP; } } } Simp.clear_render_target(0.0, 0.0, 0.0, 1.0); drawing_in_world_space = true; // draw grid drawing_color = .{0.2, 0.2, 0.2, 0.2}; for x: -30..30 { line(xy(x, 30), xy(x, -30)); } for y: -30..30 { line(xy(30, y), xy(-30, y)); } drawing_color = WHITE; line_thickness = 2.0; drawing_color = GREEN; for rects draw_rect(it); line_thickness = 1.0; drawing_color = WHITE; //line(xy(0.0, 0.0), screen_to_world(mouse())); drawing_in_world_space = false; Simp.swap_buffers(window); for Input.events_this_frame { if it.type == .QUIT then quit = true; if it.type == { case .KEYBOARD; if it.key_pressed && it.key_code == .ESCAPE { quit = true; } if it.key_code == .MOUSE_BUTTON_LEFT { panning = cast(bool)it.key_pressed; } } } } }