]> Dogcows Code - chaz/rasterize/blob - raster.cc
begin work on ray tracer project
[chaz/rasterize] / raster.cc
1
2 /*
3 * CS5600 University of Utah
4 * Charles McGarvey
5 * mcgarvey@eng.utah.edu
6 */
7
8 #include <cassert>
9 #include <cerrno>
10 #include <cstdio>
11 #include <cstring>
12
13 #include "raster.hh"
14
15
16 struct raster
17 {
18 color_t* pixels;
19 int w, h;
20 int left, right, bottom, top;
21 };
22
23
24 raster_t* raster_alloc(int width, int height, color_t fill)
25 {
26 assert(0 < width && 0 < height && "zero-dimension raster not allowed");
27 size_t size = width * height;
28
29 raster_t* p = (raster_t*)mem_alloc(sizeof(raster_t));
30 p->pixels = (color_t*)mem_alloc(sizeof(color_t) * size);
31 p->w = width;
32 p->h = height;
33 raster_clear(p, fill);
34 raster_viewport(p, 0, 0, width, height);
35
36 return p;
37 }
38
39 void raster_destroy(raster_t* p)
40 {
41 mem_free(p->pixels);
42 mem_free(p);
43 }
44
45
46 color_t* raster_color(const raster_t* p, int x, int y)
47 {
48 return p->pixels + p->w * y + x;
49 }
50
51 int raster_width(const raster_t* p)
52 {
53 return p->w;
54 }
55
56 int raster_height(const raster_t* p)
57 {
58 return p->h;
59 }
60
61 void* raster_data(const raster_t* p)
62 {
63 size_t size = p->w * p->h;
64 rgba_t* data = (rgba_t*)mem_alloc(size * sizeof(rgba_t));
65
66 for (int i = 0; i < size; ++i) {
67 data[i] = rgba_from_color(p->pixels[i]);
68 }
69 return data;
70 }
71
72
73 void raster_clear(raster_t* p, color_t fill)
74 {
75 size_t size = p->w * p->h;
76 for (int i = 0; i < size; ++i) {
77 p->pixels[i] = fill;
78 }
79 }
80
81
82 void raster_viewport(raster_t* p, int x, int y, int width, int height)
83 {
84 p->left = x;
85 p->right = x + width;
86 p->bottom = y;
87 p->top = y + height;
88 }
89
90
91 #define _DO_OR_DIE(X) if ((X) <= 0) goto fail
92
93 int raster_export_ppm(const raster_t* p, const char* filename)
94 {
95 FILE* file = fopen(filename, "w");
96 if (file == NULL) {
97 fail: fprintf(stderr, "Cannot write to %s: %s\n", filename, strerror(errno));
98 return -1;
99 }
100
101 _DO_OR_DIE(fprintf(file, "P3\n%u %u\n255\n", p->w, p->h));
102 for (int y = (int)p->h - 1; y >= 0; --y) {
103 for (int x = 0; x < p->w; ++x) {
104 rgbachan_t r, g, b;
105 color_split(p->pixels[y * p->w + x], &r, &g, &b, NULL);
106 _DO_OR_DIE(fprintf(file, "%hhu %hhu %hhu\n", r, g, b));
107 }
108 }
109
110 fclose(file);
111 return 0;
112 }
113
114 int raster_export_bmp(const raster_t* p, const char* filename)
115 {
116 /*
117 * This function was adapted from sample code provided with the assignment
118 * instructions.
119 */
120 FILE* file = fopen(filename, "wb");
121 if (file == NULL) {
122 fail: fprintf(stderr, "Cannot write to %s: %s\n", filename, strerror(errno));
123 return -1;
124 }
125
126 uint16_t magicNumber = 0x4D42;
127 uint16_t reserved0 = 0;//0x4D41;
128 uint16_t reserved1 = 0;//0x5454;
129 uint32_t dataOffset = 54;
130 uint32_t infoHeaderSize = 40;
131 uint32_t width = p->w;
132 uint32_t height = p->h;
133 uint16_t colorPlanes = 1;
134 uint16_t bitsPerPixel = 32;
135 uint32_t compression = 0;
136 uint32_t dataSize = width * height * bitsPerPixel / 8;
137 uint32_t horizontalResolution = 2835;
138 uint32_t verticalResolution = 2835;
139 uint32_t paletteColorCount = 0;
140 uint32_t importantPaletteColorCount = 0;
141 uint32_t fileSize = 54 + dataSize;
142
143 /*
144 * Check the return values to avoid loud warnings.
145 */
146 _DO_OR_DIE(fwrite(&magicNumber, sizeof(magicNumber), 1, file));
147 _DO_OR_DIE(fwrite(&fileSize, sizeof(fileSize), 1, file));
148 _DO_OR_DIE(fwrite(&reserved0, sizeof(reserved0), 1, file));
149 _DO_OR_DIE(fwrite(&reserved1, sizeof(reserved1), 1, file));
150 _DO_OR_DIE(fwrite(&dataOffset, sizeof(dataOffset), 1, file));
151 _DO_OR_DIE(fwrite(&infoHeaderSize, sizeof(infoHeaderSize), 1, file));
152 _DO_OR_DIE(fwrite(&width, sizeof(width), 1, file));
153 _DO_OR_DIE(fwrite(&height, sizeof(height), 1, file));
154 _DO_OR_DIE(fwrite(&colorPlanes, sizeof(colorPlanes), 1, file));
155 _DO_OR_DIE(fwrite(&bitsPerPixel, sizeof(bitsPerPixel), 1, file));
156 _DO_OR_DIE(fwrite(&compression, sizeof(compression), 1, file));
157 _DO_OR_DIE(fwrite(&dataSize, sizeof(dataSize), 1, file));
158 _DO_OR_DIE(fwrite(&horizontalResolution, sizeof(horizontalResolution), 1, file));
159 _DO_OR_DIE(fwrite(&verticalResolution, sizeof(verticalResolution), 1, file));
160 _DO_OR_DIE(fwrite(&paletteColorCount, sizeof(paletteColorCount), 1, file));
161 _DO_OR_DIE(fwrite(&importantPaletteColorCount, sizeof(importantPaletteColorCount), 1, file));
162
163 size_t size = width * height;
164 for (int i = 0; i < size; ++i)
165 {
166 struct {
167 rgbachan_t b, g, r, a;
168 } argb;
169 color_split(p->pixels[i], &argb.r, &argb.g, &argb.b, &argb.a);
170 _DO_OR_DIE(fwrite(&argb, sizeof(argb), 1, file));
171 }
172
173 fclose(file);
174 return 0;
175 }
176
177
178 raster_t* raster_import(const char* filename)
179 {
180 int type = 0;
181 const char* ext = strrchr(filename, '.');
182 if (ext == NULL) {
183 goto fail;
184 }
185 ++ext;
186
187 if (strcmp(ext, "bmp") == 0) {
188 return raster_import_bmp(filename);
189 }
190 if (strcmp(ext, "ppm") == 0) {
191 return raster_import_ppm(filename);
192 }
193
194 fail:
195 fprintf(stderr, "Unknown file type: %s", filename);
196 return NULL;
197 }
198
199 raster_t* raster_import_ppm(const char* filename)
200 {
201 FILE* file = fopen(filename, "r");
202 if (file == NULL) {
203 fprintf(stderr, "Cannot read from %s: %s\n", filename, strerror(errno));
204 return NULL;
205 }
206
207 int w, h;
208 if (fscanf(file, "P3 %d %d 255 ", &w, &h) != 2) {
209 fprintf(stderr, "Cannot read header from %s: %s\n", filename, strerror(errno));
210 return NULL;
211 }
212
213 raster_t* p = raster_alloc(w, h, COLOR_WHITE);
214
215 for (int y = h - 1; y >= 0; --y) {
216 for (int x = 0; x < w; ++x) {
217 uint16_t r, g, b;
218 /* mingw32 does not like %hhu conversion type */
219 if (fscanf(file, "%hu %hu %hu ", &r, &g, &b) != 3) {
220 fprintf(stderr, "Failed reading color values from %s: %s\n", filename, strerror(errno));
221 return NULL;
222 }
223 union {
224 rgba_t rgba;
225 struct {
226 rgbachan_t r, g, b, a;
227 } chan;
228 } u;
229 u.chan.r = (rgbachan_t)r;
230 u.chan.g = (rgbachan_t)g;
231 u.chan.b = (rgbachan_t)b;
232 u.chan.a = 255;
233 p->pixels[y * w + x] = color_from_rgba(u.rgba);
234 }
235 }
236
237 fclose(file);
238 return p;
239
240 fail:
241 raster_destroy(p);
242 fclose(file);
243 fprintf(stderr, "Unexpected file format in %s: %s\n", filename, strerror(errno));
244 return NULL;
245 }
246
247 raster_t* raster_import_bmp(const char* filename)
248 {
249 FILE* file = fopen(filename, "rb");
250 if (file == NULL) {
251 fprintf(stderr, "Cannot read from %s: %s\n", filename, strerror(errno));
252 return NULL;
253 }
254
255 size_t size;
256
257 uint16_t magicNumber;
258 uint16_t reserved0;//0x4D41;
259 uint16_t reserved1;//0x5454;
260 uint32_t dataOffset;
261 uint32_t infoHeaderSize;
262 uint32_t width;
263 uint32_t height;
264 uint16_t colorPlanes;
265 uint16_t bitsPerPixel;
266 uint32_t compression;
267 uint32_t dataSize;
268 uint32_t horizontalResolution;
269 uint32_t verticalResolution;
270 uint32_t paletteColorCount;
271 uint32_t importantPaletteColorCount;
272 uint32_t fileSize;
273
274 raster_t* p = NULL;
275
276 _DO_OR_DIE(fread(&magicNumber, sizeof(magicNumber), 1, file));
277 _DO_OR_DIE(fread(&fileSize, sizeof(fileSize), 1, file));
278 _DO_OR_DIE(fread(&reserved0, sizeof(reserved0), 1, file));
279 _DO_OR_DIE(fread(&reserved1, sizeof(reserved1), 1, file));
280 _DO_OR_DIE(fread(&dataOffset, sizeof(dataOffset), 1, file));
281 _DO_OR_DIE(fread(&infoHeaderSize, sizeof(infoHeaderSize), 1, file));
282 _DO_OR_DIE(fread(&width, sizeof(width), 1, file));
283 _DO_OR_DIE(fread(&height, sizeof(height), 1, file));
284 _DO_OR_DIE(fread(&colorPlanes, sizeof(colorPlanes), 1, file));
285 _DO_OR_DIE(fread(&bitsPerPixel, sizeof(bitsPerPixel), 1, file));
286 _DO_OR_DIE(fread(&compression, sizeof(compression), 1, file));
287 _DO_OR_DIE(fread(&dataSize, sizeof(dataSize), 1, file));
288 _DO_OR_DIE(fread(&horizontalResolution, sizeof(horizontalResolution), 1, file));
289 _DO_OR_DIE(fread(&verticalResolution, sizeof(verticalResolution), 1, file));
290 _DO_OR_DIE(fread(&paletteColorCount, sizeof(paletteColorCount), 1, file));
291 _DO_OR_DIE(fread(&importantPaletteColorCount, sizeof(importantPaletteColorCount), 1, file));
292
293 p = raster_alloc((int)width, (int)height, COLOR_WHITE);
294
295 size = width * height;
296 for (int i = 0; i < size; ++i)
297 {
298 union {
299 rgba_t rgba;
300 struct {
301 rgbachan_t r, g, b, a;
302 } chan;
303 } u;
304 _DO_OR_DIE(fread(&u, sizeof(u), 1, file));
305 rgbachan_t t = u.chan.r;
306 u.chan.r = u.chan.a;
307 u.chan.a = t;
308 t = u.chan.g;
309 u.chan.g = u.chan.b;
310 u.chan.b = t;
311 t = u.chan.r;
312 u.chan.r = u.chan.g;
313 u.chan.g = u.chan.b;
314 u.chan.b = u.chan.a;
315 u.chan.a = t;
316 p->pixels[i] = color_from_rgba(u.rgba);
317 }
318
319 fclose(file);
320 return p;
321
322 fail:
323 if (p) {
324 raster_destroy(p);
325 }
326 fclose(file);
327 fprintf(stderr, "Unexpected file format in %s: %s\n", filename, strerror(errno));
328 return NULL;
329 }
330
331 #undef _DO_OR_DIE
332
This page took 0.047417 seconds and 4 git commands to generate.