home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Resource Library: Graphics
/
graphics-16000.iso
/
msdos
/
raytrace
/
rayshade
/
src
/
picture.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-05-01
|
12KB
|
499 lines
/*
* picture.c
*
* Copyright (C) 1989, 1991, Craig E. Kolb, Rod G. Bogart
* All rights reserved.
*
* This software may be freely copied, modified, and redistributed
* provided that this copyright notice is preserved on all copies.
*
* You may not distribute this software, in whole or in part, as part of
* any commercial product without the express consent of the authors.
*
* There is no warranty or other guarantee of fitness of this software
* for any purpose. It is provided solely "as is".
*
* $Id: picture.c,v 4.0.1.2 92/02/07 09:22:20 cek Exp Locker: cek $
*
* $Log: picture.c,v $
* Revision 4.0.1.2 92/02/07 09:22:20 cek
* patch6: Fixed typo in MTV error message.
*
* Revision 4.0.1.1 92/01/10 16:28:28 cek
* patch3: Added check for nonexistent patial image file.
* patch3: Fixed declaration of nrow in count_rle_rows().
* patch3: Changed level of several error messages.
*
* Revision 4.0 91/07/17 14:47:00 kolb
* Initial version.
*
*/
#include "rayshade.h"
#include "picture.h"
#include "viewing.h"
#include "options.h"
#include "stats.h"
#if defined(__WATCOMC__) || defined(__BORLANDC__)
#include <io.h>
#include <fcntl.h>
#undef URT
#define TARGA
#endif
#ifdef URT
unsigned char **outptr; /* Output buffer */
static int count_rle_rows();
#endif
/*
* Convert floating-point (0.-1.) to unsigned char (0-255), with no gamma
* correction.
*/
unsigned char
correct(x)
Float x;
{
/*
* Truncate values < 0 or > 1.
*/
if (x < 0)
return 0;
if (x > 1.)
return 255;
return (unsigned char)(x * 255.);
}
#ifdef URT
/*
* Open image file and write RLE header.
*/
void
PictureStart(argv)
char **argv;
{
char gammacom[40];
if (Options.framenum != Options.startframe) {
/*
* We've been here before;
* write a new header and return.
*/
rle_put_setup(&rle_dflt_hdr);
return;
}
/*
* If Appending, then we know that outfile is valid, 'cause
* we've already read its header.
*/
if (Options.appending) {
#if defined(__WATCOMC__) || defined(__BORLANDC__)
Options.pictfile = fopen(Options.imgname, "ab");
#else
Options.pictfile = fopen(Options.imgname, "a");
#endif
if (Options.pictfile == (FILE *)0)
RLerror(RL_PANIC, "Cannot append to %s?!\n",
Options.imgname);
rle_dflt_hdr.rle_file = Options.pictfile;
rle_put_init(&rle_dflt_hdr);
} else {
/*
* Starting image from scatch.
*/
if (Options.imgname) {
#if defined(__WATCOMC__) || defined(__BORLANDC__)
Options.pictfile = fopen(Options.imgname, "wb");
#else
Options.pictfile = fopen(Options.imgname, "w");
#endif
if (Options.pictfile == (FILE *)NULL)
RLerror(RL_ABORT,"Cannot open %s for writing.",
Options.imgname);
} else
Options.pictfile = stdout;
rle_dflt_hdr.xmax = Screen.maxx;
rle_dflt_hdr.ymax = Screen.maxy;
rle_dflt_hdr.xmin = Screen.minx;
rle_dflt_hdr.ymin = Screen.miny;
rle_dflt_hdr.alpha = Options.alpha;
if (Options.alpha)
RLE_SET_BIT(rle_dflt_hdr, RLE_ALPHA);
if (Options.exp_output) {
RLE_SET_BIT(rle_dflt_hdr, RLE_BLUE + 1);
rle_dflt_hdr.ncolors = 4;
rle_putcom("exponential_data", &rle_dflt_hdr);
}
else
rle_dflt_hdr.ncolors = 3;
/*
* Document image gamma in RLE comment area.
* Options.gamma has been inverted.
*/
(void)sprintf(gammacom, "display_gamma=%g", 1./Options.gamma);
rle_putcom(gammacom, &rle_dflt_hdr);
/*
* Document command line in RLE history.
*/
rle_addhist(argv, (rle_hdr *)0, &rle_dflt_hdr);
rle_dflt_hdr.rle_file = Options.pictfile;
rle_put_setup(&rle_dflt_hdr);
/*
* Flush the header. If we don't, and LINDA forks off
* a bunch of workers, strange things will happen (they'll
* all flush the buffer when they die, and you end up with
* lots of headers at the end of the file).
*/
(void)fflush(rle_dflt_hdr.rle_file);
}
if (rle_row_alloc(&rle_dflt_hdr, &outptr) < 0)
RLerror(RL_PANIC, "Unable to allocate image memory.\n");
}
/*
* Read RLE header to which we are appending in order determine
* old resolution, window location, and the like.
*/
void
PictureSetWindow()
{
if (Options.imgname == (char *)NULL)
RLerror(RL_ABORT,
"No partially-completed image file specified.\n");
/*
* Open image and read RLE header.
*/
#if defined(__WATCOMC__) || defined(__BORLANDC__)
Options.pictfile = fopen(Options.imgname, "rb");
#else
Options.pictfile = fopen(Options.imgname, "r");
#endif
if (Options.pictfile == (FILE *)NULL) {
RLerror(RL_ABORT, "Cannot open image file %s.\n",
Options.imgname);
}
rle_dflt_hdr.rle_file = Options.pictfile;
rle_get_setup_ok(&rle_dflt_hdr, "rayshade", Options.imgname);
/*
* If user specified a window that does not match what's in
* the header, complain.
if (Screen.minx != UNSET && Screen.minx != rle_dflt_hdr.xmin ||
Screen.miny != UNSET && Screen.miny != rle_dflt_hdr.ymin ||
Screen.maxx != UNSET && Screen.maxx != rle_dflt_hdr.xmax ||
Screen.maxy != UNSET && Screen.maxy != rle_dflt_hdr.ymax)
RLerror(RL_ADVISE, "Image window: %d - %d, %d - %d.\n",
rle_dflt_hdr.xmin, rle_dflt_hdr.xmax,
rle_dflt_hdr.ymin, rle_dflt_hdr.ymax);
*/
/*
* Set window.
*/
Screen.minx = rle_dflt_hdr.xmin;
Screen.miny = rle_dflt_hdr.ymin;
Screen.maxx = rle_dflt_hdr.xmax;
Screen.maxy = rle_dflt_hdr.ymax;
/*
* Set alpha. Warn the user if the alpha option doesn't reflect
* what's already been rendered.
*/
if (Options.alpha != rle_dflt_hdr.alpha)
RLerror(RL_WARN, "Image %s %s an alpha channel.\n",
Options.imgname,
rle_dflt_hdr.alpha ? "has" : "does not have");
Options.alpha = rle_dflt_hdr.alpha;
/*
* Determine number of scanlines written to file.
*/
Screen.miny += count_rle_rows(&rle_dflt_hdr);
if (Screen.miny >= Screen.maxy) {
fprintf(stderr, "\"%s\" is a complete image.\n",
Options.imgname);
exit(0);
}
fprintf(Stats.fstats,"Continuing \"%s\" at scanline #%d.\n",
Options.imgname, Screen.miny);
(void)fclose(Options.pictfile);
}
static int
count_rle_rows( hdr )
rle_hdr *hdr;
{
rle_op **raw;
int *nraw, y, ynext;
if (rle_raw_alloc( hdr, &raw, &nraw ) < 0) {
RLerror(RL_PANIC,
"Unable to allocate memory in count_rle_rows.\n");
}
y = hdr->ymin;
while ((ynext = rle_getraw( hdr, raw, nraw )) != 32768) {
y = ynext+1;
rle_freeraw( hdr, raw, nraw );
}
/* Free memory. */
rle_raw_free( hdr, raw, nraw );
return y - hdr->ymin;
}
/*
* Write a scanline of output.
* "buf" is an array of Color structures of size Screen.xsize. Each color
* component is normalized to [0, 1.].
*/
void
PictureWriteLine(buf)
Pixel *buf;
{
register int i, chan;
float floats[3];
rle_pixel pixels[4];
for(i = 0; i < Screen.xsize; i++) {
if (!Options.exp_output) {
/*
* Scale colors to fit unsigned char and check for
* over/underflow.
*/
outptr[0][i] = CORRECT(buf[i].r);
outptr[1][i] = CORRECT(buf[i].g);
outptr[2][i] = CORRECT(buf[i].b);
} else {
/*
* Convert 3 floats to 4 unsigned chars for
* 'exponential_data' RLE file.
*/
floats[0] = GAMMACORRECT(buf[i].r);
floats[1] = GAMMACORRECT(buf[i].g);
floats[2] = GAMMACORRECT(buf[i].b);
float_to_exp( 3, floats, pixels );
for (chan = 0; chan <= 3; chan++)
outptr[chan][i] = pixels[chan];
}
if (Options.alpha)
/*
* Don't gamma correct alpha channel.
*/
outptr[-1][i] = correct(buf[i].alpha);
}
rle_putrow(outptr, Screen.xsize, &rle_dflt_hdr);
}
/*
* End the frame.
*/
void
PictureFrameEnd()
{
rle_puteof(&rle_dflt_hdr);
}
/*
* Close image file.
*/
void
PictureEnd()
{
(void)fclose(Options.pictfile);
}
#else /* !URT */
#ifdef TARGA
#define STORE16(c,i) *((unsigned short*)(&(c)))=(i)
#define HEADERSIZE 18
#define O_COMMENTLEN 0
#define O_MAPTYPE 1
#define O_FILETYPE 2
#define O_MAPORG 3
#define O_MAPLEN 5
#define O_MAPSIZE 7
#define O_XORIGIN 8
#define O_YORIGIN 10
#define O_HSIZE 12
#define O_VSIZE 14
#define O_ESIZE 16
#define O_FLAGS 17
#define M_ORIGIN 0x20
#define T_RAWRGB 2
#include <stdlib.h>
#include <string.h>
char NameSave[256];
char AnimImgName[256];
static int AnimFrameNum=0;
char *AnimFrameName(char *name,int num) {
static char tmp[256];
#if defined(MSDOS) || defined(__MSDOS__)
static char path[_MAX_PATH],drive[_MAX_DRIVE],
dir[_MAX_DIR],fname[_MAX_FNAME],ext[_MAX_EXT];
strcpy(path,name);
_splitpath(path,drive,dir,fname,ext);
if (strlen(fname)>5)
fname[5]='\0';
sprintf(tmp,"%s%03d",fname,num);
tmp[8]='\0';
strcpy(fname,tmp);
_makepath(path,drive,dir,fname,ext);
strcpy(tmp,path);
#else
sprintf(tmp,"%s.%03d",name,num);
#endif
return tmp;
}
void
PictureStart(argv)
char **argv;
{
unsigned char header[HEADERSIZE];
if (Options.imgname) {
strcpy(NameSave,Options.imgname);
if (Options.endframe>Options.startframe) {
strcpy(AnimImgName,AnimFrameName(Options.imgname,AnimFrameNum));
AnimFrameNum++;
strcpy(Options.imgname,AnimImgName);
}
if (Options.verbose)
fprintf(Stats.fstats,"Writing Targa to: %s\n",Options.imgname);
#if defined(__WATCOMC__) || defined(__BORLANDC__)
Options.pictfile = fopen(Options.imgname, "wb");
#else
Options.pictfile = fopen(Options.imgname, "w");
#endif
if (Options.pictfile == (FILE *)NULL)
RLerror(RL_PANIC, "Cannot open %s for writing.",
Options.imgname);
strcpy(Options.imgname,NameSave);
} else {
if (Options.endframe>Options.startframe) {
RLerror(RL_PANIC, "Cannot output animation to stdout.");
}
Options.pictfile = stdout;
#if defined(__WATCOMC__) || defined(__BORLANDC__)
#ifdef __BORLANDC__
setmode(fileno(Options.pictfile),O_BINARY);
#else
setmode(Options.pictfile->_handle,O_BINARY);
#endif
#endif
}
memset(header, 0, HEADERSIZE);
header[O_COMMENTLEN]=0;
header[O_FILETYPE]=T_RAWRGB;
STORE16(header[O_HSIZE], Screen.xsize);
STORE16(header[O_VSIZE], Screen.ysize);
header[O_ESIZE]=24;
header[O_FLAGS]=M_ORIGIN; /* Pic drawn from top to bottom */
fwrite(header, HEADERSIZE, 1, Options.pictfile);
(void)fflush(Options.pictfile);
}
void
PictureWriteLine(buf)
Pixel *buf;
{
register int i;
for (i = 0; i < Screen.xsize; i++) {
(void)fputc((int)CORRECT(buf[i].b), Options.pictfile);
(void)fputc((int)CORRECT(buf[i].g), Options.pictfile);
(void)fputc((int)CORRECT(buf[i].r), Options.pictfile);
}
(void)fflush(Options.pictfile);
}
void
PictureFrameEnd()
{
(void)fclose(Options.pictfile);
}
void
PictureEnd()
{
(void)fclose(Options.pictfile);
}
#else
void
PictureStart(argv)
char **argv;
{
if (Options.imgname) {
#if defined(__WATCOMC__) || defined(__BORLANDC__)
Options.pictfile = fopen(Options.imgname, "wb");
#else
Options.pictfile = fopen(Options.imgname, "w");
#endif
if (Options.pictfile == (FILE *)NULL)
RLerror(RL_ABORT, "Cannot open %s for writing.",
Options.imgname);
} else
Options.pictfile = stdout;
fprintf(Options.pictfile,"%d %d\n",Screen.xsize, Screen.ysize);
(void)fflush(Options.pictfile);
}
void
PictureWriteLine(buf)
Pixel *buf;
{
register int i;
for (i = 0; i < Screen.xsize; i++) {
(void)fputc((int)CORRECT(buf[i].r), Options.pictfile);
(void)fputc((int)CORRECT(buf[i].g), Options.pictfile);
(void)fputc((int)CORRECT(buf[i].b), Options.pictfile);
}
(void)fflush(Options.pictfile);
}
void
PictureFrameEnd()
{
/*
* Don't do anything -- generic format has no end-of-image marker.
*/
}
void
PictureEnd()
{
(void)fclose(Options.pictfile);
}
#endif
#endif /* URT */