int R2Image:: ReadJPEG(const char *filename) { #ifndef OMIT_JPEG // Open file FILE *fp = fopen(filename, "rb"); if (!fp) { fprintf(stderr, "Unable to open image file: %s", filename); return 0; } // Initialize decompression info struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; cinfo.err = jpeg_std_error(&jerr); jpeg_create_decompress(&cinfo); jpeg_stdio_src(&cinfo, fp); jpeg_read_header(&cinfo, TRUE); jpeg_start_decompress(&cinfo); // Remember image attributes width = cinfo.output_width; height = cinfo.output_height; ncomponents = cinfo.output_components; rowsize = ncomponents * width; if ((rowsize % 4) != 0) rowsize = (rowsize / 4 + 1) * 4; // Allocate image pixels int nbytes = rowsize * height; this->pixels = new unsigned char [nbytes]; if (!this->pixels) { fprintf(stderr, "Unable to allocate memory for JPEG file"); fclose(fp); return 0; } // Read scan lines // First jpeg pixel is top-left, so read pixels in opposite scan-line order while (cinfo.output_scanline < cinfo.output_height) { int scanline = cinfo.output_height - cinfo.output_scanline - 1; unsigned char *row_pointer = &pixels[scanline * rowsize]; jpeg_read_scanlines(&cinfo, &row_pointer, 1); } // Free everything jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); // Close file fclose(fp); // Return success return 1; #else RNFail("JPEG not supported"); return 0; #endif }
int R2Image:: WriteTIFF(const char *filename) const { #ifndef OMIT_TIFF // Open TIFF file TIFF *out = TIFFOpen(filename, "w"); if (!out) { fprintf(stderr, "Unable to open TIFF file %s\n", filename); return 0; } // Set TIFF parameters TIFFSetField(out, TIFFTAG_IMAGEWIDTH, width); TIFFSetField(out, TIFFTAG_IMAGELENGTH, height); TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_BOTLEFT); TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, 3); TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, 8); TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); TIFFSetField(out, TIFFTAG_COMPRESSION, COMPRESSION_NONE); TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, 1); // Allocate data for scan lines int scanline_size = TIFFScanlineSize(out); unsigned char *buf = (unsigned char *)_TIFFmalloc(scanline_size); if (!buf) { fprintf(stderr, "Unable to allocate memory for TIFF scan lines\n"); return 0; } // Write scan lines to TIFF file for (int row = 0; row < height; row++) { const unsigned char *p = Pixels(row); if (TIFFWriteScanline(out, (tdata_t) p, height - row - 1, 0) < 0) { fprintf(stderr, "Unable to write scanline to TIFF image %s\n", filename); return 0; } } // Free data for scan lines _TIFFfree(buf); // Close TIFF file TIFFClose(out); // Return number of bytes written return 1; #else RNFail("TIFF not supported"); return 0; #endif }
int R2Image:: WriteJPEG(const char *filename) const { #ifndef OMIT_JPEG // Open file FILE *fp = fopen(filename, "wb"); if (!fp) { fprintf(stderr, "Unable to open image file: %s", filename); return 0; } // Initialize compression info struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); jpeg_stdio_dest(&cinfo, fp); cinfo.image_width = width; /* image width and height, in pixels */ cinfo.image_height = height; cinfo.input_components = ncomponents; /* # of color components per pixel */ cinfo.in_color_space = JCS_RGB; /* colorspace of input image */ cinfo.dct_method = JDCT_ISLOW; jpeg_set_defaults(&cinfo); cinfo.optimize_coding = TRUE; jpeg_set_quality(&cinfo, 75, TRUE); jpeg_start_compress(&cinfo, TRUE); // Output scan lines // First jpeg pixel is top-left, so write in opposite scan-line order while (cinfo.next_scanline < cinfo.image_height) { int scanline = cinfo.image_height - cinfo.next_scanline - 1; unsigned char *row_pointer = &pixels[scanline * rowsize]; jpeg_write_scanlines(&cinfo, &row_pointer, 1); } // Free everything jpeg_finish_compress(&cinfo); jpeg_destroy_compress(&cinfo); // Close file fclose(fp); // Return number of bytes written return 1; #else RNFail("JPEG not supported"); return 0; #endif }
int R3Model:: WriteObjFile(const char *filename) const { // Open file FILE *fp; if (!(fp = fopen(filename, "w"))) { RNFail("Unable to open file %s", filename); return 0; } RNAbort("Not implemented"); // Close file fclose(fp); // Return success return 1; }
int R3Model:: WriteFile(const char *filename) const { // Parse input filename extension const char *extension; if (!(extension = strrchr(filename, '.'))) { printf("Filename %s has no extension (e.g., .obj)\n", filename); return 0; } // Write file of appropriate type if (!strncmp(extension, ".obj", 4)) { if (!WriteObjFile(filename)) return 0; } else { RNFail("Unable to write file %s (unrecognized extension: %s)\n", filename, extension); return 0; } // Return success return 1; }
int R2Image:: ReadGRD(const char *filename) { // Open file FILE *fp = fopen(filename, "rb"); if (!fp) { RNFail("Unable to open file %s", filename); return 0; } // Read grid resolution from file int grid_resolution[2]; if (fread(&grid_resolution, sizeof(int), 2, fp) != 2) { RNFail("Unable to read resolution from grid file"); return 0; } // Read world_to_grid transformation from file RNScalar m[9]; if (fread(m, sizeof(RNScalar), 9, fp) != 9) { RNFail("Unable to read transformation matrix from file"); return 0; } // Allocate grid values int grid_size = grid_resolution[0] * grid_resolution[1]; RNScalar *grid_values = new RNScalar [ grid_size ]; assert(grid_values); // Read grid values if (fread(grid_values, sizeof(RNScalar), grid_size, fp) != (unsigned int) grid_size) { RNFail("Unable to read %d grid values from file", grid_size); return 0; } // Close file fclose(fp); // Determine offset and scale RNScalar offset = 0; RNScalar scale = 1; if (grid_size > 0) { RNScalar sum = 0; RNScalar min_value = FLT_MAX; RNScalar max_value = -FLT_MAX; for (int i = 0; i < grid_size; i++) { if (grid_values[i] == R2_GRID_UNKNOWN_VALUE) continue; if (grid_values[i] > max_value) max_value = grid_values[i]; if (grid_values[i] < min_value) min_value = grid_values[i]; sum += grid_values[i]; } RNScalar mean = sum / grid_size; RNScalar ssd = 0; for (int i = 0; i < grid_size; i++) { if (grid_values[i] == R2_GRID_UNKNOWN_VALUE) continue; RNScalar delta = grid_values[i] - mean; ssd += delta * delta; } RNScalar stddev = sqrt(ssd); RNScalar min_clamped = mean - 3 * stddev; if (min_clamped < min_value) min_clamped = min_value; RNScalar max_clamped = mean + 3 * stddev; if (max_clamped > max_value) max_clamped = max_value; RNScalar range = max_clamped - min_clamped; if (range > 0) { offset = min_clamped; scale = 1.0 / range; } } // Allocate pixels ncomponents = 3; width = grid_resolution[0]; height = grid_resolution[1]; rowsize = ncomponents * width; if ((rowsize % 4) != 0) rowsize = (rowsize / 4 + 1) * 4; int nbytes = rowsize * height; pixels = new unsigned char [nbytes]; assert(pixels); // Fill in pixels RNScalar *grid_valuesp = grid_values; for (int j = 0; j < height; j++) { unsigned char *pixelsp = &pixels[j*rowsize]; for (int i = 0; i < width; i++) { int value = (int) ((*(grid_valuesp++) - offset) * 255.0 * scale); if (value < 0) value = 0; if (value > 255) value = 255; unsigned char p = (unsigned char) value; *(pixelsp++) = p; *(pixelsp++) = p; *(pixelsp++) = p; } } // Delete grid values delete [] grid_values; // Return number of bytes return nbytes; }
int R2Image:: ReadTIFF(const char *filename) { #ifndef OMIT_TIFF // Open file TIFF* tif = TIFFOpen(filename, "r"); if (!tif) { fprintf(stderr, "Unable to open TIFF file %s\n", filename); return 0; } // Get image dimensions uint32 w, h; TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w); TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h); size_t npixels = w * h; // Allocate buffer for data uint32* raster = (uint32*) _TIFFmalloc(npixels * sizeof (uint32)); if (!raster) { fprintf(stderr, "Unable to allocate data for TIFF file %s\n", filename); return 0; } // Read data into buffer if (!TIFFReadRGBAImage(tif, w, h, raster, 0)) { fprintf(stderr, "Unable to read TIFF file %s\n", filename); return 0; } // Initialize R2Image data width = w; height = h; ncomponents = 3; rowsize = ncomponents * width; if ((rowsize % 4) != 0) rowsize = (rowsize / 4 + 1) * 4; int nbytes = rowsize * height; pixels = new unsigned char [nbytes]; if (!pixels) { fprintf(stderr, "Unable to allocate memory for TIFF file %s", filename); return 0; } // Fill R2Image pixel data uint32 *rasterp = raster; for (int j = 0; j < height; j++) { unsigned char *p = &pixels[j*rowsize]; for (int i = 0; i < width; i++) { uint32 pixel = *(rasterp++); *(p++) = pixel & 0xFF; *(p++) = (pixel >> 8) & 0xFF; *(p++) = (pixel >> 16) & 0xFF; } } // Free data _TIFFfree(raster); // Close file TIFFClose(tif); // Return success return 1; #else RNFail("TIFF not supported"); return 0; #endif }
int R3Model:: ReadObjFile(const char *filename) { // Open file FILE *fp = fopen(filename, "r"); if (!fp) { RNFail("Unable to open file %s", filename); return 0; } // Determine directory name (for texture image files) char dirname[1024]; strncpy(dirname, filename, 1024); char *endp = strrchr(dirname, '/'); if (!endp) endp = strrchr(dirname, '\\'); if (!endp) strcpy(dirname, "."); else *endp = '\0'; // Read body char buffer[1024]; int line_count = 0; int material_index =-1; RNArray<R2Point *> texture_coords; RNArray<R3TriangleVertex *> verts; RNArray<R3Triangle *> tris; while (fgets(buffer, 1023, fp)) { // Increment line counter line_count++; // Skip white space char *bufferp = buffer; while (isspace(*bufferp)) bufferp++; // Skip blank lines and comments if (*bufferp == '#') continue; if (*bufferp == '\0') continue; // Get keyword char keyword[80]; if (sscanf(bufferp, "%s", keyword) != 1) { RNFail("Syntax error on line %d in file %s", line_count, filename); return 0; } // Check keyword if (!strcmp(keyword, "v")) { // Read vertex coordinates double x, y, z; if (sscanf(bufferp, "%s%lf%lf%lf", keyword, &x, &y, &z) != 4) { RNFail("Syntax error on line %d in file %s", line_count, filename); return 0; } // Create vertex R3TriangleVertex *vertex = new R3TriangleVertex(R3Point(x, y, z)); verts.Insert(vertex); } else if (!strcmp(keyword, "vt")) { // Read texture coordinates double u, v; if (sscanf(bufferp, "%s%lf%lf", keyword, &u, &v) != 3) { RNFail("Syntax error on line %d in file %s", line_count, filename); return 0; } // Create texture coordinates R2Point *vt = new R2Point(u, v); texture_coords.Insert(vt); } else if (!strcmp(keyword, "f")) { // Read vertex indices int quad = 1; char s1[128], s2[128], s3[128], s4[128] = { '\0' }; if (sscanf(bufferp, "%s%s%s%s%s", keyword, s1, s2, s3, s4) != 5) { quad = 0;; if (sscanf(bufferp, "%s%s%s%s", keyword, s1, s2, s3) != 4) { RNFail("Syntax error on line %d in file %s", line_count, filename); return 0; } } // Parse vertex indices int vi1 = -1, vi2 = -1, vi3 = -1, vi4 = -1; int ti1 = -1, ti2 = -1, ti3 = -1, ti4 = -1; char *p1 = strchr(s1, '/'); if (p1) { *p1 = 0; vi1 = atoi(s1); p1++; if (*p1) ti1 = atoi(p1); } else { vi1 = atoi(s1); ti1 = vi1; } char *p2 = strchr(s2, '/'); if (p2) { *p2 = 0; vi2 = atoi(s2); p2++; if (*p2) ti2 = atoi(p2); } else { vi2 = atoi(s2); ti2 = vi2; } char *p3 = strchr(s3, '/'); if (p3) { *p3 = 0; vi3 = atoi(s3); p3++; if (*p3) ti3 = atoi(p3); } else { vi3 = atoi(s3); ti3 = vi3; } if (quad) { char *p4 = strchr(s4, '/'); if (p4) { *p4 = 0; vi4 = atoi(s4); p4++; if (*p4) ti4 = atoi(p4); } else { vi4 = atoi(s4); ti4 = vi4; } } // Get vertices R3TriangleVertex *v1 = verts.Kth(vi1-1); R3TriangleVertex *v2 = verts.Kth(vi2-1); R3TriangleVertex *v3 = verts.Kth(vi3-1); R3TriangleVertex *v4 = (quad) ? verts.Kth(vi4-1) : NULL; // Assign texture coordinates if ((ti1 >= 0) && (ti1 < texture_coords.NEntries())) v1->SetTextureCoords(*(texture_coords.Kth(ti1-1))); if ((ti2 >= 0) && (ti2 < texture_coords.NEntries())) v2->SetTextureCoords(*(texture_coords.Kth(ti2-1))); if ((ti3 >= 0) && (ti3 < texture_coords.NEntries())) v3->SetTextureCoords(*(texture_coords.Kth(ti3-1))); if (quad) { if ((ti4 >= 0) && (ti4 < texture_coords.NEntries())) v4->SetTextureCoords(*(texture_coords.Kth(ti4-1))); } // Check vertices if ((v1 == v2) || (v2 == v3) || (v1 == v3)) continue; if ((quad) && ((v4 == v1) || (v4 == v2) || (v4 == v3))) quad = 0; // Create default material, if needed if (material_index == -1) { R3Brdf *brdf = new R3Brdf(RNRgb(0.2, 0.2, 0.2), RNRgb(0.8, 0.8, 0.8), RNRgb(0.0, 0.0, 0.0), RNRgb(0.0, 0.0, 0.0), 0.2, 1.0, 1.0); R3Material *material = new R3Material(brdf, "Default"); materials.Insert(material); RNArray<R3Triangle *> *mat_tris = new RNArray<R3Triangle *>(); material_triangles.Insert(mat_tris); material_index = 0; } // Get material assert(material_index >= 0); R3Material *material = materials.Kth(material_index); // Create first triangle R3Triangle *triangle = new R3Triangle(v1, v2, v3); tris.Insert(triangle); triangle_materials.Insert(material); material_triangles[material_index]->Insert(triangle); // Create second triangle if (quad) { R3Triangle *triangle = new R3Triangle(v1, v3, v4); tris.Insert(triangle); triangle_materials.Insert(material); material_triangles[material_index]->Insert(triangle); } } else if (!strcmp(keyword, "mtllib")) { // Read fields char mtlname[1024]; if (sscanf(bufferp, "%s%s", keyword, mtlname) != 2) { RNFail("Syntax error on line %d in file %s", line_count, filename); return 0; } // Read materials if (!ReadObjMtlFile(dirname, mtlname)) return 0; } else if (!strcmp(keyword, "usemtl")) { // Read fields char mtlname[1024]; if (sscanf(bufferp, "%s%s", keyword, mtlname) != 2) { RNFail("Syntax error on line %d in file %s", line_count, filename); return 0; } // Find material material_index = FindMaterialIndex(materials, mtlname); if (material_index == -1) { fprintf(stderr, "Unable to find material %s at on line %d in file %s", mtlname, line_count, filename); return 0; } } } // Create triangle array triangles = new R3TriangleArray(verts, tris); // Delete texture coordinates for (int i = 0; i < texture_coords.NEntries(); i++) { R2Point *vt = texture_coords.Kth(i); delete vt; } // Close file fclose(fp); // Return success return 1; }
int R3Model:: ReadObjMtlFile(const char *dirname, const char *mtlname) { // Open file char filename[1024]; sprintf(filename, "%s/%s", dirname, mtlname); FILE *fp = fopen(filename, "r"); if (!fp) { RNFail("Unable to open file %s", filename); return 0; } // Parse file char buffer[1024]; int line_count = 0; R3Brdf *brdf = NULL; R2Texture *texture = NULL; R3Material *material = NULL; while (fgets(buffer, 1023, fp)) { // Increment line counter line_count++; // Skip white space char *bufferp = buffer; while (isspace(*bufferp)) bufferp++; // Skip blank lines and comments if (*bufferp == '#') continue; if (*bufferp == '\0') continue; // Get keyword char keyword[80]; if (sscanf(bufferp, "%s", keyword) != 1) { RNFail("Syntax error on line %d in file %s", line_count, filename); return 0; } // Check keyword if (!strcmp(keyword, "newmtl")) { // Parse line char name[1024]; if (sscanf(bufferp, "%s%s", keyword, name) != (unsigned int) 2) { RNFail("Syntax error on line %d in file %s", line_count, filename); return 0; } // Create new material texture = NULL; brdf = new R3Brdf(); material = new R3Material(brdf, texture, name); materials.Insert(material); RNArray<R3Triangle *> *mat_tris = new RNArray<R3Triangle *>(); material_triangles.Insert(mat_tris); } else if (!strcmp(keyword, "Ka")) { // Parse line double r, g, b; if (sscanf(bufferp, "%s%lf%lf%lf", keyword, &r, &g, &b) != (unsigned int) 4) { RNFail("Syntax error on line %d in file %s", line_count, filename); return 0; } // Set ambient reflectance if (material && brdf) { brdf->SetAmbient(RNRgb(r, g, b)); material->Update(); } } else if (!strcmp(keyword, "Kd")) { // Parse line double r, g, b; if (sscanf(bufferp, "%s%lf%lf%lf", keyword, &r, &g, &b) != (unsigned int) 4) { RNFail("Syntax error on line %d in file %s", line_count, filename); return 0; } // Set diffuse reflectance if (material && brdf) { brdf->SetDiffuse(RNRgb(r, g, b)); material->Update(); } } else if (!strcmp(keyword, "Ks")) { // Parse line double r, g, b; if (sscanf(bufferp, "%s%lf%lf%lf", keyword, &r, &g, &b) != (unsigned int) 4) { RNFail("Syntax error on line %d in file %s", line_count, filename); return 0; } // Set specular reflectance if (material && brdf) { brdf->SetSpecular(RNRgb(r, g, b)); material->Update(); } } else if (!strcmp(keyword, "Ns")) { // Parse line double ns; if (sscanf(bufferp, "%s%lf", keyword, &ns) != (unsigned int) 2) { RNFail("Syntax error on line %d in file %s", line_count, filename); return 0; } // Set shininess if (material && brdf) { brdf->SetShininess(ns); material->Update(); } } else if (!strcmp(keyword, "Ni")) { // Parse line double index_of_refraction; if (sscanf(bufferp, "%s%lf", keyword, &index_of_refraction) != (unsigned int) 2) { RNFail("Syntax error on line %d in file %s", line_count, filename); return 0; } // Set index of refraction if (material && brdf) { brdf->SetIndexOfRefraction(index_of_refraction); material->Update(); } } else if (!strcmp(keyword, "d")) { // Parse line double transparency; if (sscanf(bufferp, "%s%lf", keyword, &transparency) != (unsigned int) 2) { RNFail("Syntax error on line %d in file %s", line_count, filename); return 0; } // Set opacity if (material && brdf) { brdf->SetOpacity(1 - transparency); material->Update(); } } else if (!strcmp(keyword, "map_Kd")) { // Parse line char texture_name[1024]; if (sscanf(bufferp, "%s%s", keyword, texture_name) != (unsigned int) 2) { RNFail("Syntax error on line %d in file %s", line_count, filename); return 0; } // Set texture if (material) { char texture_filename[1024]; sprintf(texture_filename, "%s/%s", dirname, texture_name); R2Image *image = new R2Image(); if (!image->Read(texture_filename)) return 0; R2Texture *texture = new R2Texture(image); material->SetTexture(texture); material->Update(); } } } // Close file fclose(fp); // Return success return 1; }