void heman_image_sample(heman_image* img, float u, float v, HEMAN_FLOAT* result) { int x = CLAMP(img->width * u, 0, img->width - 1); int y = CLAMP(img->height * v, 0, img->height - 1); HEMAN_FLOAT* data = heman_image_texel(img, x, y); for (int b = 0; b < img->nbands; ++b) { *result++ = *data++; } }
heman_image* heman_ops_emboss(heman_image* img, int mode) { int seed = 1; int octaves = 4; struct osn_context* ctx; open_simplex_noise(seed, &ctx); int width = img->width; int height = img->height; assert(img->nbands == 1); heman_image* result = heman_image_create(width, height, 1); HEMAN_FLOAT invw = 1.0 / width; HEMAN_FLOAT invh = 1.0 / height; HEMAN_FLOAT inv = MIN(invw, invh); float gain = 0.6; float lacunarity = 2.0; float land_amplitude = 0.0005; float land_frequency = 256.0; float ocean_amplitude = 0.5; float ocean_frequency = 1.0; #pragma omp parallel for for (int y = 0; y < height; y++) { HEMAN_FLOAT* dst = result->data + y * width; for (int x = 0; x < width; x++) { HEMAN_FLOAT z = *heman_image_texel(img, x, y); if (z > 0 && mode == 1) { float s = x * inv; float t = y * inv; float a = land_amplitude; float f = land_frequency; for (int i = 0; i < octaves; i++) { z += NOISEX(s, t, a, f); a *= gain; f *= lacunarity; } } else if (z <= 0 && mode == -1) { z = MAX(z, -0.1); float soften = fabsf(z); float s = x * inv; float t = y * inv; float a = ocean_amplitude; float f = ocean_frequency; for (int i = 0; i < octaves; i++) { z += soften * NOISEX(s, t, a, f); a *= gain; f *= lacunarity; } } *dst++ = z; } } open_simplex_noise_free(ctx); return result; }
static void copy_row(heman_image* src, heman_image* dst, int dstx, int y) { int width = src->width; if (src->nbands == 1) { for (int x = 0; x < width; x++) { HEMAN_FLOAT* srcp = heman_image_texel(src, x, y); HEMAN_FLOAT* dstp = heman_image_texel(dst, dstx + x, y); *dstp = *srcp; } return; } for (int x = 0; x < width; x++) { HEMAN_FLOAT* srcp = heman_image_texel(src, x, y); HEMAN_FLOAT* dstp = heman_image_texel(dst, dstx + x, y); int nbands = src->nbands; while (nbands--) { *dstp++ = *srcp++; } } }
heman_image* heman_ops_laplacian(heman_image* heightmap) { assert(heightmap->nbands == 1); int width = heightmap->width; int height = heightmap->height; heman_image* result = heman_image_create(width, height, 1); int maxx = width - 1; int maxy = height - 1; #pragma omp parallel for for (int y = 0; y < height; y++) { int y1 = MIN(y + 1, maxy); HEMAN_FLOAT* dst = result->data + y * width; for (int x = 0; x < width; x++) { int x1 = MIN(x + 1, maxx); HEMAN_FLOAT p = *heman_image_texel(heightmap, x, y); HEMAN_FLOAT px = *heman_image_texel(heightmap, x1, y); HEMAN_FLOAT py = *heman_image_texel(heightmap, x, y1); *dst++ = (p - px) * (p - px) + (p - py) * (p - py); } } return result; }
void heman_export_ply(heman_image* img, const char* filename) { assert(img->nbands == 1); FILE* fout = fopen(filename, "wb"); int ncols = (img->width - 1); int nrows = (img->height - 1); int ncells = ncols * nrows; int nverts = img->width * img->height; fprintf(fout, "ply\n" "format binary_little_endian 1.0\n" "comment heman\n" "element vertex %d\n" "property float32 x\n" "property float32 y\n" "property float32 z\n" "element face %d\n" "property list int32 int32 vertex_indices\n" "end_header\n", nverts, ncells); float invw = 2.0f / img->width; float invh = 2.0f / img->height; float vert[3]; for (int j = 0; j < img->height; j++) { for (int i = 0; i < img->width; i++) { vert[0] = -1 + i * invw; vert[1] = -1 + j * invh; vert[2] = *heman_image_texel(img, i, j); fwrite(vert, sizeof(vert), 1, fout); } } int face[5]; face[0] = 4; for (int j = 0; j < nrows; j++) { int p = j * img->width; for (int i = 0; i < ncols; i++, p++) { face[1] = p; face[2] = p + 1; face[3] = p + img->width + 1; face[4] = p + img->width; fwrite(face, sizeof(face), 1, fout); } } fclose(fout); }
heman_image* heman_ops_sobel(heman_image* img, heman_color rgb) { int width = img->width; int height = img->height; assert(img->nbands == 3); heman_image* result = heman_image_create(width, height, 3); heman_image* gray = heman_color_to_grayscale(img); HEMAN_FLOAT inv = 1.0f / 255.0f; kmVec3 edge_rgb; edge_rgb.x = (HEMAN_FLOAT)(rgb >> 16) * inv; edge_rgb.y = (HEMAN_FLOAT)((rgb >> 8) & 0xff) * inv; edge_rgb.z = (HEMAN_FLOAT)(rgb & 0xff) * inv; #pragma omp parallel for for (int y = 0; y < height; y++) { kmVec3* dst = (kmVec3*) result->data + y * width; const kmVec3* src = (kmVec3*) img->data + y * width; for (int x = 0; x < width; x++) { int xm1 = MAX(x - 1, 0); int xp1 = MIN(x + 1, width - 1); int ym1 = MAX(y - 1, 0); int yp1 = MIN(y + 1, height - 1); HEMAN_FLOAT t00 = *heman_image_texel(gray, xm1, ym1); HEMAN_FLOAT t10 = *heman_image_texel(gray, x, ym1); HEMAN_FLOAT t20 = *heman_image_texel(gray, xp1, ym1); HEMAN_FLOAT t01 = *heman_image_texel(gray, xm1, 0); HEMAN_FLOAT t21 = *heman_image_texel(gray, xp1, 0); HEMAN_FLOAT t02 = *heman_image_texel(gray, xm1, yp1); HEMAN_FLOAT t12 = *heman_image_texel(gray, x, yp1); HEMAN_FLOAT t22 = *heman_image_texel(gray, xp1, yp1); HEMAN_FLOAT gx = t00 + 2.0 * t01 + t02 - t20 - 2.0 * t21 - t22; HEMAN_FLOAT gy = t00 + 2.0 * t10 + t20 - t02 - 2.0 * t12 - t22; HEMAN_FLOAT is_edge = gx * gx + gy * gy > 1e-5; kmVec3Lerp(dst++, src++, &edge_rgb, is_edge); } } heman_image_destroy(gray); return result; }
heman_image* heman_ops_warp_points(heman_image* img, int seed, int octaves, heman_points* pts) { int width = img->width; int height = img->height; heman_image* mapping = heman_distance_identity_cpcf(width, height); heman_image* retval = heman_ops_warp_core(img, mapping, seed, octaves); HEMAN_FLOAT* src = pts->data; for (int k = 0; k < pts->width; k++, src += pts->nbands) { HEMAN_FLOAT x = src[0]; HEMAN_FLOAT y = src[1]; int i = x * mapping->width; int j = y * mapping->height; if (i < 0 || i >= mapping->width || j < 0 || j >= mapping->height) { continue; } HEMAN_FLOAT* texel = heman_image_texel(mapping, i, j); src[0] = texel[0] / mapping->width; src[1] = texel[1] / mapping->height; } heman_image_destroy(mapping); return retval; }
heman_image* heman_ops_warp_core(heman_image* img, heman_image* secondary, int seed, int octaves) { struct osn_context* ctx; open_simplex_noise(seed, &ctx); int width = img->width; int height = img->height; int nbands = img->nbands; heman_image* result = heman_image_create(width, height, nbands); heman_image* result2 = secondary ? heman_image_create(width, height, secondary->nbands) : 0; HEMAN_FLOAT invw = 1.0 / width; HEMAN_FLOAT invh = 1.0 / height; HEMAN_FLOAT inv = MIN(invw, invh); HEMAN_FLOAT aspect = (float) width / height; float gain = 0.6; float lacunarity = 2.0; float initial_amplitude = 0.05; float initial_frequency = 8.0; #pragma omp parallel for for (int y = 0; y < height; y++) { HEMAN_FLOAT* dst = result->data + y * width * nbands; for (int x = 0; x < width; x++) { float a = initial_amplitude; float f = initial_frequency; HEMAN_FLOAT* src; // This is a little hack that modulates noise according to // elevation, to prevent "swimming" at high elevations. if (nbands == 4) { src = heman_image_texel(img, x, y); HEMAN_FLOAT elev = 1 - src[3]; a *= pow(elev, 4); } float s = x * inv; float t = y * inv; float u = x * invw; float v = y * invh; for (int i = 0; i < octaves; i++) { u += NOISEX(s, t, a, f); v += aspect * NOISEY(s, t, a, f); a *= gain; f *= lacunarity; } int i = CLAMP(u * width, 0, width - 1); int j = CLAMP(v * height, 0, height - 1); src = heman_image_texel(img, i, j); for (int n = 0; n < nbands; n++) { *dst++ = *src++; } if (secondary) { src = heman_image_texel(secondary, x, y); HEMAN_FLOAT* dst2 = heman_image_texel(result2, i, j); for (int n = 0; n < secondary->nbands; n++) { *dst2++ = *src++; } } } } open_simplex_noise_free(ctx); if (secondary) { free(secondary->data); secondary->data = result2->data; free(result2); } return result; }
void heman_export_with_colors_ply( heman_image* hmap, heman_image* colors, const char* filename) { int width = hmap->width; int height = hmap->height; assert(hmap->nbands == 1); assert(colors->nbands == 3); assert(colors->width == width); assert(colors->height == height); FILE* fout = fopen(filename, "wb"); int ncols = (hmap->width - 1); int nrows = (hmap->height - 1); int ncells = ncols * nrows; int nverts = hmap->width * hmap->height; unsigned char* colordata = malloc(width * height * 3); heman_export_u8(colors, 0.0, 1.0, colordata); fprintf(fout, "ply\n" "format binary_little_endian 1.0\n" "comment heman\n" "element vertex %d\n" "property float32 x\n" "property float32 y\n" "property float32 z\n" "property uchar red\n" "property uchar green\n" "property uchar blue\n" "property uchar alpha\n" "element face %d\n" "property list int32 int32 vertex_indices\n" "end_header\n", nverts, ncells); float invw = 2.0f / width; float invh = 2.0f / height; heman_byte* pcolor = colordata; float vert[3]; for (int j = 0; j < height; j++) { for (int i = 0; i < width; i++) { vert[0] = -1 + i * invw; vert[1] = -1 + j * invh; vert[2] = *heman_image_texel(hmap, i, j); fwrite(vert, sizeof(vert), 1, fout); fwrite(pcolor, 3, 1, fout); pcolor += 3; fputc(255, fout); } } int face[5]; face[0] = 4; for (int j = 0; j < nrows; j++) { int p = j * width; for (int i = 0; i < ncols; i++, p++) { face[1] = p; face[2] = p + 1; face[3] = p + hmap->width + 1; face[4] = p + hmap->width; fwrite(face, sizeof(face), 1, fout); } } fclose(fout); free(colordata); }