diff --git a/geometry.h b/geometry.h index 9b669a25..6b418b2d 100644 --- a/geometry.h +++ b/geometry.h @@ -4,11 +4,11 @@ #include template struct vec { - double & operator[](const int i) { assert(i>=0 && i=0 && i=0 && i=0 && i double operator*(const vec& lhs, const vec& rhs) { @@ -65,23 +65,21 @@ template std::ostream& operator<<(std::ostream& out, const vec& v) { } template<> struct vec<2> { + double x = 0, y = 0; double& operator[](const int i) { assert(i>=0 && i<2); return i ? y : x; } double operator[](const int i) const { assert(i>=0 && i<2); return i ? y : x; } double norm2() const { return *this * *this; } double norm() const { return std::sqrt(norm2()); } - vec & normalize() { *this = (*this)/norm(); return *this; } - - double x{}, y{}; + vec<2> normalized() { return (*this)/norm(); } }; template<> struct vec<3> { + double x = 0, y = 0, z = 0; double& operator[](const int i) { assert(i>=0 && i<3); return i ? (1==i ? y : z) : x; } double operator[](const int i) const { assert(i>=0 && i<3); return i ? (1==i ? y : z) : x; } double norm2() const { return *this * *this; } double norm() const { return std::sqrt(norm2()); } - vec & normalize() { *this = (*this)/norm(); return *this; } - - double x{}, y{}, z{}; + vec<3> normalized() { return (*this)/norm(); } }; typedef vec<2> vec2; diff --git a/main.cpp b/main.cpp index 38a0685e..f89ba7f1 100644 --- a/main.cpp +++ b/main.cpp @@ -4,11 +4,10 @@ constexpr int width = 800; // output image size constexpr int height = 800; - -const vec3 light_dir{1,1,1}; // light source -const vec3 eye{1,1,3}; // camera position -const vec3 center{0,0,0}; // camera direction -const vec3 up{0,1,0}; // camera up vector +constexpr vec3 light_dir{1,1,1}; // light source +constexpr vec3 eye{1,1,3}; // camera position +constexpr vec3 center{0,0,0}; // camera direction +constexpr vec3 up{0,1,0}; // camera up vector extern mat<4,4> ModelView; // "OpenGL" state matrices extern mat<4,4> Projection; @@ -21,7 +20,7 @@ struct Shader : IShader { mat<3,3> view_tri; // triangle in view coordinates Shader(const Model &m) : model(m) { - uniform_l = proj<3>((ModelView*embed<4>(light_dir, 0.))).normalize(); // transform the light vector to view coordinates + uniform_l = proj<3>((ModelView*embed<4>(light_dir, 0.))).normalized(); // transform the light vector to view coordinates } virtual void vertex(const int iface, const int nthvert, vec4& gl_Position) { @@ -33,7 +32,7 @@ struct Shader : IShader { } virtual bool fragment(const vec3 bar, TGAColor &gl_FragColor) { - vec3 bn = (varying_nrm*bar).normalize(); // per-vertex normal interpolation + vec3 bn = (varying_nrm*bar).normalized(); // per-vertex normal interpolation vec2 uv = varying_uv*bar; // tex coord interpolation // for the math refer to the tangent space normal mapping lecture @@ -41,11 +40,11 @@ struct Shader : IShader { mat<3,3> AI = mat<3,3>{ {view_tri.col(1) - view_tri.col(0), view_tri.col(2) - view_tri.col(0), bn} }.invert(); vec3 i = AI * vec3{varying_uv[0][1] - varying_uv[0][0], varying_uv[0][2] - varying_uv[0][0], 0}; vec3 j = AI * vec3{varying_uv[1][1] - varying_uv[1][0], varying_uv[1][2] - varying_uv[1][0], 0}; - mat<3,3> B = mat<3,3>{ {i.normalize(), j.normalize(), bn} }.transpose(); + mat<3,3> B = mat<3,3>{ {i.normalized(), j.normalized(), bn} }.transpose(); - vec3 n = (B * model.normal(uv)).normalize(); // transform the normal from the texture to the tangent space + vec3 n = (B * model.normal(uv)).normalized(); // transform the normal from the texture to the tangent space double diff = std::max(0., n*uniform_l); // diffuse light intensity - vec3 r = (n*(n*uniform_l)*2 - uniform_l).normalize(); // reflected light direction, specular mapping is described here: https://github.com/ssloy/tinyrenderer/wiki/Lesson-6-Shaders-for-the-software-renderer + vec3 r = (n*(n*uniform_l)*2 - uniform_l).normalized(); // reflected light direction, specular mapping is described here: https://github.com/ssloy/tinyrenderer/wiki/Lesson-6-Shaders-for-the-software-renderer double spec = std::pow(std::max(-r.z, 0.), 5+sample2D(model.specular(), uv)[0]); // specular intensity, note that the camera lies on the z-axis (in view), therefore simple -r.z TGAColor c = sample2D(model.diffuse(), uv); diff --git a/model.cpp b/model.cpp index 2790ee09..a1c4d4c0 100644 --- a/model.cpp +++ b/model.cpp @@ -20,7 +20,7 @@ Model::Model(const std::string filename) { iss >> trash >> trash; vec3 n; for (int i=0;i<3;i++) iss >> n[i]; - norms.push_back(n.normalize()); + norms.push_back(n.normalized()); } else if (!line.compare(0, 3, "vt ")) { iss >> trash >> trash; vec2 uv; @@ -38,12 +38,10 @@ Model::Model(const std::string filename) { } if (3!=cnt) { std::cerr << "Error: the obj file is supposed to be triangulated" << std::endl; - in.close(); return; } } } - in.close(); std::cerr << "# v# " << nverts() << " f# " << nfaces() << " vt# " << tex_coord.size() << " vn# " << norms.size() << std::endl; load_texture(filename, "_diffuse.tga", diffusemap ); load_texture(filename, "_nm_tangent.tga", normalmap ); diff --git a/our_gl.cpp b/our_gl.cpp index 6ef5a4ce..7f1afac8 100644 --- a/our_gl.cpp +++ b/our_gl.cpp @@ -14,9 +14,9 @@ void projection(const double f) { // check https://en.wikipedia.org/wiki/Camera_ } void lookat(const vec3 eye, const vec3 center, const vec3 up) { // check https://github.com/ssloy/tinyrenderer/wiki/Lesson-5-Moving-the-camera - vec3 z = (center-eye).normalize(); - vec3 x = cross(up,z).normalize(); - vec3 y = cross(z, x).normalize(); + vec3 z = (center-eye).normalized(); + vec3 x = cross(up,z).normalized(); + vec3 y = cross(z, x).normalized(); mat<4,4> Minv = {{{x.x,x.y,x.z,0}, {y.x,y.y,y.z,0}, {z.x,z.y,z.z,0}, {0,0,0,1}}}; mat<4,4> Tr = {{{1,0,0,-eye.x}, {0,1,0,-eye.y}, {0,0,1,-eye.z}, {0,0,0,1}}}; ModelView = Minv*Tr; diff --git a/tgaimage.cpp b/tgaimage.cpp index ebbca767..c9e61ada 100644 --- a/tgaimage.cpp +++ b/tgaimage.cpp @@ -6,16 +6,14 @@ TGAImage::TGAImage(const int w, const int h, const int bpp) : w(w), h(h), bpp(bp bool TGAImage::read_tga_file(const std::string filename) { std::ifstream in; - in.open (filename, std::ios::binary); + in.open(filename, std::ios::binary); if (!in.is_open()) { std::cerr << "can't open file " << filename << "\n"; - in.close(); return false; } TGAHeader header; in.read(reinterpret_cast(&header), sizeof(header)); if (!in.good()) { - in.close(); std::cerr << "an error occured while reading the header\n"; return false; } @@ -23,7 +21,6 @@ bool TGAImage::read_tga_file(const std::string filename) { h = header.height; bpp = header.bitsperpixel>>3; if (w<=0 || h<=0 || (bpp!=GRAYSCALE && bpp!=RGB && bpp!=RGBA)) { - in.close(); std::cerr << "bad bpp (or width/height) value\n"; return false; } @@ -32,18 +29,15 @@ bool TGAImage::read_tga_file(const std::string filename) { if (3==header.datatypecode || 2==header.datatypecode) { in.read(reinterpret_cast(data.data()), nbytes); if (!in.good()) { - in.close(); std::cerr << "an error occured while reading the data\n"; return false; } } else if (10==header.datatypecode||11==header.datatypecode) { if (!load_rle_data(in)) { - in.close(); std::cerr << "an error occured while reading the data\n"; return false; } } else { - in.close(); std::cerr << "unknown file format " << (int)header.datatypecode << "\n"; return false; } @@ -52,7 +46,6 @@ bool TGAImage::read_tga_file(const std::string filename) { if (header.imagedescriptor & 0x10) flip_horizontally(); std::cerr << w << "x" << h << "/" << bpp*8 << "\n"; - in.close(); return true; } @@ -110,13 +103,12 @@ bool TGAImage::write_tga_file(const std::string filename, const bool vflip, cons constexpr std::uint8_t extension_area_ref[4] = {0, 0, 0, 0}; constexpr std::uint8_t footer[18] = {'T','R','U','E','V','I','S','I','O','N','-','X','F','I','L','E','.','\0'}; std::ofstream out; - out.open (filename, std::ios::binary); + out.open(filename, std::ios::binary); if (!out.is_open()) { std::cerr << "can't open file " << filename << "\n"; - out.close(); return false; } - TGAHeader header; + TGAHeader header = {}; header.bitsperpixel = bpp<<3; header.width = w; header.height = h; @@ -124,7 +116,6 @@ bool TGAImage::write_tga_file(const std::string filename, const bool vflip, cons header.imagedescriptor = vflip ? 0x00 : 0x20; // top-left or bottom-left origin out.write(reinterpret_cast(&header), sizeof(header)); if (!out.good()) { - out.close(); std::cerr << "can't dump the tga file\n"; return false; } @@ -132,33 +123,27 @@ bool TGAImage::write_tga_file(const std::string filename, const bool vflip, cons out.write(reinterpret_cast(data.data()), w*h*bpp); if (!out.good()) { std::cerr << "can't unload raw data\n"; - out.close(); return false; } } else if (!unload_rle_data(out)) { - out.close(); std::cerr << "can't unload rle data\n"; return false; } out.write(reinterpret_cast(developer_area_ref), sizeof(developer_area_ref)); if (!out.good()) { std::cerr << "can't dump the tga file\n"; - out.close(); return false; } out.write(reinterpret_cast(extension_area_ref), sizeof(extension_area_ref)); if (!out.good()) { std::cerr << "can't dump the tga file\n"; - out.close(); return false; } out.write(reinterpret_cast(footer), sizeof(footer)); if (!out.good()) { std::cerr << "can't dump the tga file\n"; - out.close(); return false; } - out.close(); return true; } @@ -205,7 +190,10 @@ bool TGAImage::unload_rle_data(std::ofstream &out) const { TGAColor TGAImage::get(const int x, const int y) const { if (!data.size() || x<0 || y<0 || x>=w || y>=h) return {}; - return TGAColor(data.data()+(x+y*w)*bpp, bpp); + TGAColor ret = {0, 0, 0, 0, bpp}; + const std::uint8_t *p = data.data()+(x+y*w)*bpp; + for (int i=bpp; i--; ret.bgra[i] = p[i]); + return ret; } void TGAImage::set(int x, int y, const TGAColor &c) { diff --git a/tgaimage.h b/tgaimage.h index b9f9ac2f..976818a7 100644 --- a/tgaimage.h +++ b/tgaimage.h @@ -5,30 +5,24 @@ #pragma pack(push,1) struct TGAHeader { - std::uint8_t idlength{}; - std::uint8_t colormaptype{}; - std::uint8_t datatypecode{}; - std::uint16_t colormaporigin{}; - std::uint16_t colormaplength{}; - std::uint8_t colormapdepth{}; - std::uint16_t x_origin{}; - std::uint16_t y_origin{}; - std::uint16_t width{}; - std::uint16_t height{}; - std::uint8_t bitsperpixel{}; - std::uint8_t imagedescriptor{}; + std::uint8_t idlength = 0; + std::uint8_t colormaptype = 0; + std::uint8_t datatypecode = 0; + std::uint16_t colormaporigin = 0; + std::uint16_t colormaplength = 0; + std::uint8_t colormapdepth = 0; + std::uint16_t x_origin = 0; + std::uint16_t y_origin = 0; + std::uint16_t width = 0; + std::uint16_t height = 0; + std::uint8_t bitsperpixel = 0; + std::uint8_t imagedescriptor = 0; }; #pragma pack(pop) struct TGAColor { std::uint8_t bgra[4] = {0,0,0,0}; - std::uint8_t bytespp = {0}; - - TGAColor() = default; - TGAColor(const std::uint8_t R, const std::uint8_t G, const std::uint8_t B, const std::uint8_t A=255) : bgra{B,G,R,A}, bytespp(4) { } - TGAColor(const std::uint8_t *p, const std::uint8_t bpp) : bytespp(bpp) { - for (int i=bpp; i--; bgra[i] = p[i]); - } + std::uint8_t bytespp = 4; std::uint8_t& operator[](const int i) { return bgra[i]; } }; @@ -49,9 +43,9 @@ struct TGAImage { bool load_rle_data(std::ifstream &in); bool unload_rle_data(std::ofstream &out) const; - int w = 0; - int h = 0; - int bpp = 0; + int w = 0; + int h = 0; + std::uint8_t bpp = 0; std::vector data = {}; };