X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?a=blobdiff_plain;f=src%2Fscene.c;h=36c9fba9aa0851eda4d5d903e7e62a00f9394dc7;hb=86aa9bdd85243207bbd7e888d73c2b865d805265;hp=4f78861d6526e07258390ccd757f7a8ea553d843;hpb=f0f09a5f3f76fd4207e4d2d71f29f876b2b379f7;p=retroray diff --git a/src/scene.c b/src/scene.c index 4f78861..36c9fba 100644 --- a/src/scene.c +++ b/src/scene.c @@ -16,10 +16,14 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include +#include #include "scene.h" +#include "geom.h" #include "darray.h" #include "logger.h" +static struct material *default_material(void); + struct scene *create_scene(void) { struct scene *scn; @@ -29,7 +33,8 @@ struct scene *create_scene(void) return 0; } scn->objects = darr_alloc(0, sizeof *scn->objects); - + scn->lights = darr_alloc(0, sizeof *scn->lights); + scn->mtl = darr_alloc(0, sizeof *scn->mtl); return scn; } @@ -43,6 +48,18 @@ void free_scene(struct scene *scn) free_object(scn->objects[i]); } darr_free(scn->objects); + + for(i=0; ilights); i++) { + free_light(scn->lights[i]); + } + darr_free(scn->lights); + + for(i=0; imtl); i++) { + mtl_destroy(scn->mtl[i]); + free(scn->mtl[i]); + } + darr_free(scn->mtl); + free(scn); } @@ -52,11 +69,177 @@ int scn_add_object(struct scene *scn, struct object *obj) return 0; } -int scn_num_objects(struct scene *scn) +int scn_rm_object(struct scene *scn, int idx) +{ + int numobj = darr_size(scn->objects); + + if(idx < 0 || idx >= numobj) { + return -1; + } + + free_object(scn->objects[idx]); + + if(idx < numobj - 1) { + scn->objects[idx] = scn->objects[numobj - 1]; + } + darr_pop(scn->objects); + return 0; +} + +int scn_num_objects(const struct scene *scn) { return darr_size(scn->objects); } +int scn_object_index(const struct scene *scn, const struct object *obj) +{ + int i, num = darr_size(scn->objects); + for(i=0; iobjects[i] == obj) { + return i; + } + } + return -1; +} + + + +int scn_add_material(struct scene *scn, struct material *mtl) +{ + darr_push(scn->mtl, &mtl); + return 0; +} + +int scn_rm_material(struct scene *scn, struct material *mtl) +{ + int idx, num_mtl; + + if((idx = scn_material_index(scn, mtl)) == -1) { + return -1; + } + + num_mtl = darr_size(scn->mtl); + + if(idx < num_mtl - 1) { + scn->mtl[idx] = scn->mtl[num_mtl - 1]; + } + darr_pop(scn->mtl); + return 0; +} + +int scn_num_materials(const struct scene *scn) +{ + return darr_size(scn->mtl); +} + +int scn_material_index(const struct scene *scn, const struct material *mtl) +{ + int i, num_mtl; + + num_mtl = darr_size(scn->mtl); + for(i=0; imtl[i] == mtl) { + return i; + } + } + return -1; +} + +struct material *scn_find_material(const struct scene *scn, const char *mname) +{ + int i, num_mtl; + + num_mtl = darr_size(scn->mtl); + for(i=0; imtl[i]->name, mname) == 0) { + return scn->mtl[i]; + } + } + return 0; +} + +/* manage lights */ + +int scn_add_light(struct scene *scn, struct light *light) +{ + darr_push(scn->lights, &light); + return 0; +} + +int scn_rm_light(struct scene *scn, struct light *light) +{ + int idx, num_lights; + + if((idx = scn_light_index(scn, light)) == -1) { + return -1; + } + + num_lights = darr_size(scn->lights); + + if(idx < num_lights - 1) { + scn->lights[idx] = scn->lights[num_lights - 1]; + } + darr_pop(scn->lights); + return 0; +} + +int scn_num_lights(const struct scene *scn) +{ + return darr_size(scn->lights); +} + +int scn_light_index(const struct scene *scn, const struct light *light) +{ + int i, num_lights; + + num_lights = darr_size(scn->lights); + for(i=0; ilights[i] == light) { + return i; + } + } + return -1; +} + +struct light *scn_find_light(const struct scene *scn, const char *mname) +{ + int i, num_lights; + + num_lights = darr_size(scn->lights); + for(i=0; ilights[i]->name, mname) == 0) { + return scn->lights[i]; + } + } + return 0; +} + + +int scn_intersect(const struct scene *scn, const cgm_ray *ray, struct rayhit *hit) +{ + int i, numobj; + struct rayhit hit0, tmphit; + + hit0.t = FLT_MAX; + hit0.obj = 0; + + numobj = darr_size(scn->objects); + for(i=0; iobjects[i], &tmphit) && tmphit.t < hit0.t) { + hit0 = tmphit; + } + } + + if(hit0.obj) { + if(hit) *hit = hit0; + return 1; + } + return 0; +} + + +/* --- object functions --- */ + struct object *create_object(int type) { struct object *obj; @@ -64,33 +247,42 @@ struct object *create_object(int type) char buf[32]; static int objid; - if(!(obj = malloc(sizeof *obj))) { - errormsg("failed to allocate object\n"); - return 0; - } - obj->type = type; - - cgm_vcons(&obj->pos, 0, 0, 0); - cgm_qcons(&obj->rot, 0, 0, 0, 1); - cgm_vcons(&obj->scale, 1, 1, 1); - cgm_vcons(&obj->pivot, 0, 0, 0); - cgm_midentity(obj->xform); - switch(type) { case OBJ_SPHERE: + if(!(obj = calloc(1, sizeof *sph))) { + goto err; + } sph = (struct sphere*)obj; sph->rad = 1.0f; sprintf(buf, "sphere%03d", objid); break; default: + if(!(obj = calloc(1, sizeof *obj))) { + goto err; + } sprintf(buf, "object%03d", objid); break; } + obj->type = type; + + cgm_vcons(&obj->pos, 0, 0, 0); + cgm_qcons(&obj->rot, 0, 0, 0, 1); + cgm_vcons(&obj->scale, 1, 1, 1); + cgm_vcons(&obj->pivot, 0, 0, 0); + cgm_midentity(obj->xform); + cgm_midentity(obj->inv_xform); + obj->xform_valid = 1; + obj->mtl = default_material(); + set_object_name(obj, buf); objid++; return obj; + +err: + errormsg("failed to allocate object\n"); + return 0; } void free_object(struct object *obj) @@ -131,6 +323,72 @@ void calc_object_matrix(struct object *obj) mat[2] *= obj->scale.x; mat[6] *= obj->scale.y; mat[10] *= obj->scale.z; mat[14] += obj->pos.z; cgm_mpretranslate(mat, -obj->pivot.x, -obj->pivot.y, -obj->pivot.z); - /* that's basically: pivot * rotation * translation * scaling * -pivot */ + + cgm_mcopy(obj->inv_xform, mat); + cgm_minverse(obj->inv_xform); + + obj->xform_valid = 1; +} + +/* --- lights --- */ +struct light *create_light(void) +{ + struct light *lt; + static int ltidx; + char buf[64]; + + if(!(lt = malloc(sizeof *lt))) { + return 0; + } + cgm_vcons(<->pos, 0, 0, 0); + + set_light_color(lt, 1, 1, 1); + set_light_energy(lt, 1); + + sprintf(buf, "light%03d", ltidx++); + set_light_name(lt, buf); + + return lt; +} + +void free_light(struct light *lt) +{ + if(!lt) return; + free(lt->name); + free(lt); +} + +int set_light_name(struct light *lt, const char *name) +{ + char *tmp = strdup(name); + if(!tmp) return -1; + free(lt->name); + lt->name = tmp; + return 0; +} + +void set_light_color(struct light *lt, float r, float g, float b) +{ + cgm_vcons(<->orig_color, r, g, b); + lt->color = lt->orig_color; + cgm_vscale(<->color, lt->energy); +} + +void set_light_energy(struct light *lt, float e) +{ + lt->energy = e; + lt->color = lt->orig_color; + cgm_vscale(<->color, e); +} + +static struct material *default_material(void) +{ + static struct material defmtl; + + if(!defmtl.name) { + mtl_init(&defmtl); + mtl_set_name(&defmtl, "default_mtl"); + } + return &defmtl; }