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