123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526 |
- #include "eruta.h"
- #include "area.h"
- #include "tilemap.h"
- #include "bump.h"
- #include "thing.h"
- #include "mem.h"
- #include "flags.h"
- #include "draw.h"
- #include "sprite.h"
- #include "callrb.h"
- #include "monolog.h"
- #include "thing_struct.h"
- /** Scale factor. */
- #define AREA_SCALE_BY (32.0lf)
- /** Scales int by scale factor */
- #define AREA_SCALE_INT(I) ((double)((INT) I)>>5))
- /*
- An area is an in game region that corresponds with a single loaded tile map
- and that keeps track of the physics and location of all in-game objects.
- An area consists of a chipmunk cpSpace that simulates the dynamics,
- and a list of Things, that is, in game objects. It also contains a reference
- to a SpriteList (that is owned by state).
- Division of the data locations: visual and physics engine: in C.
- Logic/game/character data: in scripting engine.
- */
- /* Start with space for 20000 things. */
- #define AREA_THINGS 20000
- struct Area_ {
- BumpWorld * world;
- int lastid;
- Thing * things[AREA_THINGS];
- Thing * things_todraw[AREA_THINGS];
- BumpTilemap * bumpmap;
- int draw_physics;
- };
- /** Gets the amount of possible things for this area */
- int area_maxthings(Area * area) {
- (void) area;
- return AREA_THINGS;
- }
- /** Gets the thing for the given thing ID. */
- Thing * area_thing(Area * area, int index) {
- if (index < 0) return NULL;
- if (index > AREA_THINGS) return NULL;
- if (!area) return NULL;
- return area->things[index];
- }
- /** Sets the thing for the given thing ID. */
- Thing * area_thing_(Area * area, int index, Thing * set) {
- if (index < 0) return NULL;
- if (index > AREA_THINGS) return NULL;
- if (!area) return NULL;
- return area->things[index] = set;
- }
- /** Returns the first unused Thing ID. Internally walks over
- * the known things and finds an empty cell. Returns negative on error. */
- int area_get_unused_thing_id(Area * self) {
- int index, stop;
- if (!self) return -1;
- stop = area_maxthings(self);
- for (index = 0; index < stop; index++) {
- Thing * thing = area_thing(self, index);
- if(!thing) {
- return index;
- }
- }
- return -3;
- }
- /** Puts a thing inside the area. Returns NULL on error.
- returns the thing set if ok. Sets the thing's id to it's
- position in the internal array for things the area has. */
- Thing * area_add_thing(Area * area, int index, Thing * thing) {
- if (!thing) return NULL;
- if (index < 0 ) return NULL;
- if (index > AREA_THINGS) return NULL;
- if(!area_thing_(area, index, thing)) return NULL;
- thing_id_(thing, index);
- /* Set last used id to index if needed */
- if (area->lastid < index) { area->lastid = index; }
- /* Don't forget to add physical body and hull to the space if needed. */
- bumpworld_add_body(area->world, thing->physical);
- bumpworld_add_hull(area->world, thing->hull);
- /* Fix up drawing array. */
- area_update_things(area);
- return thing;
- }
- /** Set the tile map to use for this area. */
- Tilemap *
- area_addmap(Area * area, Tilemap * map) {
- return bumpworld_tilemap_(area->world, map);
- }
- /** Returns the static body that this area uses for static things.
- * Removed, since not needed because bump uses real tile maps and not static bodies.
- */
- /* Removes the thing from the area, but does not deallocate it.
- * Returns thing if sucessful. */
- Thing * area_remove_thing(Area * area, Thing * thing) {
- if (!thing) return NULL;
- if (thing->id<0) return NULL;
- if (thing->kind == THING_UNUSED) return NULL;
- bumpworld_remove_hull(area->world, thing->hull);
- bumpworld_remove_body_only(area->world, thing->physical);
- bumpworld_delete_hulls_for(area->world, thing->physical);
- area_thing_(area, thing->id, NULL);
- /* Fix up drawing array. */
- area_update_things(area);
- return thing;
- }
- /* Removes a thing from the area, selected by ID and deallocates it. */
- int area_delete_thing(Area * area, int index) {
- Thing * thing = area_thing(area, index);
- Thing * del = area_remove_thing(area, thing);
- if(thing && del) {
- thing_free(thing);
- }
-
- return 0;
- }
- /* Cleans up the things of the area */
- Area * area_cleanupthings(Area * self) {
- int index, stop;
- if(!self) return NULL;
- stop = area_maxthings(self);
- for (index= 0; index < stop; index++) {
- area_delete_thing(self, index);
- }
- return self;
- }
- /* Empties the things of an area. Does not destroy them! */
- Area * area_emptythings(Area * self) {
- int index, stop;
- if (!self) return NULL;
- stop = area_maxthings(self);
- for (index= 0; index < stop; index++) {
- area_thing_(self, index, NULL);
- }
- return self;
- }
- /** Deinitializes an area and returns self. */
- Area * area_done(Area * self) {
- if(!self) return self;
- if(!self->world) return self;
- area_cleanupthings(self);
- bumpworld_free(self->world);
- self->world = NULL;
- self->draw_physics = FALSE;
- return self;
- }
- /** Frees an area. Returns NULL. */
- Area * area_free(Area * self) {
- if(area_done(self)) {
- mem_free(self);
- }
- return NULL;
- }
- /** Allocates an area. */
- Area * area_alloc() {
- return STRUCT_ALLOC(Area);
- }
- /** Initializes an area. */
- Area * area_init(Area * self) {
- if(!self) return NULL;
- self->lastid = 0;
- self->world = bumpworld_new();
- if (!self->world) goto out_of_memory;
- area_emptythings(self);
- self->bumpmap = NULL;
- self->draw_physics = FALSE;
- // area_setup_default_collision_handlers(self, self);
- return self;
- out_of_memory:
- area_done(self);
- return NULL;
- }
- /** Updates the things in the area, must be called whan adding or deleting a thing too. */
- void area_update_things(Area * self) {
- int index;
- int subindex = 0;
- /* Empty the draw queue to avoid stale references after deleting a thing
- * or it's physical body. */
- for(index = 0; index < AREA_THINGS; index++) {
- self->things_todraw[index] = NULL;
- }
- for(index = 0; index < AREA_THINGS; index++) {
- Thing * thing = area_thing(self, index);
- if (thing && thing->physical) {
- self->things_todraw[subindex] = thing;
- subindex++;
- }
- }
- /** Sort drawing array so the painter's algorihm can be used. */
- qsort(self->things_todraw, subindex, sizeof(Thing*), thing_compare_for_drawing);
- }
- /** Sets the area so it will draw its physics
- * bounds boxes when it is drawn or not.
- */
- void area_draw_physics_(Area * self, int draw) {
- self->draw_physics = draw;
- }
- /** Checks if the area draws its physics or not. */
- int area_draw_physics(Area * self) {
- return self->draw_physics;
- }
- /** Makes a new area. */
- Area * area_new() {
- return area_init(area_alloc());
- }
- /** Returns the BumpWorld that the area uses for dynamics modelling. */
- BumpWorld * area_world(Area * self) {
- if (!self) return NULL;
- return self->world;
- }
- /** Makes a new thing and adds it to the area. Return it or NULL on error. */
- Thing * area_new_thing(Area * self, int kind,
- int x, int y, int z, int w, int h) {
- Thing * thing;
- int index;
-
- index = area_get_unused_thing_id(self);
- thing = thing_new_dynamic(self, index, kind, x, y, z, w, h);
-
- if (!area_add_thing(self, index, thing)) {
- return thing_free(thing);
- }
- return thing;
- }
- /** Makes a new thing and returns it's ID. */
- int area_new_thing_id(Area * self, int kind, int x, int y, int z, int w, int h) {
- Thing * thing;
- thing = area_new_thing(self, kind, x, y, z, w, h);
- return thing_id(thing);
- }
- /** Sets the current tile map of the area. */
- ERES area_tilemap_(Area * self, Tilemap * map) {
- int wide, high;
- if (map) {
- wide = tilemap_gridwide(map);
- high = tilemap_gridhigh(map);
- } else {
- /* No map so this is whatever, I think. */
- wide = 640;
- high = 480;
- }
- bumpworld_tilemap_(self->world, map);
- return ERES_OK;
- }
- /** Draws all things in an area taking the camera into account. */
- void area_draw(Area * self, Camera * camera) {
- int index;
- for(index = 0; index < (self->lastid + 1); index++) {
- Thing * thing = self->things_todraw[index];
- /* If we encounter a NULL, we're all done drawing. */
- if(!thing) break;
- thing_draw(thing, camera);
- }
- #ifdef ERUTA_DEBUG_DRAW
- bumpworld_draw_debug(self->world);
- #endif
- }
- /** Draws all things in an area taking the camera and layer into account. */
- void area_draw_layer (Area * self, Camera * camera, int layer) {
- int index;
- for (index = 0; index < (self->lastid + 1); index++) {
- Thing * thing = self->things_todraw[index];
- /* If we encounter a NULL, we're all done drawing. */
- if(!thing) break;
- /* Only draw current layer. */
- if(thing_z(thing) != layer) {
- continue;
- }
- thing_draw(thing, camera);
- }
- if (self->draw_physics) {
- bumpworld_draw_debug(self->world);
- }
- }
- /** Updates the area */
- void area_update(Area * self, double dt) {
- int subindex = 0;
- int index;
- bumpworld_update(self->world, dt);
- area_update_things(self);
-
- for(index = 0; index < (self->lastid + 1); index++) {
- Thing * thing = area_thing(self, index);
- /* this is a bandaid, somehow uninitialized things are stored in the area. */
- if (thing && thing->physical) {
- thing_update(thing, dt);
- } else if (thing && (thing->id > AREA_THINGS)) {
- LOG_WARNING("Corrupted thing detected! %p", thing);
- }
- }
- }
- /* Helper for callback wrapper. */
- struct area_find_hulls_helper {
- int (* callback)(Thing * thing, void * extra);
- void * extra;
- };
- /* Callback wrapper. */
- static int area_find_hulls_callback(BumpHull * hull, void * extra) {
- struct area_find_hulls_helper * helper = extra;
- Thing * thing = bumphull_thing(hull);
- if (thing) {
- return helper->callback(thing, helper->extra);
- }
- return 0;
- }
- /** Finds all things in a given rectangle and calls the callback for each of them.
- * Returns 0. If the callback returns nonzero returns this in stead immediately. */
- int area_find_things(Area * self, int x, int y, int w, int h, void * extra,
- int callback(Thing * thing, void * extra)) {
- struct area_find_hulls_helper helper;
- BumpAABB bounds = bumpaabb_make_int(x, y, w, h);
- helper.callback = callback;
- helper.extra = extra;
- return bumpworld_find_hulls(self->world, bounds, &helper, area_find_hulls_callback);
- }
- /* Avoid allocation in the function below. */
- static BumpHull * area_hulls[AREA_THINGS];
- /** Finds all things in a given rectangle and returns
- * up to max_things of them in the array things.
- * Returns the amount of things found or negative on error. */
- int area_find_and_fetch_things(Area * self, int x, int w, int y, int h,
- Thing ** things, int max_things) {
- int index, result;
- BumpAABB bounds = bumpaabb_make_int(x, y, w, h);
- int amount = bumpworld_find_and_fetch_hulls(self->world, bounds, area_hulls, AREA_THINGS);
- int stop = amount;
- if (stop < max_things) stop = max_things;
- result = 0;
- for (index = 0; index < stop; index ++) {
- Thing * thing = bumphull_thing(area_hulls[index]);
- if (thing) {
- things[result] = thing;
- result++;
- }
- }
- return result;
- }
- /** Gets the thing at index index and adds a new hull to it */
- BumpHull * area_add_hull(Area * self, int index, int kind,
- int x, int y, int z, int w, int h) {
- BumpHull * hull;
- Thing * thing;
- BumpAABB aabb = bumpaabb_make_int(x, y, w, h);
- thing = area_thing(self, index);
- return bumpworld_new_hull(self->world, thing->physical, bevec(x,y), aabb, z, kind);
- }
- /* Removes a hull from the area and also from the body it was attached
- * to. */
- Area * area_delete_hull(Area * self, int index) {
- if (bumpworld_delete_hull_index(self->world, index)) return self;
- return NULL;
- }
- /* Removes a body from the area and also all hulls attached to it from the area. */
- Area * area_delete_body(Area * self, int index) {
- if(bumpworld_delete_body_index(self->world, index)) return self;
- return NULL;
- }
- /** Sets a flag on the main hull of the Thing indicated by index. */
- int area_set_thing_hull_flag(Area * me, int index, int flag) {
- Thing * thing;
- if (!me) return 0;
- thing = area_thing(me, index);
- return thing_set_hull_flag(thing, flag);
- }
- /** Unsets a flag for the main hull of the thing. */
- int area_unset_thing_hull_flag(Area * me, int index, int flag) {
- Thing * thing;
- if (!me) return 0;
- thing = area_thing(me, index);
- return thing_unset_hull_flag(thing, flag);
- }
- /** Sets all flags for the main hull of the thing. */
- int area_thing_hull_flags_(Area * me, int index, int flags) {
- Thing * thing;
- if (!me) return 0;
- thing = area_thing(me, index);
- return thing_hull_flags_(thing, flags);
- }
- /** Gets all flags for the main hull of the thing. */
- int area_thing_hull_flags(Area * me, int index) {
- Thing * thing;
- if (!me) return 0;
- thing = area_thing(me, index);
- return thing_hull_flags(thing);
- }
- /** Sets a flag on the hull indicated by index. */
- int area_set_hull_flag(Area * me, int index, int flag) {
- if (!me) return 0;
- return bumpworld_set_hull_flag(me->world, index, flag);
- }
- /** Unsets a flag for the hull indicated by index. */
- int area_unset_hull_flag(Area * me, int index, int flag) {
- if (!me) return 0;
- return bumpworld_unset_hull_flag(me->world, index, flag);
- }
- /** Sets all flags for the hull indicated by index. */
- int area_hull_flags_(Area * me, int index, int flags) {
- if (!me) return 0;
- return bumpworld_hull_flags_(me->world, index, flags);
- }
- /** Gets all flags for the hull indicated by index. */
- int area_hull_flags(Area * me, int index) {
- if (!me) return 0;
- return bumpworld_hull_flags(me->world, index);
- }
- int area_thing_hull_group(Area * me , int index) {
- if (!me) return -1;
- return thing_hull_group(area_thing(me, index));
- }
- int area_thing_hull_group_(Area * me, int index, int group) {
- if (!me) return -1;
- return thing_hull_group_(area_thing(me, index), group);
- }
- /** Returns the thing related to the hull's body, if any.
- * This is in area.c for dependency reasons.
- */
- Thing * bumphull_thing(BumpHull * hull) {
- return bumphull_body_data(hull);
- }
- #define THING_TRACK_DELTA 32.0 * 4
- #ifdef COMMENT_
- /** A tracker function for tracking a Thing. Only works with dynamic things. */
- int thing_track(Tracker * tracker, void * data) {
- Thing * thing = NULL;
- if(!tracker || !tracker->camera) return TRACKER_ERROR;
- thing = (Thing *) tracker->target;
- if(thing_static_p(thing)) return TRACKER_ERROR;
- // TODO: correct with half width and half height
- camera_centerdelta_(tracker->camera, thing_p(thing), THING_TRACK_DELTA);
- return TRACKER_DONE;
- }
- #endif
|