Files
Image-Heightmapper/HydraulicErosion.c
2025-10-29 21:24:15 +00:00

345 lines
8.0 KiB
C

#include "STLTextWriter.h"
#include "time.h"
// I did not write this Image-reading library. You can find the original author at the following link.
// https://github.com/nothings/stb/blob/master/stb_image.h
#define STB_IMAGE_IMPLEMENTATION
//#define STBI_MALLOC
//#define STBI_REALLOC
//#define STBI_FREE
#include "stb_image.h"
// minimum value function for integers
int imin(int num1, int num2){
if(num1 < num2){
return num1;
}
else{
return num2;
}
}
// minimum value function for doubles
double dmin(double num1, double num2){
if(num1 <= num2){
return num1;
}
else{
return num2;
}
}
// minimum value function for doubles
double dmax(double num1, double num2){
if(num1 >= num2){
return num1;
}
else{
return num2;
}
}
// makes an array index wrap to the other end if it does out of bounds
int indmod(int index, int size){ // index modulus
index %= size;
if(index < 0){
index += size;
}
return index;
}
// does literally everything else
int main(int argc, char *argv[]){
double point1[3] = {0,0,0};
double point2[3] = {0,0,0};
double point3[3] = {0,0,0};
double point4[3] = {0,0,0};
int hmheight = 0;
int hmwidth = 0;
int n = 0;
double const dpi = 1.0/8;
char filepath[300];
char modelpath[300];
int extlen = 0;
char newext[] = "stl";
srand(time(NULL));
printf("\n\n");
//check for filename
if(argc < 2){
printf("Enter file path/name: ");
scanf("%300s",&filepath);
}
else{
strcpy(filepath, argv[1]);
}
// populate heightmap
unsigned char *data = stbi_load(filepath, &hmwidth, &hmheight, &n, 0);
if(data == NULL){
printf("data = NULL\n\n");
exit(1);
}
double* heightmap;
heightmap = (double*)malloc(hmheight * hmwidth * sizeof(double));
if(heightmap == NULL){
printf("Memory for heightmap could not be allocated.\n\n");
exit(1);
}
for(int i = 0; i < hmwidth; i++){
for(int j = 0; j < hmheight; j++){
heightmap[i*hmheight+j] = 0.5f;
}
}
for(int i = 0; i < hmwidth; i++){
for(int j = 0; j < hmheight; j++){
for(int k = 0; k < n; k++){
heightmap[i*hmheight+j] += *(data+i*hmheight*n+j*n) / (127.0f*n);
}
heightmap[i*hmheight+j] = dmax(heightmap[i*hmheight+j], 0.1f);
}
}
stbi_image_free(data);
printf("STATUS___Read data into heightmap\n");
// bustin' out the spreadsheet again
// Uncomment the code below to get a .csv spreadsheet of the heightmap
/*
FILE *dumpfile;
dumpfile = fopen("heightmap.csv", "w");
for(int i = 0; i < hmheight*hmwidth; i++){
fprintf(dumpfile, "%f,", heightmap[i]);
if(i % hmwidth == 0){
fprintf(dumpfile, "\n");
}
}
fclose(dumpfile);
*/
// get model file name
for(int i = strlen(filepath)-1; i >= 0; i--){
if(filepath[i] == '.'){
extlen = i;
filepath[i+1] = '\0';
break;
}
if(i == 0){
printf("Could not recognize file path/name\n\n");
exit(1);
}
}
strcpy(modelpath, filepath);
strcat(modelpath, newext);
// writing to file
FILE *modelfile;
modelfile = fopen(modelpath, "w");
startSTL(modelfile);
// drawing the top of the mesh
for(int i = 0; i < hmwidth-1; i++){ // i is the distance from the left edge
for(int j = 0; j < hmheight-1; j++){ // j is the distance from the bottom edge
point1[0] = i*dpi;
point1[1] = j*dpi;
point1[2] = heightmap[i+((hmheight-1-j)*hmwidth)];
point2[0] = (i+1)*dpi;
point2[1] = j*dpi;
point2[2] = heightmap[(i+1)+((hmheight-1-j)*hmwidth)];
point3[0] = i*dpi;
point3[1] = (j+1)*dpi;
point3[2] = heightmap[i+((hmheight-2-j)*hmwidth)];
point4[0] = (i+1)*dpi;
point4[1] = (j+1)*dpi;
point4[2] = heightmap[(i+1)+((hmheight-2-j)*hmwidth)];
drawTriangle(modelfile, point1, point2, point4);
drawTriangle(modelfile, point1, point4, point3);
}
}
printf("STATUS___Drew top of mesh\n");
//drawing the sides of the mesh
for(int i = 0; i < hmwidth-1; i++){
// Front edge
point1[0] = i*dpi;
point1[1] = 0;
point1[2] = 0;
point2[0] = i*dpi;
point2[1] = 0;
point2[2] = heightmap[i+(hmwidth*(hmheight-1))];
point3[0] = (i+1)*dpi;
point3[1] = 0;
point3[2] = 0;
point4[0] = (i+1)*dpi;
point4[1] = 0;
point4[2] = heightmap[i+1+(hmwidth*(hmheight-1))];
drawTriangle(modelfile, point1, point4, point2);
drawTriangle(modelfile, point1, point3, point4);
// Back edge
point1[0] = i*dpi;
point1[1] = (hmheight-1)*dpi;
point1[2] = 0;
point2[0] = i*dpi;
point2[1] = (hmheight-1)*dpi;
point2[2] = heightmap[i];
point3[0] = (i+1)*dpi;
point3[1] = (hmheight-1)*dpi;
point3[2] = 0;
point4[0] = (i+1)*dpi;
point4[1] = (hmheight-1)*dpi;
point4[2] = heightmap[i+1];
drawTriangle(modelfile, point1, point2, point4);
drawTriangle(modelfile, point1, point4, point3);
}
printf("STATUS___Drew front and back of mesh\n");
for(int j = 0; j < hmheight-1; j++){
// Left edge
point1[0] = 0;
point1[1] = (hmheight-j-1)*dpi;
point1[2] = 0;
point2[0] = 0;
point2[1] = (hmheight-j-1)*dpi;
point2[2] = heightmap[j*hmwidth];
point3[0] = 0;
point3[1] = (hmheight-j-2)*dpi;
point3[2] = 0;
point4[0] = 0;
point4[1] = (hmheight-j-2)*dpi;
point4[2] = heightmap[(j+1)*hmwidth];
drawTriangle(modelfile, point1, point4, point2);
drawTriangle(modelfile, point1, point3, point4);
// Right edge
point1[0] = (hmwidth-1)*dpi;
point1[1] = (hmheight-j-1)*dpi;
point1[2] = 0;
point2[0] = (hmwidth-1)*dpi;
point2[1] = (hmheight-j-1)*dpi;
point2[2] = heightmap[(j*hmwidth)+hmwidth-1];
point3[0] = (hmwidth-1)*dpi;
point3[1] = (hmheight-j-2)*dpi;
point3[2] = 0;
point4[0] = (hmwidth-1)*dpi;
point4[1] = (hmheight-j-2)*dpi;
point4[2] = heightmap[((j+1)*hmwidth)+hmwidth-1];
drawTriangle(modelfile, point1, point2, point4);
drawTriangle(modelfile, point1, point4, point3);
}
printf("STATUS___Drew left and right sides of mesh\n");
//drawing the bottom of the mesh
point1[0] = 0;
point1[1] = 0;
point1[2] = 0;
point2[0] = 0;
point2[1] = dpi;
point2[2] = 0;
point3[0] = dpi;
point3[1] = 0;
point3[2] = 0;
drawTriangle(modelfile, point1, point2, point3);
point4[2] = 0;
for(int i = 1; i < imin(hmheight, hmwidth)-1; i++){
point1[0] = 0;
point1[1] = i * dpi;
point2[0] = 0;
point2[1] = (i+1) * dpi;
point3[0] = i * dpi;
point3[1] = 0;
point4[0] = (i+1) * dpi;
point4[1] = 0;
drawTriangle(modelfile, point1, point2, point4);
drawTriangle(modelfile, point1, point4, point3);
point1[0] = (hmwidth - i - 2) * dpi;
point1[1] = (hmheight - 1) * dpi;
point2[0] = (hmwidth - i - 1) * dpi;
point2[1] = (hmheight - 1) * dpi;
point3[0] = (hmwidth - 1) * dpi;
point3[1] = (hmheight - i - 2) * dpi;
point4[0] = (hmwidth - 1) * dpi;
point4[1] = (hmheight - i - 1) * dpi;
drawTriangle(modelfile, point1, point2, point4);
drawTriangle(modelfile, point1, point4, point3);
}
point1[0] = (hmwidth - 2) * dpi;
point1[1] = (hmheight - 1) * dpi;
point2[0] = (hmwidth - 1) * dpi;
point2[1] = (hmheight - 1) * dpi;
point3[0] = (hmwidth - 1) * dpi;
point3[1] = (hmheight - 2) * dpi;
drawTriangle(modelfile, point1, point2, point3);
if(hmheight > hmwidth){
for(int i = 0; i < abs(hmheight-hmwidth); i++){
point1[0] = (hmwidth-1) * dpi;
point1[1] = i * dpi;
point2[0] = (hmwidth-1) * dpi;
point2[1] = (i+1) * dpi;
point3[0] = 0;
point3[1] = (hmwidth+i-1) * dpi;
point4[0] = 0;
point4[1] = (hmwidth+i) * dpi;
drawTriangle(modelfile, point1, point3, point2);
drawTriangle(modelfile, point2, point3, point4);
}
}
else if(hmheight < hmwidth){
for(int i = 0; i < abs(hmheight-hmwidth); i++){
point1[1] = (0) * dpi;
point1[0] = (hmheight+i-1) * dpi;
point2[1] = (0) * dpi;
point2[0] = (hmheight+i) * dpi;
point3[1] = (hmheight-1) * dpi;
point3[0] = (i) * dpi;
point4[1] = (hmheight-1) * dpi;
point4[0] = (i+1) * dpi;
drawTriangle(modelfile, point1, point3, point2);
drawTriangle(modelfile, point2, point3, point4);
}
}
/*
// reference triangle that points at the origin
point1[0] = 0;
point1[1] = 0;
point2[0] = -0.1;
point2[1] = 0.1;
point2[2] = -0.1;
point3[0] = 0.1;
point3[1] = -0.1;
point3[2] = -0.1;
drawTriangle(modelfile, point1, point2, point3);
*/
printf("STATUS___Drew bottom of mesh\n\n\n");
endSTL(modelfile);
fclose(modelfile);
free(heightmap);
return 0;
}