home *** CD-ROM | disk | FTP | other *** search
- /*
- * imagemap.c -- read imagemaps.
- *
- * (c) 1993, 1994 by Han-Wen Nienhuys <hanwen@stack.urc.tue.nl>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
- #include <string.h>
- #include "ray.h"
- #include "proto.h"
- #include "extern.h"
-
- /* save info about previously read maps */
- PRIVATE struct {
- struct pixel_data *pic;
- char *name;
- }
-
- themaps [MAXMAPS];
-
- PRIVATE int nextfree = 0;
-
-
- /* read in a TGA file. */
- PUBLIC struct pixel_data *
- get_TGA_pixels(char *fn)
- {
- FILE *f;
- int header[18];
- long l,
- imsiz;
- int r,
- g,
- b,
- i;
- struct pixel_data *p;
- char *buf;
- byte *cp;
-
- for (i = 0; i < nextfree; i++) {
- if (!strcmp(themaps[i].name, fn))
- return themaps[i].pic;
- }
-
- /* open file, buffer it */
- f = fopen(fn, "rb");
- if (f == NULL)
- errormsg("can't open %s", fn);
-
- printf("(%s", fn);
- buf = (char *) malloc(BUFFERSIZE * sizeof(char));
-
- CHECK_MEM(buf, "buffer");
-
-
- p = ALLOC(struct pixel_data);
-
- CHECK_MEM(p, "pixel data");
-
- if (nextfree < MAXMAPS) {
-
- themaps[nextfree].name = malloc(strlen(fn) + 1);
- CHECK_MEM(themaps[nextfree].name, "file name");
- strcpy(themaps[nextfree].name, fn);
- themaps[nextfree].pic = p;
- nextfree++;
- }
- /* read TGA header */
- for (i = 0; i < 18; i++)
- header[i] = getc(f);
-
- /* check file id */
- if (header[2] != 0x02 || header[16] != 24 || header[17] != 32)
- errormsg("Not a valid TGA!");
-
- /* calc resolution */
- p->imagex = header[12] + header[13] * 256;
- p->imagey = header[14] + header[15] * 256;
-
- p->palsize = 0;
- p->pal = NULL;
- imsiz = p->imagex * p->imagey;
-
- cp = p->data = (char *) malloc(sizeof(byte) * imsiz * 3);
-
- CHECK_MEM(cp, "pixel data");
- if (setvbuf(f, buf, _IOFBF, BUFFERSIZE))
- errormsg("cannot buffer TGA input");
-
-
- for (l = 0; l < imsiz; l++) {
- b = getc(f);
- g = getc(f);
- r = getc(f);
- *cp++ = (byte) r;
- *cp++ = (byte) g;
- *cp++ = (byte) b;
- }
-
- fclose(f);
- free((void *) buf);
- printf(")");
-
- return p;
- }
-
-
- /* read in a GIF file. */
- PUBLIC struct pixel_data *
- get_GIF_pixels(char *fn)
- {
- int i;
- FILE *f;
- struct pixel_data *p;
-
- for (i = 0; i < nextfree; i++) {
- if (!strcmp(themaps[i].name, fn))
- return themaps[i].pic;
- }
-
- p = ALLOC(struct pixel_data);
- CHECK_MEM(p, "pixel data");
-
- if (nextfree < MAXMAPS) {
- themaps[nextfree].name = malloc(strlen(fn) + 1);
- CHECK_MEM(themaps[nextfree].name, "file name");
- strcpy(themaps[nextfree].name, fn);
- themaps[nextfree].pic = p;
- nextfree++;
- }
- f = fopen(fn, "rb");
- if (f == NULL)
- errormsg("can't open %s", fn);
- printf("(%s", fn);
-
-
- load_gif(p, f);
-
- printf(")");
- return p;
- }
-
- /***************************************************************************
- * INVERSE MAPS *
- ***************************************************************************/
-
-
- /*
- * give inverse mapping for point, on sphere centered in 0,0,0
- *
- * z = cos(v * pi), x = cos (u*2pi), y = sin(u*2pi).
- */
- PUBLIC void
- inverse_spheremap(double *u, double *v, vector x)
- {
- norm(x, x);
- *u = acos(x.z) / M_PI;
- *v = safe_arctangent(x.y, x.x) / (2 * M_PI) + 0.5;
- }
-
- /*
- * maps x onto plane.
- */
- PUBLIC void
- inverse_planemap(double *u, double *v, vector x)
- {
- *u = x.x;
- *v = x.y;
- }
-
- /*
- * maps x onto torus in XZ plane, major radius 1.0
- */
- PUBLIC void
- inverse_torusmap(double *u, double *v, vector x)
- {
- double horiz;
-
- *u = safe_arctangent(x.y, x.x) / (2 * M_PI) + 0.5;
- horiz = 1.0 - sqrt(sqr(x.x) + sqr(x.y));
- *v = safe_arctangent(x.y, horiz) / (2 * M_PI) + 0.5;
- }
-
- /*
- * maps x onto a cylinder with axis along the Z-axis.
- */
- PUBLIC void
- inverse_cylindermap(double *u, double *v, vector x)
- {
- *u = safe_arctangent(x.y, x.x) / (2 * M_PI) + 0.5;
- *v = x.z;
- }
-
- /*
- * OTHER STUFF
- */
-
- /* alloc and init an imagemap */
- PUBLIC struct image_map *
- get_new_image_map(void)
- {
- struct image_map *p;
-
- p = ALLOC(struct image_map);
-
- CHECK_MEM(p, "image map");
- p->inv_map = inverse_planemap;
- p->pic = NULL;
- p->u_range = p->v_range = 1.0;
- p->u_offs = p->v_offs = 0.0;
- p->uvswap = p->once = p->interpolated = FALSE;
- p->usenormal = FALSE;
-
- return p;
- }
-
- /* kill imagemap. Don't throw away pixels. */
- PUBLIC void
- free_image_map(struct image_map *p)
- {
- free((void *) p);
- }
-
- PRIVATE color interpolate_pic(struct pixel_data *pic, double u, double v);
- PRIVATE void color_in_pixmap(byte *r, byte *g, byte *b, struct pixel_data *pic, int x, int y);
-
-
- /* lookup the color in an image map. */
- PUBLIC color
- get_image_map_color(struct image_map *p, struct intersect i)
- {
- double u,
- v,
- w;
- byte r,
- g,
- b;
- struct pixel_data *pic;
- color c;
- int x_pix,
- y_pix;
-
-
-
- /* find the u and v for the desired point */
- p->inv_map(&u, &v, i.x);
-
- /* swap them? */
- if (p->uvswap) {
- w = u;
- u = v;
- v = w;
- }
- /* transformations */
- u *= p->u_range;
- v *= p->v_range;
- u -= p->u_offs;
- v -= p->v_offs;
-
- if (p->once && (u < 0.0 || u > 1.0 || v < 0.0 || v > 1.0)) {
- setcolor(c, 0, 0, 0);
- return c;
- }
- /* truncate, only the fractional part remains */
- u -= ceil(u);
- if (u < 0)
- u += 1.0;
-
- v -= ceil(v);
- if (v < 0)
- v += 1.0;
-
- v = 1.0 - v; /* 0,0 is left upper with pictures. */
-
- pic = p->pic;
- if (p->interpolated) {
- c = interpolate_pic(pic, u, v);
- } else {
- x_pix = (u) * pic->imagex;
- y_pix = (v) * pic->imagey;
-
- color_in_pixmap(&r, &g, &b, pic, x_pix, y_pix);
- c.r = r / 255.0;
- c.g = g / 255.0;
- c.b = b / 255.0;
- }
-
- return c;
- }
-
-
- /*
- * Bilinear interpolation (thanks to Advanced Animation and Rendering
- * Techniques by Watt & Watt)
- */
- PRIVATE color
- interpolate_pic(struct pixel_data *pic, double u, double v)
- {
- color up,
- down,
- leftup,
- leftdown,
- rightup,
- rightdown,
- final;
- int right_coord,
- up_coord;
- byte r,
- g,
- b;
- double pixu,
- pixv;
-
- assert(u > 0.0 && v > 0.0 && v < 1.0 && u < 1.0);
-
- /* relative position to pixels */
- pixu = u * (double) pic->imagex;
- pixv = v * (double) pic->imagey;
-
-
- right_coord = ceil(pixu);
- if (right_coord >= pic->imagex)
- right_coord = 0;
-
- up_coord = ceil(pixv);
- if (up_coord >= pic->imagey)
- up_coord = 0;
-
- /* find colors in the corners */
- color_in_pixmap(&r, &g, &b, pic, floor(pixu), up_coord);
- leftup.r = r / 255.0;
- leftup.g = g / 255.0;
- leftup.b = b / 255.0;
-
- color_in_pixmap(&r, &g, &b, pic, floor(pixu), floor(pixv));
- leftdown.r = r / 255.0;
- leftdown.g = g / 255.0;
- leftdown.b = b / 255.0;
-
- color_in_pixmap(&r, &g, &b, pic, right_coord, up_coord);
- rightup.r = r / 255.0;
- rightup.g = g / 255.0;
- rightup.b = b / 255.0;
-
- color_in_pixmap(&r, &g, &b, pic, right_coord, floor(pixv));
- rightdown.r = r / 255.0;
- rightdown.g = g / 255.0;
- rightdown.b = b / 255.0;
-
- /* don't walk off the picture */
- pixu = pixu - ceil(pixu);
- if (pixu < 0.0)
- pixu += 1.0;
-
- pixv = pixv - ceil(pixv);
- if (pixv < 0.0)
- pixv += 1.0;
-
- /* find colors above and below of (u,v) */
- up = color_add(scolorproduct(1.0 - pixu, leftup),
- scolorproduct(pixu, rightup));
- down = color_add(scolorproduct(1.0 - pixu, leftdown),
- scolorproduct(pixu, rightdown));
-
- /* and linearly interpolate them */
- final = color_add(scolorproduct(1.0 - pixv, down),
- scolorproduct(pixv, up));
-
- return final;
- }
-
- /* get a 24 bit color at (x,y) from a pixel data. */
- PRIVATE void
- color_in_pixmap(byte *r, byte *g, byte *b, struct pixel_data *pic, int x, int y)
- {
- byte *bp;
- int offset;
-
- offset = (x + y * pic->imagex) % (pic->imagex * pic->imagey);
-
- if (!pic->palsize) {
- /* no palette, rgb raw data */
- bp = pic->data + 3 * offset;
- } else {
- /* 256 color palette, */
- int palent;
-
- palent = *((byte *) (pic->data) + offset);
- bp = pic->pal + 3 * palent;
- }
-
- *r = *bp++;
- *g = *bp++;
- *b = *bp++;
-
- }
-
-
- /* standard method. */
- PUBLIC void
- copy_image_map(struct image_map *dst, struct image_map *src)
- {
- assert(dst != NULL && src != NULL);
-
- /*
- * the raw pixel data itself is stored only once, so there is no need
- * to copy the pixeldata
- */
- *dst = *src;
- }
-
- /*
- * yepp. another one (Vanessa: "Zie boven... " (chuckle) (never mind) (you
- * won't understand))
- */
- PUBLIC void
- print_image_map(struct image_map *p)
- {
- printf("RES %d x %d\n", p->pic->imagex, p->pic->imagey);
- printf("palsize %d", p->pic->palsize);
- }
-
- /* eof */
-