diff options
author | quou <quou@disroot.org> | 2025-02-07 00:34:44 +1100 |
---|---|---|
committer | quou <quou@disroot.org> | 2025-02-07 00:34:44 +1100 |
commit | 73d7f8325aeb00cbaec89a1c15602b9bd85ff04e (patch) | |
tree | fbef9f89fad53a86882aab0b17a2ff2d7290ad41 | |
parent | 5d09e4f0880b182a2f4c89508744c27823ed554e (diff) |
collision yes/no
-rw-r--r-- | c2.cpp | 13 | ||||
-rw-r--r-- | editor.cpp | 131 | ||||
-rw-r--r-- | editor.hpp | 8 | ||||
-rw-r--r-- | physics.cpp | 200 | ||||
-rw-r--r-- | physics.hpp | 65 | ||||
-rw-r--r-- | testhull.cpp | 152 | ||||
-rw-r--r-- | testsat.cpp | 155 |
7 files changed, 710 insertions, 14 deletions
@@ -742,10 +742,14 @@ struct C2 : public App { box_col = make_box(&asset_arena, v3f(1.0f, 1.0f, 1.0f)); floor_col = make_box(&asset_arena, v3f(10.0f, 0.1f, 10.0f)); box = world->create_entity(); - auto [trans, rb] = world->add<Transform, Rigidbody>(box); + auto [trans, rb, mod] = world->add<Transform, Rigidbody, C_Model>(box); trans.mat = m4f::identity(); rb.init(box_col, v3f(0.0f, 5.0f, 0.0f), quat::identity(), 1.0f); rb.add_force(v3f(0.4f, -1.0f, 0.0f), v3f(0.0f, 0.1f, 0.0f)); + mod.i = scene.instantiate( + dev, + (Model*)assets.load("cube.mdl") + ); floor = world->create_entity(); auto [transf, rbf] = world->add<Transform, Rigidbody>(floor); @@ -781,7 +785,12 @@ struct C2 : public App { if (es.pause_physics) phys_dt = 0.0f; - physics_update(*world, &frame_arena, phys_dt); + physics_update( + *world, + &frame_arena, + phys_dt, + editor_physics_debughook() + ); dev->begin_frame(); lr.begin(w, h); @@ -2,6 +2,7 @@ #include "debugdraw.hpp" #include "editor.hpp" #include "model.hpp" +#include "physics.hpp" #include "scene.hpp" #include "ui.hpp" #include "world.hpp" @@ -11,13 +12,32 @@ extern "C" { #include "plat.h" } +#include <vector> + +struct Editor_PD : Physics_Debughook { + void shrinkwrap( + const Int_Collider* col, + int axis, + const v2f* points, + int count + ) override; + void projection( + const Int_Collider* col, + const v3f& n, + int axis, + const v2f* points, + int count + ) override; +}; + static struct { Editor_Settings settings; + Editor_PD physics_debughook; UI* ui; UI::Toolbar* toolbar; UI::Button* mat_btn, * ent_btn, * phy_btn; UI::Modal* mat_win, * ent_win, * phy_win; - UI::Label* mat_name; + UI::Label* mat_name, * spl; UI::Slider* metalness_input; UI::Slider* roughness_input; UI::Slider* ao_input; @@ -28,8 +48,12 @@ static struct { int selected_mesh; int hovered_axis; int dragging_gizmo; + int debug_sat_axis; v3f drag_axis, drag_off; v3f gf, gu, gr; + std::vector<v2f> shrinkwrap_points; + std::vector<v2f> projection_points; + v3f projection_start, projection_end; } editor; static int mat_win_handler(UI::Element* e, const UI::Message& m) { @@ -215,6 +239,29 @@ static int phy_btn_handler(UI::Element* e, const UI::Message& m) { } return 0; }; + auto csat = ui->create_element<UI::Checkbox>(cont, "Debug SAT"); + csat->set_val(editor.settings.debug_sat); + csat->handler = [](UI::Element* e, const UI::Message& m) { + if (m.type == UI::Message::Type::checkbox_changed) { + UI::Checkbox* ch = (UI::Checkbox*)e; + editor.settings.debug_sat = ch->val; + } + return 0; + }; + int rows[] = { 150, 50, 0 }; + auto tab = ui->create_element<UI::Table>(cont, rows); + ui->create_element<UI::Label>(tab, "Debug Axis"); + auto iaxis = ui->create_element<UI::Int_Input>(tab); + iaxis->set_val(editor.debug_sat_axis); + iaxis->handler = [](UI::Element* e, const UI::Message& m) { + if (m.type == UI::Message::Type::input_finalised) { + UI::Int_Input* i = (UI::Int_Input*)e; + editor.debug_sat_axis = i->val; + } + return 0; + }; + ui->create_element<UI::Label>(tab, "Shrinkwrap"); + editor.spl = ui->create_element<UI::Label>(tab, "0"); } return 0; } @@ -240,6 +287,7 @@ void init_editor(UI* ui, World* world) { editor.mat_win = 0; editor.ent_win = 0; editor.phy_win = 0; + editor.debug_sat_axis = 0; editor.world = world; editor.dragging_gizmo = 0; zero(&editor.settings, sizeof editor.settings); @@ -249,7 +297,7 @@ void deinit_editor() { } void editor_on_select(Entity_Id e, int m) { - if (!editor.ui->hovered) { + if (!editor.ui->hovered && !editor.dragging_gizmo) { editor.selected = e; if (e && editor.world->has<C_Model>(e)) { auto& cm = editor.world->get<C_Model>(e); @@ -300,6 +348,25 @@ void editor_draw(Line_Renderer& lr) { lr.colour(v3f(0.0f, 0.0f, 1.0f)); lr.add_arrow(p, p + r); } + if (w.has<Rigidbody>(e)) { + if (editor.settings.debug_sat) { + lr.colour(v3f(1.0f, 1.0f, 1.0f)); + int i, c = editor.shrinkwrap_points.size(); + for (i = 0; i < c; i++) { + v2f point = editor.shrinkwrap_points[i]; + v2f prev = editor.shrinkwrap_points[(i + 1) % c]; + lr.add_line(v3f(prev, 0.0f), v3f(point, 0.0f)); + } + lr.colour(v3f(1.0f, 0.0f, 0.0f)); + c = editor.projection_points.size(); + for (i = 0; i < c; i++) { + v2f point = editor.projection_points[i]; + lr.add_point(v3f(point, 0.0f)); + } + lr.colour(v3f(1.0f, 0.5f, 1.0f)); + lr.add_arrow(editor.projection_start, editor.projection_end); + } + } } } @@ -332,6 +399,10 @@ void editor_update(const App& app, const Camera& cam) { m.m[3][0] += (gp.x - m.m[3][0]) * editor.drag_axis.x; m.m[3][1] += (gp.y - m.m[3][1]) * editor.drag_axis.y; m.m[3][2] += (gp.z - m.m[3][2]) * editor.drag_axis.z; + if (w.has<Rigidbody>(e)) { + Rigidbody& rb = w.get<Rigidbody>(e); + rb.set_pos(v3f(m.m[3][0], m.m[3][1], m.m[3][2])); + } if (app.mjr(mbtn_left)) editor.dragging_gizmo = 0; return; @@ -383,3 +454,59 @@ void editor_update(const App& app, const Camera& cam) { Editor_Settings& editor_settings() { return editor.settings; } + +Physics_Debughook* editor_physics_debughook() { + return &editor.physics_debughook; +} + +void Editor_PD::shrinkwrap( + const Int_Collider* col, + int axis, + const v2f* points, + int count +) { + World& world = *editor.world; + Entity_Id s = editor.selected; + Rigidbody* rb; + if (!editor.settings.debug_sat) return; + if (!s) return; + if (!world.has<Rigidbody>(s)) return; + rb = &world.get<Rigidbody>(s); + if (axis == editor.debug_sat_axis && col->rb == rb) { + int i; + auto& v = editor.shrinkwrap_points; + v.clear(); + editor.spl->set_int(count); + for (i = 0; i < count; i++) + v.push_back(points[i]); + } +} + +void Editor_PD::projection( + const Int_Collider* col, + const v3f& n, + int axis, + const v2f* points, + int count +) { + World& world = *editor.world; + Entity_Id s = editor.selected; + Rigidbody* rb; + if (!editor.settings.debug_sat) return; + if (!s) return; + if (!world.has<Rigidbody>(s)) return; + rb = &world.get<Rigidbody>(s); + if (axis == editor.debug_sat_axis && col->rb == rb) { + int i; + float w = 1.0f / (float)count; + auto& v = editor.projection_points; + v.clear(); + editor.projection_start = v3f(0.0f); + for (i = 0; i < count; i++) { + const v2f& point = points[i]; + v.push_back(point); + editor.projection_start += v3f(point, 0.0f) * w; + } + editor.projection_end = editor.projection_start + n; + } +} @@ -3,13 +3,15 @@ #include "world.hpp" -struct UI; -struct Model_Instance; struct Line_Renderer; +struct Model_Instance; +struct Physics_Debughook; +struct UI; struct Editor_Settings { bool pause_physics; bool debug_physics; + bool debug_sat; }; void init_editor(UI* ui, World* w); @@ -19,4 +21,6 @@ void editor_update(const App& app, const Camera& cam); void editor_draw(Line_Renderer& lr); Editor_Settings& editor_settings(); +Physics_Debughook* editor_physics_debughook(); + #endif diff --git a/physics.cpp b/physics.cpp index 993b587..0c67747 100644 --- a/physics.cpp +++ b/physics.cpp @@ -5,9 +5,11 @@ extern "C" { #include "memory.h" +#include "plat.h" #include "str.h" } +#include <algorithm> #include <new> void Collider::debug_render( @@ -45,6 +47,8 @@ Int_Collider* Collider::transform(const m4f& t, Arena* a) const { Int_Collider* r = (Int_Collider*)arena_alloc(a, sizeof *r); r->faces = (v3f*)arena_alloc(a, face_count * sizeof *r->faces); r->verts = (v3f*)arena_alloc(a, vert_count * sizeof *r->verts); + r->vert_count = vert_count; + r->face_count = face_count; for (i = 0; i < face_count; i++) r->faces[i] = (t * v4f(faces[i].normal, 0.0f)).xyz(); for (i = 0; i < vert_count; i++) @@ -207,8 +211,160 @@ void physics_tick(World& w, float ts) { } } -bool Int_Collider::collide(const Int_Collider& other) const { - return false; +v2f Int_Collider::Projection::Iter::operator*() { + v3f& pos = p->col->verts[vert]; + return v2f(v3f::dot(p->r, pos), v3f::dot(p->u, pos)); +} + +Int_Collider::Projection Int_Collider::project(const v3f& axis) const { + v3f r = v3f::perp(axis); + v3f u = v3f::cross(r, axis); + return Projection { this, r, u }; +} + +struct Shrinkwrap { + v2f* points; + int count; + Shrinkwrap(Arena* a, v2f* src, int src_count): + count(0) { + int i, top = 0; + int stack_size = src_count; + v2f p0(INFINITY, INFINITY); + v2f* stack = (v2f*)arena_alloc(a, stack_size * sizeof *points); + points = (v2f*)arena_alloc(a, src_count * sizeof *points); + auto push = [&](v2f p) { + assert(top < stack_size); + stack[top++] = p; + }; + auto pop = [&]() { + assert(top); + return stack[--top]; + }; + auto peek = [&](int i) { + assert(top - 1 - i >= 0); + return stack[top - 1 - i]; + }; + auto ccw = [](v2f a, v2f b, v2f c) { + float angle = + (b.y - a.y) * (c.x - b.x) - + (b.x - a.x) * (c.y - b.y); + return angle > -0.00001f; + }; + for (i = 0; i < src_count; i++) { + v2f p = src[i]; + if (p.y < p0.y || (p.y == p0.y && p.x < p0.x)) + p0 = p; + } + std::sort( + src, + src + src_count, + [p0](const v2f& f, const v2f& s) { + float a = + (f.y - p0.y) * (s.x - f.x) - + (f.x - p0.x) * (s.y - f.y); + bool colinear = fabsf(a) < 0.001f; + if (colinear) + return v2f::mag(p0 - s) >= v2f::mag(p0 - f); + return a < 0.0f; + } + ); + for (i = 0; i < src_count; i++) { + v2f p = src[i]; + while (top > 1 && ccw(peek(1), peek(0), p)) + pop(); + push(p); + } + while (top) + points[count++] = pop(); + } + + std::pair<v2f*, int> normals(Arena* a) const { + int c = (count >> 1) + 1, i; + v2f* normals = (v2f*)arena_alloc(a, c * sizeof *normals); + for (i = 0; i < count; i++) { + v2f a = points[i]; + v2f b = points[(i + 1) % count]; + v2f e = a - b; + v2f n = v2f::normalised(v2f(e.y, -e.x)); + normals[i] = n; + } + return { normals, i }; + } + + bool SAT(Arena* a, const Shrinkwrap& other) { + int i; + auto[fn, fnc] = normals(a); + auto[sn, snc] = other.normals(a); + auto project = [](const Shrinkwrap& shape, v2f axis) { + int i; + float mini = INFINITY; + float maxi = -INFINITY; + for (i = 0; i < shape.count; i++) { + const v2f& p = shape.points[i]; + float d = v2f::dot(p, axis); + if (d < mini) mini = d; + if (d > maxi) maxi = d; + } + return std::pair<float, float>{ mini, maxi }; + }; + for (i = 0; i < fnc; i++) { + v2f axis = fn[i]; + auto [fp1, fp2] = project(*this, axis); + auto [sp1, sp2] = project(other, axis); + if (fp2 > sp1 && fp1 > sp2) + return true; + } + for (i = 0; i < snc; i++) { + v2f axis = sn[i]; + auto [fp1, fp2] = project(*this, axis); + auto [sp1, sp2] = project(other, axis); + if (fp2 > sp1 && fp1 > sp2) + return true; + } + return false; + } +}; + +bool Int_Collider::collide( + Physics_Debughook* hook, + Arena* a, + const Int_Collider& other +) const { + auto check_axes = [&]( + const Int_Collider& f, + const Int_Collider& s + ) { + int i, c = s.face_count; + v2f* fp, * sp; + arena_push(a); + fp = (v2f*)arena_alloc(a, sizeof *fp * f.vert_count); + sp = (v2f*)arena_alloc(a, sizeof *sp * s.vert_count); + for (i = 0; i < c; i++) { + const v3f& axis = s.faces[i]; + int fpc = 0, spc = 0; + for (v2f p : f.project(axis)) + fp[fpc++] = p; + for (v2f p : s.project(axis)) + sp[spc++] = p; + Shrinkwrap fwf(a, fp, fpc); + Shrinkwrap swf(a, sp, spc); +#ifdef DEBUG + if (hook) { + hook->projection(&s, axis, i, sp, spc); + hook->projection(&f, axis, i, fp, fpc); + hook->shrinkwrap(&s, i, swf.points, swf.count); + hook->shrinkwrap(&f, i, fwf.points, fwf.count); + } +#endif + if (fwf.SAT(a, swf)) return true; + } + arena_pop(a); + return false; + }; + if (check_axes(*this, other)) return false; + if (check_axes(other, *this)) return false; + (void)hook; + return true; } struct Collision_Engine { @@ -227,12 +383,12 @@ struct Collision_Engine { bodies = b; } } - void detect() { + void detect(Physics_Debughook* hook) { Int_Collider* a; for (a = bodies; a; a = a->next) { Int_Collider* b; for (b = a->next; b; b = b->next) { - if (a->collide(*b)) { + if (a->collide(hook, arena, *b)) { a->rb->colliding = 1; b->rb->colliding = 1; } @@ -241,10 +397,15 @@ struct Collision_Engine { } }; -void physics_update(World& w, Arena* a, float ts) { +void physics_update( + World& w, + Arena* a, + float ts, + Physics_Debughook* hook +) { Collision_Engine ce; ce.init(w, a); - ce.detect(); + ce.detect(hook); physics_tick(w, ts); for (auto v : w.view<Transform, Rigidbody>()) { auto& t = v.get<Transform>(); @@ -272,3 +433,30 @@ void physics_debug(World& w, Line_Renderer& r) { r.add_arrow(rb.pos, rb.pos + rb.torque); } } + +void Physics_Debughook::shrinkwrap( + const Int_Collider* col, + int axis, + const v2f* points, + int count +) { + (void)col; + (void)axis; + (void)points; + (void)count; +} + +void Physics_Debughook::projection( + const Int_Collider* col, + const v3f& n, + int axis, + const v2f* points, + int count +) { + (void)col; + (void)n; + (void)axis; + (void)points; + (void)count; +} + diff --git a/physics.hpp b/physics.hpp index 6e6b259..a800b16 100644 --- a/physics.hpp +++ b/physics.hpp @@ -17,6 +17,23 @@ struct Manifold { v3f normal; }; +struct Int_Collider; +struct Physics_Debughook { + virtual void shrinkwrap( + const Int_Collider* col, + int axis, + const v2f* points, + int count + ); + virtual void projection( + const Int_Collider* col, + const v3f& n, + int axis, + const v2f* points, + int count + ); +}; + struct Rigidbody; struct Int_Collider { Rigidbody* rb; @@ -26,7 +43,46 @@ struct Int_Collider { v3f* verts; v3f* faces; - bool collide(const Int_Collider& other) const; + bool collide( + Physics_Debughook* hook, + Arena* a, + const Int_Collider& other + ) const; + + struct Projection { + const Int_Collider* col; + v3f r, u; + + struct Iter { + const Projection* p; + int vert; + + bool equals(const Iter& other) const { + return vert == other.vert; + } + bool operator==(const Iter& other) const { + return equals(other); + } + bool operator!=(const Iter& other) const { + return !equals(other); + } + Iter operator++() { + vert++; + return *this; + } + v2f operator*(); + }; + + Iter begin() { + return { this, 0 }; + } + + Iter end() { + return { this, col->vert_count }; + } + }; + + Projection project(const v3f& axis) const; }; struct Collider : Asset { @@ -72,7 +128,12 @@ struct Rigidbody { Collider* make_box(Arena* a, const v3f& size); -void physics_update(World& w, Arena* a, float ts); +void physics_update( + World& w, + Arena* a, + float ts, + Physics_Debughook* hook +); void physics_debug(World& w, Line_Renderer& lr); #endif diff --git a/testhull.cpp b/testhull.cpp new file mode 100644 index 0000000..d02f17a --- /dev/null +++ b/testhull.cpp @@ -0,0 +1,152 @@ +#include <SDL2/SDL.h> + +#include <assert.h> +#include <stdlib.h> + +#include "maths.cpp" + +struct Shrinkwrap { + v2f* points; + int count; + v2f p0; + Shrinkwrap(v2f* src, int src_count): + count(0), p0(INFINITY, INFINITY) { + int i, top = 0; + int stack_size = src_count; + v2f* stack = (v2f*)malloc(stack_size * sizeof *stack); + points = (v2f*)malloc(src_count * sizeof *points); + auto push = [&](v2f p) { + assert(top < stack_size); + stack[top++] = p; + }; + auto pop = [&]() { + assert(top > 0); + return stack[--top]; + }; + auto peek = [&](int i) { + assert(top - 1 - i >= 0); + return stack[top - 1 - i]; + }; + auto ccw = [](v2f a, v2f b, v2f c) { + float angle = + (b.y - a.y) * (c.x - b.x) - + (b.x - a.x) * (c.y - b.y); + return angle > -0.00001f; + }; + for (i = 0; i < src_count; i++) { + v2f p = src[i]; + if (p.y < p0.y || (fabsf(p.y - p0.y) < 0.0001f && p.x < p0.x)) + p0 = p; + } + std::sort( + src, + src + src_count, + [this](const v2f& f, const v2f& s) { + float a = + (f.y - p0.y) * (s.x - f.x) - + (f.x - p0.x) * (s.y - f.y); + bool colinear = fabsf(a - 0.0f) < 0.001f; + if (colinear) + return v2f::mag(p0 - s) >= v2f::mag(p0 - f); + return a < 0.0f; + } + ); + for (i = 0; i < src_count; i++) { + v2f p = src[i]; + while (top > 1 && ccw(peek(1), peek(0), p)) + pop(); + push(p); + } + while (top) + points[count++] = pop(); + free(stack); + } +}; + +int main(int argc, const char** argv) { + int r = 1; + float rot = 3.5f; + SDL_Window* window; + SDL_Renderer* ren; + SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK); + SDL_CreateWindowAndRenderer( + 800, + 800, + 0, + &window, + &ren + ); + v2f points[] = { + { 129.0f, 148.0f }, + { 178.0f, 178.0f }, + { 146.0f, 146.0f }, + { 163.0f, 172.0f }, + { 129.0f, 159.0f }, + { 102.0f, 151.0f }, + { 167.0f, 122.0f } + }; + float rots[] = { + 0.0f, + 1.0f, + 1.0f, + 1.0f, + 0.0f, + 1.0f, + 0.0f, + }; + constexpr int point_count = sizeof points / sizeof *points; + v2f points2[point_count]; + while (r) { + int i; + SDL_Event e; + while (SDL_PollEvent(&e)) { + switch (e.type) { + case SDL_QUIT: + r = 0; + break; + } + } + for (i = 0; i < point_count; i++) { + v2f p = points[i]; + points2[i] = v2f( + p.x * 2 + (sinf(rot * rots[i]) * p.x - cosf(rot * rots[i]) * p.y), + p.y * 2 + (sinf(rot * rots[i]) * p.x + cosf(rot * rots[i]) * p.y) + ); + } + Shrinkwrap s(points2, point_count); + SDL_SetRenderDrawColor(ren, 0x00, 0x00, 0x00, 0x00); + SDL_RenderClear(ren); + for (int i = 0; i < s.count; i++) { + v2f a = s.points[i]; + v2f b = s.points[(i + 1) % s.count]; + v2f e = a - b; + v2f h = e * 0.5f; + v2f n = v2f(e.y, -e.x); + n = v2f::normalised(n); + SDL_SetRenderDrawColor(ren, 0x00, 0x00, 0xff, 0xff); + SDL_RenderDrawLine(ren, (int)a.x, (int)a.y, (int)b.x, (int)b.y); + SDL_SetRenderDrawColor(ren, 0xff, 0x00, 0xff, 0xff); + SDL_RenderDrawLine( + ren, + (int)(a.x - h.x), + (int)(a.y - h.y), + (int)((a.x - h.x) + n.x * 32.0f), + (int)((a.y - h.y) + n.y * 32.0f) + ); + } + SDL_SetRenderDrawColor(ren, 0xff, 0x00, 0x00, 0xff); + for (i = 0; i < point_count; i++) { + v2f p = points2[i]; + SDL_RenderDrawPoint(ren, (int)p.x, (int)p.y); + } + SDL_SetRenderDrawColor(ren, 0x00, 0xff, 0x00, 0xff); + SDL_RenderDrawPoint(ren, (int)s.p0.x, (int)s.p0.y); + SDL_RenderPresent(ren); + free(s.points); + rot += 0.0003f; + } + SDL_DestroyRenderer(ren); + SDL_DestroyWindow(window); + SDL_Quit(); + return 0; +} diff --git a/testsat.cpp b/testsat.cpp new file mode 100644 index 0000000..45f3891 --- /dev/null +++ b/testsat.cpp @@ -0,0 +1,155 @@ +#include <SDL2/SDL.h> + +#include <assert.h> +#include <stdlib.h> + +#include "maths.cpp" + +struct Shape { + v2f* points; + int count; + + Shape(std::initializer_list<v2f> in) { + int i; + points = (v2f*)malloc(in.size() * sizeof *points); + count = in.size(); + for (i = 0; i < count; i++) + points[i] = *(in.begin() + i); + } + + Shape(const Shape& other) { + int s = other.count * sizeof *points; + count = other.count; + points = (v2f*)malloc(s); + memcpy(points, other.points, s); + } + + ~Shape() { + free(points); + } + + void render(SDL_Renderer* ren) { + int i, c = count; + for (i = 0; i < c; i++) { + v2f a = points[i]; + v2f b = points[(i + 1) % c]; + SDL_RenderDrawLine( + ren, + (int)a.x, + (int)a.y, + (int)b.x, + (int)b.y + ); + } + } + + std::pair<v2f*, int> normals() const { + int c = (count >> 1) + 1, i; + v2f* normals = (v2f*)malloc(c * sizeof *normals); + for (i = 0; i < count; i++) { + v2f a = points[i]; + v2f b = points[(i + 1) % count]; + v2f e = a - b; + v2f n = v2f::normalised(v2f(e.y, -e.x)); + normals[i] = n; + } + return { normals, i }; + } +}; + +bool intersect(Shape& a, Shape& b) { + bool r = true; + int i; + auto[fn, fnc] = a.normals(); + auto[sn, snc] = b.normals(); + auto project = [](const Shape& shape, v2f axis) { + int i; + float mini = INFINITY; + float maxi = -INFINITY; + for (i = 0; i < shape.count; i++) { + v2f p = shape.points[i]; + float d = v2f::dot(p, axis); + if (d < mini) mini = d; + if (d > maxi) maxi = d; + } + return std::pair<float, float>{ mini, maxi }; + }; + for (i = 0; i < fnc; i++) { + v2f axis = fn[i]; + auto [fp1, fp2] = project(a, axis); + auto [sp1, sp2] = project(b, axis); + if (fp2 > sp1 && fp1 > sp2) { + r = false; + goto end; + } + } + for (i = 0; i < snc; i++) { + v2f axis = sn[i]; + auto [fp1, fp2] = project(a, axis); + auto [sp1, sp2] = project(b, axis); + if (fp2 > sp1 && fp1 > sp2) { + r = false; + goto end; + } + } +end: + free(fn); + free(sn); + return r; +} + +int main(int argc, const char** argv) { + int r = 1; + SDL_Window* window; + SDL_Renderer* ren; + SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK); + SDL_CreateWindowAndRenderer( + 800, + 800, + 0, + &window, + &ren + ); + Shape a({ + v2f(300.0f, 300.0f), + v2f(400.0f, 400.0f), + v2f(250.0f, 500.0f), + }); + Shape tri({ + v2f(0.0f, 0.0f), + v2f(50.0f, 200.0f), + v2f(200.0f, 100.0f), + }); + while (r) { + int i; + SDL_Event e; + while (SDL_PollEvent(&e)) { + switch (e.type) { + case SDL_QUIT: + r = 0; + break; + } + } + int mx, my; + SDL_GetMouseState(&mx, &my); + Shape b(tri); + for (i = 0; i < b.count; i++) { + v2f& p = b.points[i]; + p.x += mx; + p.y += my; + } + SDL_SetRenderDrawColor(ren, 0x00, 0x00, 0x00, 0x00); + SDL_RenderClear(ren); + SDL_SetRenderDrawColor(ren, 0xff, 0x00, 0xff, 0xff); + a.render(ren); + if (intersect(a, b)) { + SDL_SetRenderDrawColor(ren, 0xff, 0x00, 0x00, 0xff); + } + b.render(ren); + SDL_RenderPresent(ren); + } + SDL_DestroyRenderer(ren); + SDL_DestroyWindow(window); + SDL_Quit(); + return 0; +} |