#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <cstdint>
#include "SimpleImage.h"
#include <vector>
#include <math.h>
//Load a block of data from a file
//(this is the counterpart to SaveBlock from Assignment 1)
bool LoadBlock(const char * Path, uint16_t * Block, size_t Count) {
if(!Block) return false;
FILE * filePointer = NULL;
errno_t error = fopen_s(&filePointer, Path, "rb");
if(error) return false;
fread(Block, sizeof(uint16_t), Count, filePointer);
fclose(filePointer);
return true;
}
void calcAlphas(float height, float slope, float& alpha1, float& alpha2, float& alpha3) {
alpha1 = (1-height) * slope;
alpha2 = height;
alpha3 = height * slope;
}
int main(int argc, char * argv[])
{
//simple commandline validity check
if(argc<9 || strcmp(argv[1],"-r") != 0 || strcmp(argv[3],"-i") != 0
|| strcmp(argv[5],"-o_color") != 0 || strcmp(argv[7],"-o_normal") != 0)
{
puts("Syntax: TextureGenerator -r <Power of 2 resolution> -i <Input height field filename> "
"-o_color <Output color filename> -o_normal <Output normal filename>\n");
system("pause");
return -1;
}
//parse commandline arguments
int resolution = atoi(argv[2]);
char* filename_in = argv[4];
char* filename_out_color = argv[6];
char* filename_out_normal = argv[8];
//Allocate raw height field
std::vector<uint16_t> height_raw;
height_raw.resize(resolution*resolution);
//Load raw height field (the output from TerrainGenerator)
//Hint: &(height_raw[0]) obtains a pointer to the internal raw C++ array of the vector
bool success = LoadBlock(filename_in, &height_raw[0], resolution*resolution);
//print warning if write failed
if (!success)
{
puts("SaveBlock failed\n");
system("pause");
return -1;
}
//convert raw heightfield to floats in range [0;1]
std::vector<float> height(resolution*resolution);
for (int i=0; i<resolution*resolution; i++)
{
height[i] = (float)height_raw[i] / (float)UINT16_MAX;
}
//Load input textures
//TODO: use textures of your liking from /external/textures or
// use your own textures (do not commit textures from external
// to your own repository)
SimpleImage tex_flat_low ("../../external/textures/gras15.jpg");
SimpleImage tex_steep_low ("../../external/textures/ground02.jpg");
SimpleImage tex_flat_high ("../../external/textures/rock1.jpg");
SimpleImage tex_steep_high("../../external/textures/rock5.jpg");
//Create output images
SimpleImage img_color(resolution, resolution);
SimpleImage img_normal(resolution, resolution);
float df_du;
float df_dv;
//Iterate over height field
for (int y=0; y<resolution; y++)
{
for (int x=0; x<resolution; x++)
{
// TODO: Assignment 2.1.2
/* if(x!=resolution-1 && x!=0){
df_du = (height[(x+1)*resolution+y] - height[(x-1)*resolution+y])/2;}
else if(x==0){
df_du = (height[(x+1)*resolution+y] - height[(x)*resolution+y])/2;}
else if(x==resolution-1){
df_du = (height[(x)*resolution+y] - height[(x-1)*resolution+y])/2;}
if(y!=resolution-1 && y!= 0){
df_dv = (height[x*resolution+(y+1)] - height[x*resolution+(y-1)])/2;}
else if(y==0){
df_dv = (height[x*resolution+(y+1)] - height[x*resolution+y])/2;}
else if(y==resolution-1){
df_dv = (height[x*resolution+y] - height[x*resolution+(y-1)])/2;}
*/
float spz = 1/((2^16)-1);
float spxy = 1/((4096)-1);
float scale = spz/(2 * spxy);
if(x!=resolution-1 && x!=0){
df_du = (scale*(height[(x-1)*resolution+y] - height[(x+1)*resolution+y]));}
else if(x==0){
df_du = (scale*(height[(x)*resolution+y] - height[(x+1)*resolution+y]));}
else if(x==resolution-1){
df_du = (scale*(height[(x-1)*resolution+y] - height[(x)*resolution+y]));}
if(y!=resolution-1 && y!= 0){
df_dv = (scale*(height[x*resolution+(y-1)] - height[x*resolution+(y+1)]));}
else if(y==0){
df_dv = (scale*(height[x*resolution+(y)] - height[x*resolution+(y+1)]));}
else if(y==resolution-1){
df_dv = (scale*(height[x*resolution+(y-1)] - height[x*resolution+(y)]));}
//df_du = (scale*(height[(x-1)*resolution+y] - height[(x+1)*resolution+y]));
//df_dv = (scale*(height[x*resolution+(y-1)] - height[x*resolution+(y+1)]));
float n[3] ={df_du, df_dv, -1};
float normal_x = n[0];
float normal_y = n[1];
float normal_z = n[2];
float length = sqrt(normal_x*normal_x+normal_y*normal_y+normal_z*normal_z);
normal_x = normal_x/length;
normal_y = normal_y/length;
normal_z = normal_z/length;
//default normal pointing upward
/*float normal_x = 0.0f;
float normal_y = 0.0f;
float normal_z = 1.0f;*/
//map floats in range [-1;1] to bytes in range [0;255]
BYTE normal_r = (BYTE)((normal_x+1.0f)/2.0f * 255.0f);
BYTE normal_g = (BYTE)((normal_y+1.0f)/2.0f * 255.0f);
BYTE normal_b = (BYTE)((normal_z+1.0f)/2.0f * 255.0f);
//set all normals in normal image to default normal
img_normal.setPixel(x, y, normal_r, normal_g, normal_b);
// TODO: Assignment 2.1.3
//Texture Array
SimpleImage seamlessTexture[4] = {tex_flat_low,tex_steep_low,tex_flat_high,tex_steep_high};
//Blend Weights
float h = height[x*resolution+y] ;
float s = 1-normal_z;
float a1,a2,a3;
calcAlphas(h,s,a1,a2,a3);
// TODO: Assignment 2.1.4
//for a start, we simply use one of our textures for the color image
BYTE r, b, g;
BYTE r0,r1,r2,r3;
BYTE g0,g1,g2,g3;
BYTE b0,b1,b2,b3;
int x_seemless0 = x % seamlessTexture[0].getWidth(); //seemless texturing
int y_seemless0 = y % seamlessTexture[0].getHeight(); //seemless texturing
int x_seemless1 = x % seamlessTexture[1].getWidth(); //seemless texturing
int y_seemless1 = y % seamlessTexture[1].getHeight(); //seemless texturing
int x_seemless2 = x % seamlessTexture[2].getWidth(); //seemless texturing
int y_seemless2 = y % seamlessTexture[2].getHeight(); //seemless texturing
int x_seemless3 = x % seamlessTexture[3].getWidth(); //seemless texturing
int y_seemless3 = y % seamlessTexture[3].getHeight(); //seemless texturing
seamlessTexture[0].getPixel(x_seemless0,y_seemless0,r0,g0,b0);
seamlessTexture[1].getPixel(x_seemless1,y_seemless1,r1,g1,b1);
seamlessTexture[2].getPixel(x_seemless2,y_seemless2,r2,g2,b2);
seamlessTexture[3].getPixel(x_seemless3,y_seemless3,r3,g3,b3);
r = (BYTE)(a3*r3+(1-a3)*(a2*r2+(1-a2)*(a1*r1+(1-a1)*r0)));
g = (BYTE)(a3*g3+(1-a3)*(a2*g2+(1-a2)*(a1*g1+(1-a1)*g0)));
b = (BYTE)(a3*b3+(1-a3)*(a2*b2+(1-a2)*(a1*b1+(1-a1)*b0)));
img_color.setPixel(x, y, r, g, b);
}
}
//write color image
success = img_color.save(filename_out_color);
//print warning if write failed
if (!success)
{
puts("img_color.save failed\n");
system("pause");
return -1;
}
//write normal image
success = img_normal.save(filename_out_normal);
//print warning if write failed
if (!success)
{
puts("img_normal.save failed\n");
system("pause");
return -1;
}
return 0;
}