Tachyon (current)  Current Main Branch
tgafile.c
Go to the documentation of this file.
1 /*
2  * tgafile.c - This file contains the code to write 24 bit targa files...
3  *
4  * (C) Copyright 1994-2022 John E. Stone
5  * SPDX-License-Identifier: BSD-3-Clause
6  *
7  * $Id: tgafile.c,v 1.29 2022/02/18 17:55:28 johns Exp $
8  *
9  */
10 
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <math.h>
15 
16 #define TACHYON_INTERNAL 1
17 #include "tachyon.h"
18 #include "util.h"
19 #include "ui.h"
20 #include "imageio.h"
21 #include "tgafile.h"
22 
23 typedef struct {
24  unsigned short width;
25  unsigned short height;
26  FILE * ofp;
27 } tgahandle;
28 
29 int createtgafile(char *name, unsigned short width, unsigned short height) {
30  int filesize;
31  FILE * ofp;
32 
33  filesize = 3*width*height + 18 - 10;
34 
35  if (name==NULL) {
36  return IMAGEWRITEERR;
37  } else {
38  ofp=fopen(name, "w+b");
39  if (ofp == NULL) {
40  char msgtxt[2048];
41  sprintf(msgtxt, "Cannot create %s for output!", name);
42  rt_ui_message(MSG_ERR, msgtxt);
43  rt_ui_message(MSG_ABORT, "Rendering Aborted.");
44  return IMAGEWRITEERR;
45  }
46 
47  fputc(0, ofp); /* IdLength */
48  fputc(0, ofp); /* ColorMapType */
49  fputc(2, ofp); /* ImageTypeCode */
50  fputc(0, ofp); /* ColorMapOrigin, low byte */
51  fputc(0, ofp); /* ColorMapOrigin, high byte */
52  fputc(0, ofp); /* ColorMapLength, low byte */
53  fputc(0, ofp); /* ColorMapLength, high byte */
54  fputc(0, ofp); /* ColorMapEntrySize */
55  fputc(0, ofp); /* XOrigin, low byte */
56  fputc(0, ofp); /* XOrigin, high byte */
57  fputc(0, ofp); /* YOrigin, low byte */
58  fputc(0, ofp); /* YOrigin, high byte */
59  fputc((width & 0xff), ofp); /* Width, low byte */
60  fputc(((width >> 8) & 0xff), ofp); /* Width, high byte */
61  fputc((height & 0xff), ofp); /* Height, low byte */
62  fputc(((height >> 8) & 0xff), ofp); /* Height, high byte */
63  fputc(24, ofp); /* ImagePixelSize */
64  fputc(0x20, ofp); /* ImageDescriptorByte 0x20 == flip vertically */
65 
66  fseek(ofp, filesize, 0);
67  fprintf(ofp, "9876543210");
68 
69  fclose(ofp);
70  }
71 
72  return IMAGENOERR;
73 }
74 
75 void * opentgafile(char * filename) {
76  tgahandle * tga;
77  tga = malloc(sizeof(tgahandle));
78 
79  tga->ofp=fopen(filename, "r+b");
80  if (tga->ofp == NULL) {
81  char msgtxt[2048];
82  sprintf(msgtxt, "Cannot open %s for output!", filename);
83  rt_ui_message(MSG_ERR, msgtxt);
84  rt_ui_message(MSG_ABORT, "Rendering Aborted.");
85  return NULL;
86  }
87 
88  fseek(tga->ofp, 12, 0);
89  tga->width = fgetc(tga->ofp);
90  tga->width |= fgetc(tga->ofp) << 8;
91  tga->height = fgetc(tga->ofp);
92  tga->height |= fgetc(tga->ofp) << 8;
93 
94  return tga;
95 }
96 
97 void writetgaregion(void * voidhandle, int startx, int starty,
98  int stopx, int stopy, unsigned char * buffer) {
99  int x, y, totalx, totaly, xbytes, widthbytes, regionstart;
100  unsigned char * bufpos;
101  int filepos, numbytes;
102  tgahandle * tga = (tgahandle *) voidhandle;
103  unsigned char * fixbuf;
104 
105  totalx = stopx - startx + 1;
106  totaly = stopy - starty + 1;
107  xbytes = totalx*3;
108  widthbytes = tga->width*3;
109  fixbuf = (unsigned char *) malloc(xbytes);
110  if (fixbuf == NULL) {
111  rt_ui_message(MSG_ERR, "writetgaregion: failed memory allocation!\n");
112  return;
113  }
114 
115  regionstart = 18 + (startx-1)*3 + widthbytes*(tga->height-starty-totaly+1);
116  if (totalx == tga->width) {
117  filepos=regionstart;
118  if (filepos >= 18) {
119  fseek(tga->ofp, filepos, 0);
120  } else {
121  rt_ui_message(MSG_ERR, "writetgaregion: file ptr out of range!!!\n");
122  free(fixbuf);
123  return; /* don't try to continue */
124  }
125 
126  for (y=0; y<totaly; y++) {
127  bufpos=buffer + xbytes*(totaly-y-1);
128  for (x=0; x<xbytes; x+=3) {
129  fixbuf[x ] = bufpos[x + 2];
130  fixbuf[x + 1] = bufpos[x + 1];
131  fixbuf[x + 2] = bufpos[x ];
132  }
133  numbytes = fwrite(fixbuf, 1, xbytes, tga->ofp);
134  if (numbytes != xbytes) {
135  char msgtxt[256];
136  sprintf(msgtxt, "File write problem, %d bytes written.", numbytes);
137  rt_ui_message(MSG_ERR, msgtxt);
138  free(fixbuf);
139  return; /* don't try to continue */
140  }
141  }
142  } else {
143  for (y=0; y<totaly; y++) {
144  bufpos=buffer + xbytes*(totaly-y-1);
145  filepos=regionstart + widthbytes*y;
146 
147  if (filepos >= 18) {
148  fseek(tga->ofp, filepos, 0);
149 
150  for (x=0; x<xbytes; x+=3) {
151  fixbuf[x ] = bufpos[x + 2];
152  fixbuf[x + 1] = bufpos[x + 1];
153  fixbuf[x + 2] = bufpos[x ];
154  }
155 
156  numbytes = fwrite(fixbuf, 1, xbytes, tga->ofp);
157  if (numbytes != xbytes) {
158  char msgtxt[256];
159  sprintf(msgtxt, "File write problem, %d bytes written.", numbytes);
160  rt_ui_message(MSG_ERR, msgtxt);
161  free(fixbuf);
162  return; /* don't try to continue */
163  }
164  } else {
165  rt_ui_message(MSG_ERR, "writetgaregion: file ptr out of range!!!\n");
166  free(fixbuf);
167  return; /* don't try to continue */
168  }
169  }
170  }
171 
172  free(fixbuf);
173 }
174 
175 void closetgafile(void * voidhandle) {
176  tgahandle * tga = (tgahandle *) voidhandle;
177 
178  fclose(tga->ofp);
179  free(tga);
180 }
181 
182 int readtga(char * name, int * xres, int * yres, unsigned char **imgdata) {
183  int format, width, height, w1, w2, h1, h2, depth, flags;
184  int imgsize, bytesread, i, tmp;
185  FILE * ifp;
186 
187  ifp=fopen(name, "r");
188  if (ifp==NULL) {
189  return IMAGEBADFILE; /* couldn't open the file */
190  }
191 
192  /* read the targa header */
193  getc(ifp); /* ID length */
194  getc(ifp); /* colormap type */
195  format = getc(ifp); /* image type */
196  getc(ifp); /* color map origin */
197  getc(ifp); /* color map origin */
198  getc(ifp); /* color map length */
199  getc(ifp); /* color map length */
200  getc(ifp); /* color map entry size */
201  getc(ifp); /* x origin */
202  getc(ifp); /* x origin */
203  getc(ifp); /* y origin */
204  getc(ifp); /* y origin */
205  w1 = getc(ifp); /* width (low) */
206  w2 = getc(ifp); /* width (hi) */
207  h1 = getc(ifp); /* height (low) */
208  h2 = getc(ifp); /* height (hi) */
209  depth = getc(ifp); /* image pixel size */
210  flags = getc(ifp); /* image descriptor byte */
211 
212  if ((format != 2) || (depth != 24)) {
213  fclose(ifp);
214  return IMAGEUNSUP; /* unsupported targa format */
215  }
216 
217 
218  width = ((w2 << 8) | w1);
219  height = ((h2 << 8) | h1);
220 
221  imgsize = 3 * width * height;
222  *imgdata = malloc(imgsize);
223  bytesread = fread(*imgdata, 1, imgsize, ifp);
224  fclose(ifp);
225 
226  /* flip image vertically */
227  if (flags == 0x20) {
228  int rowsize = 3 * width;
229  unsigned char * copytmp;
230 
231  copytmp = malloc(rowsize);
232 
233  for (i=0; i<height / 2; i++) {
234  memcpy(copytmp, &((*imgdata)[rowsize*i]), rowsize);
235  memcpy(&(*imgdata)[rowsize*i], &(*imgdata)[rowsize*(height - 1 - i)], rowsize);
236  memcpy(&(*imgdata)[rowsize*(height - 1 - i)], copytmp, rowsize);
237  }
238 
239  free(copytmp);
240  }
241 
242 
243  /* convert from BGR order to RGB order */
244  for (i=0; i<imgsize; i+=3) {
245  tmp = (*imgdata)[i]; /* Blue */
246  (*imgdata)[i] = (*imgdata)[i+2]; /* Red */
247  (*imgdata)[i+2] = tmp; /* Blue */
248  }
249 
250  *xres = width;
251  *yres = height;
252 
253  if (bytesread != imgsize)
254  return IMAGEREADERR;
255 
256  return IMAGENOERR;
257 }
258 
259 
260 int writetga(char * name, int xres, int yres, unsigned char *imgdata) {
261  void * outfile;
262  int rc = IMAGENOERR;
263 
264  rc = createtgafile(name, (unsigned short) xres, (unsigned short) yres);
265  if (rc == IMAGENOERR) {
266  outfile = opentgafile(name);
267 
268  if (outfile == NULL)
269  return IMAGEWRITEERR;
270 
271  writetgaregion(outfile, 1, 1, xres, yres, imgdata);
272  closetgafile(outfile);
273  }
274 
275  return rc;
276 }
277 
278 
279 
#define IMAGEUNSUP
the image file is an unsupported format
Definition: imageio.h:18
void closetgafile(void *voidhandle)
Definition: tgafile.c:175
void rt_ui_message(int level, char *msg)
Definition: ui.c:31
#define MSG_ABORT
Definition: ui.h:19
void * opentgafile(char *filename)
Definition: tgafile.c:75
unsigned short height
Definition: tgafile.c:25
#define MSG_ERR
Definition: ui.h:18
Tachyon cross-platform timers, special math function wrappers, and RNGs.
int readtga(char *name, int *xres, int *yres, unsigned char **imgdata)
Definition: tgafile.c:182
#define IMAGENOERR
no error
Definition: imageio.h:16
#define IMAGEREADERR
failed read, short reads etc
Definition: imageio.h:20
FILE * ofp
Definition: tgafile.c:26
#define IMAGEWRITEERR
failed write, short writes etc
Definition: imageio.h:21
unsigned short width
Definition: tgafile.c:24
void writetgaregion(void *voidhandle, int startx, int starty, int stopx, int stopy, unsigned char *buffer)
Definition: tgafile.c:97
int writetga(char *name, int xres, int yres, unsigned char *imgdata)
Definition: tgafile.c:260
Tachyon public API function prototypes and declarations used to drive the ray tracing engine...
#define IMAGEBADFILE
can&#39;t find or can&#39;t open the file
Definition: imageio.h:17
int createtgafile(char *name, unsigned short width, unsigned short height)
Definition: tgafile.c:29