diff options
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | README.md | 9 | ||||
-rw-r--r-- | gui.hpp | 10 | ||||
-rw-r--r-- | main.cpp | 29 | ||||
-rw-r--r-- | sim.cpp | 91 | ||||
-rw-r--r-- | sim.hpp | 12 |
6 files changed, 147 insertions, 8 deletions
@@ -1,5 +1,5 @@ -WARNINGS=-Wall -Wextra -Wshadow -Wconversion -Wpedantic -pedantic -std=gnu++11 -Wno-unused-function -Wno-fixed-enum-extension -Wimplicit-fallthrough -LIBS=-ldl `pkg-config --libs --cflags box2d sdl2 gl` +WARNINGS=-Wall -Wextra -Wshadow -Wconversion -Wpedantic -pedantic -std=gnu++11 -Wno-unused-function -Wimplicit-fallthrough +LIBS=-ldl `pkg-config --libs --cflags sdl2 gl` -l:libbox2d.a DEBUG_CFLAGS=$(CFLAGS) $(WARNINGS) $(LIBS) -DDEBUG -O0 -g obj/debug: physics obj/sim.so obj touch obj/debug diff --git a/README.md b/README.md new file mode 100644 index 0000000..47c1441 --- /dev/null +++ b/README.md @@ -0,0 +1,9 @@ +To install box2d: +```bash +git clone https://github.com/erincatto/box2d/ +cd box2d +mkdir -p build +cd build +cmake -DBOX2D_BUILD_TESTBED=False .. +sudo make -j8 install +``` @@ -33,9 +33,10 @@ enum { }; typedef u16 Key; -#define MOUSE_LEFT 0 -#define MOUSE_MIDDLE 1 -#define MOUSE_RIGHT 2 +#define MOUSE_OTHER 0 +#define MOUSE_LEFT 1 +#define MOUSE_MIDDLE 2 +#define MOUSE_RIGHT 3 typedef struct { u8 button; @@ -51,6 +52,9 @@ typedef struct { u16 nmouse_presses; #define MAX_MOUSE_PRESSES_PER_FRAME 256 MousePress mouse_presses[MAX_MOUSE_PRESSES_PER_FRAME]; + u16 nmouse_releases; +#define MAX_MOUSE_RELEASES_PER_FRAME MAX_MOUSE_PRESSES_PER_FRAME + MousePress mouse_releases[MAX_MOUSE_RELEASES_PER_FRAME]; i32 mouse_x, mouse_y; // (+y = down) bool shift, ctrl; @@ -267,6 +267,35 @@ int main(void) { Key key = keycode_to_key(event.key.keysym.sym); ++input->keys_released[key]; } break; + case SDL_MOUSEBUTTONDOWN: + case SDL_MOUSEBUTTONUP: { + int x = event.button.x, y = event.button.y; + u8 button = 0; + switch (event.button.button) { + case SDL_BUTTON_LEFT: + button = MOUSE_LEFT; + break; + case SDL_BUTTON_MIDDLE: + button = MOUSE_MIDDLE; + break; + case SDL_BUTTON_RIGHT: + button = MOUSE_RIGHT; + break; + } + MousePress *press = NULL; + if (event.type == SDL_MOUSEBUTTONDOWN) { + if (input->nmouse_presses < MAX_MOUSE_PRESSES_PER_FRAME) + press = &input->mouse_presses[input->nmouse_presses++]; + } else { + if (input->nmouse_releases < MAX_MOUSE_RELEASES_PER_FRAME) + press = &input->mouse_releases[input->nmouse_releases++]; + } + if (press) { + press->button = button; + press->x = x; + press->y = y; + } + } break; case SDL_QUIT: input->closed = true; break; @@ -229,6 +229,18 @@ static void ball_render(State *state) { shader_stop_using(gl); } +static uintptr_t platform_to_user_data(State *state, Platform *platform) { + return USER_DATA_PLATFORM | (uintptr_t)(platform - state->platforms); +} + +static Platform *platform_from_user_data(State *state, uintptr_t user_data) { + if ((user_data & USER_DATA_TYPE) == USER_DATA_PLATFORM) { + uintptr_t index = user_data & USER_DATA_INDEX; + return &state->platforms[index]; + } else { + return NULL; + } +} // sets platform->body to a new Box2D body. static void platform_make_body(State *state, Platform *platform) { @@ -253,6 +265,7 @@ static void platform_make_body(State *state, Platform *platform) { b2FixtureDef fixture; fixture.shape = &shape; fixture.friction = 0.8f; + fixture.userData.pointer = platform_to_user_data(state, platform); body->CreateFixture(&fixture); if (platform->moves) { @@ -267,6 +280,32 @@ static void platform_make_body(State *state, Platform *platform) { platform->body = body; } +class PlatformQueryCallback : public b2QueryCallback { +public: + PlatformQueryCallback(State *state_) { + this->state = state_; + } + bool ReportFixture(b2Fixture *fixture) { + platform = platform_from_user_data(state, fixture->GetUserData().pointer); + return !platform; // if we haven't found a platform, keep going + } + Platform *platform = NULL; + State *state = NULL; +}; + +static Platform *platform_at_mouse_pos(State *state) { + v2 mouse_pos = state->mouse_pos; + v2 mouse_radius = V2(0.3f, 0.3f); // you don't have to hover exactly over a platform to select it. this is the tolerance. + v2 a = v2_sub(mouse_pos, mouse_radius); + v2 b = v2_add(mouse_pos, mouse_radius); + PlatformQueryCallback callback(state); + b2AABB aabb; + aabb.lowerBound = v2_to_b2(a); + aabb.upperBound = v2_to_b2(b); + state->world->QueryAABB(&callback, aabb); + return callback.platform; +} + static void simulate_time(State *state, float dt) { float time_step = 0.01f; // fixed time step dt += state->time_residue; @@ -328,6 +367,25 @@ static void simulate_time(State *state, float dt) { state->time_residue = dt; } +static void platform_delete(State *state, u32 index) { + Platform *platforms = state->platforms; + u32 nplatforms = state->nplatforms; + + state->world->DestroyBody(platforms[index].body); + + if (index+1 < nplatforms) { + // set this platform to last platform + platforms[index] = platforms[nplatforms-1]; + memset(&platforms[nplatforms-1], 0, sizeof(Platform)); + platforms[index].body->GetFixtureList()->GetUserData().pointer = platform_to_user_data(state, &platforms[index]); + } else { + // platform is at end of array; don't need to do anything special + memset(&platforms[index], 0, sizeof(Platform)); + } + --state->nplatforms; + +} + #ifdef __cplusplus extern "C" #endif @@ -506,6 +564,7 @@ void sim_frame(Frame *frame) { } Font *font = &state->font; + Platform *mouse_platform = platform_at_mouse_pos(state); if (state->simulating) { // simulate physics @@ -534,12 +593,42 @@ void sim_frame(Frame *frame) { platform_building->size = clampf(platform_building->size, 0.3f, 10.0f); platform_building->angle = fmodf(platform_building->angle, TAUf); + + for (u32 i = 0; i < input->nmouse_presses; ++i) { + if (input->mouse_presses[i].button == MOUSE_LEFT) { + if (mouse_platform) { + // click to delete platform + platform_delete(state, (u32)(mouse_platform - state->platforms)); + } else { + // left-click to build platform + if (state->nplatforms < MAX_PLATFORMS) { + Platform *p = &state->platforms[state->nplatforms++]; + *p = *platform_building; + p->color |= 0xFF; // set alpha to 255 + platform_make_body(state, p); + } + } + } + } + + if (keys_pressed[KEY_SPACE]) { + state->building = false; + state->simulating = true; + } } + u32 prev_mouse_platform_color = mouse_platform ? mouse_platform->color : 0; + if (state->building) { + // turn platform under mouse red (if user clicks, it will be deleted) + if (mouse_platform) mouse_platform->color = 0xFF0000FF; + } platforms_render(state, state->platforms, state->nplatforms); if (state->building) { - platforms_render(state, &state->platform_building, 1); + if (mouse_platform) + mouse_platform->color = prev_mouse_platform_color; + else + platforms_render(state, &state->platform_building, 1); } ball_render(state); @@ -4,7 +4,7 @@ #if _WIN32 #include <box2d.h> #else -#include <Box2D/Box2D.h> +#include <box2d/box2d.h> #endif #define STBTT_STATIC @@ -150,6 +150,13 @@ typedef struct { b2Body *body; } Ball; +#define USER_DATA_TYPE_SHIFT 12 +#define USER_DATA_TYPE (((uintptr_t)-1) << USER_DATA_TYPE_SHIFT) +#define USER_DATA_INDEX (~USER_DATA_TYPE) +#define USER_DATA_TYPE_PLATFORM ((uintptr_t)0x1) +// indicator that this Box2D fixture is a platform +#define USER_DATA_PLATFORM (USER_DATA_TYPE_PLATFORM << USER_DATA_TYPE_SHIFT) + typedef struct { bool initialized; @@ -185,7 +192,8 @@ typedef struct { float platform_thickness; u32 nplatforms; - Platform platforms[1000]; +#define MAX_PLATFORMS 1000 + Platform platforms[MAX_PLATFORMS]; u32 tmp_mem_used; // this is not measured in bytes, but in MaxAligns #define TMP_MEM_BYTES (4L<<20) |