X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?a=blobdiff_plain;f=src%2Fscene.c;h=36c9fba9aa0851eda4d5d903e7e62a00f9394dc7;hb=3bf187fe037df34459f04bf4e625f38afb80fcf8;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;
}