diff --git a/Makefile b/Makefile index 31e19462..f7c67205 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ SYSCONF_LINK = g++ -CPPFLAGS = -O3 +CPPFLAGS = -Wall -Wextra -Weffc++ -Werror -pedantic -std=c++98 LDFLAGS = -O3 LIBS = -lm diff --git a/geometry.cpp b/geometry.cpp index 4324f634..750652f7 100644 --- a/geometry.cpp +++ b/geometry.cpp @@ -4,10 +4,14 @@ #include #include "geometry.h" -template <> template <> Vec3::Vec3<>(const Vec3 &v) : x(int(v.x+.5)), y(int(v.y+.5)), z(int(v.z+.5)) { -} +template <> Vec3::Vec3(Matrix m) : x(m[0][0]/m[3][0]), y(m[1][0]/m[3][0]), z(m[2][0]/m[3][0]) {} +template <> template <> Vec3::Vec3<>(const Vec3 &v) : x(int(v.x+.5)), y(int(v.y+.5)), z(int(v.z+.5)) {} +template <> template <> Vec3::Vec3<>(const Vec3 &v) : x(v.x), y(v.y), z(v.z) {} -template <> template <> Vec3::Vec3<>(const Vec3 &v) : x(v.x), y(v.y), z(v.z) { +Matrix::Matrix(Vec3f v) : m(std::vector >(4, std::vector(1, 1.f))), rows(4), cols(1) { + m[0][0] = v.x; + m[1][0] = v.y; + m[2][0] = v.z; } diff --git a/geometry.h b/geometry.h index 141d5367..ec2b85b3 100644 --- a/geometry.h +++ b/geometry.h @@ -2,23 +2,18 @@ #define __GEOMETRY_H__ #include +#include + +class Matrix; template struct Vec2 { t x, y; Vec2() : x(t()), y(t()) {} Vec2(t _x, t _y) : x(_x), y(_y) {} - Vec2(const Vec2 &v) : x(t()), y(t()) { *this = v; } - Vec2 & operator =(const Vec2 &v) { - if (this != &v) { - x = v.x; - y = v.y; - } - return *this; - } Vec2 operator +(const Vec2 &V) const { return Vec2(x+V.x, y+V.y); } Vec2 operator -(const Vec2 &V) const { return Vec2(x-V.x, y-V.y); } Vec2 operator *(float f) const { return Vec2(x*f, y*f); } - t& operator[](const int i) { if (x<=0) return x; else return y; } + t& operator[](const int i) { return i<=0 ? x : y; } template friend std::ostream& operator<<(std::ostream& s, Vec2& v); }; @@ -26,16 +21,8 @@ template struct Vec3 { t x, y, z; Vec3() : x(t()), y(t()), z(t()) { } Vec3(t _x, t _y, t _z) : x(_x), y(_y), z(_z) {} + Vec3(Matrix m); template Vec3(const Vec3 &v); - Vec3(const Vec3 &v) : x(t()), y(t()), z(t()) { *this = v; } - Vec3 & operator =(const Vec3 &v) { - if (this != &v) { - x = v.x; - y = v.y; - z = v.z; - } - return *this; - } Vec3 operator ^(const Vec3 &v) const { return Vec3(y*v.z-z*v.y, z*v.x-x*v.z, x*v.y-y*v.x); } Vec3 operator +(const Vec3 &v) const { return Vec3(x+v.x, y+v.y, z+v.z); } Vec3 operator -(const Vec3 &v) const { return Vec3(x-v.x, y-v.y, z-v.z); } @@ -43,7 +30,7 @@ template struct Vec3 { t operator *(const Vec3 &v) const { return x*v.x + y*v.y + z*v.z; } float norm () const { return std::sqrt(x*x+y*y+z*z); } Vec3 & normalize(t l=1) { *this = (*this)*(l/norm()); return *this; } - t& operator[](const int i) { if (i<=0) return x; else if (i==1) return y; else return z; } + t& operator[](const int i) { return i<=0 ? x : (1==i ? y : z); } template friend std::ostream& operator<<(std::ostream& s, Vec3& v); }; @@ -68,26 +55,21 @@ template std::ostream& operator<<(std::ostream& s, Vec3& v) { ////////////////////////////////////////////////////////////////////////////////////////////// -const int DEFAULT_ALLOC=4; - class Matrix { std::vector > m; int rows, cols; public: - Matrix(int r=DEFAULT_ALLOC, int c=DEFAULT_ALLOC); - inline int nrows(); - inline int ncols(); - + Matrix(int r=4, int c=4); + Matrix(Vec3f v); + int nrows(); + int ncols(); static Matrix identity(int dimensions); std::vector& operator[](const int i); Matrix operator*(const Matrix& a); Matrix transpose(); Matrix inverse(); - friend std::ostream& operator<<(std::ostream& s, Matrix& m); }; -///////////////////////////////////////////////////////////////////////////////////////////// - #endif //__GEOMETRY_H__ diff --git a/main.cpp b/main.cpp index f80d94f9..1e316b58 100644 --- a/main.cpp +++ b/main.cpp @@ -14,19 +14,6 @@ int *zbuffer = NULL; Vec3f light_dir(0,0,-1); Vec3f camera(0,0,3); -Vec3f m2v(Matrix m) { - return Vec3f(m[0][0]/m[3][0], m[1][0]/m[3][0], m[2][0]/m[3][0]); -} - -Matrix v2m(Vec3f v) { - Matrix m(4, 1); - m[0][0] = v.x; - m[1][0] = v.y; - m[2][0] = v.z; - m[3][0] = 1.f; - return m; -} - Matrix viewport(int x, int y, int w, int h) { Matrix m = Matrix::identity(4); m[0][3] = x+w/2.f; @@ -57,14 +44,13 @@ void triangle(Vec3i t0, Vec3i t1, Vec3i t2, Vec2i uv0, Vec2i uv1, Vec2i uv2, TGA Vec2i uvB = second_half ? uv1 + (uv2-uv1)*beta : uv0 + (uv1-uv0)*beta; if (A.x>B.x) { std::swap(A, B); std::swap(uvA, uvB); } for (int j=A.x; j<=B.x; j++) { - float phi = B.x==A.x ? 1. : (float)(j-A.x)/(float)(B.x-A.x); + float phi = B.x==A.x ? 1. : (float)(j-A.x)/(B.x-A.x); Vec3i P = Vec3f(A) + Vec3f(B-A)*phi; Vec2i uvP = uvA + (uvB-uvA)*phi; int idx = P.x+P.y*width; if (zbuffer[idx]diffuse(uvP); - image.set(P.x, P.y, TGAColor(color.r*intensity, color.g*intensity, color.b*intensity)); + image.set(P.x, P.y, model->diffuse(uvP)*intensity); } } } @@ -94,7 +80,7 @@ int main(int argc, char** argv) { Vec3f world_coords[3]; for (int j=0; j<3; j++) { Vec3f v = model->vert(face[j]); - screen_coords[j] = m2v(ViewPort*Projection*v2m(v)); + screen_coords[j] = Vec3f(ViewPort*Projection*Matrix(v)); world_coords[j] = v; } Vec3f n = (world_coords[2]-world_coords[0])^(world_coords[1]-world_coords[0]); diff --git a/model.cpp b/model.cpp index f45b55c4..7731bd78 100644 --- a/model.cpp +++ b/model.cpp @@ -5,7 +5,7 @@ #include #include "model.h" -Model::Model(const char *filename) : verts_(), faces_(), norms_(), uv_() { +Model::Model(const char *filename) : verts_(), faces_(), norms_(), uv_(), diffusemap_() { std::ifstream in; in.open (filename, std::ifstream::in); if (in.fail()) return; diff --git a/tgaimage.cpp b/tgaimage.cpp index 12eef1cb..7ec68bc2 100644 --- a/tgaimage.cpp +++ b/tgaimage.cpp @@ -9,344 +9,349 @@ TGAImage::TGAImage() : data(NULL), width(0), height(0), bytespp(0) { } TGAImage::TGAImage(int w, int h, int bpp) : data(NULL), width(w), height(h), bytespp(bpp) { - unsigned long nbytes = width*height*bytespp; - data = new unsigned char[nbytes]; - memset(data, 0, nbytes); + unsigned long nbytes = width*height*bytespp; + data = new unsigned char[nbytes]; + memset(data, 0, nbytes); } -TGAImage::TGAImage(const TGAImage &img) { - width = img.width; - height = img.height; - bytespp = img.bytespp; - unsigned long nbytes = width*height*bytespp; - data = new unsigned char[nbytes]; - memcpy(data, img.data, nbytes); +TGAImage::TGAImage(const TGAImage &img) : data(NULL), width(img.width), height(img.height), bytespp(img.bytespp) { + unsigned long nbytes = width*height*bytespp; + data = new unsigned char[nbytes]; + memcpy(data, img.data, nbytes); } TGAImage::~TGAImage() { - if (data) delete [] data; + if (data) delete [] data; } TGAImage & TGAImage::operator =(const TGAImage &img) { - if (this != &img) { - if (data) delete [] data; - width = img.width; - height = img.height; - bytespp = img.bytespp; - unsigned long nbytes = width*height*bytespp; - data = new unsigned char[nbytes]; - memcpy(data, img.data, nbytes); - } - return *this; + if (this != &img) { + if (data) delete [] data; + width = img.width; + height = img.height; + bytespp = img.bytespp; + unsigned long nbytes = width*height*bytespp; + data = new unsigned char[nbytes]; + memcpy(data, img.data, nbytes); + } + return *this; } bool TGAImage::read_tga_file(const char *filename) { - if (data) delete [] data; - data = NULL; - std::ifstream in; - in.open (filename, std::ios::binary); - if (!in.is_open()) { - std::cerr << "can't open file " << filename << "\n"; - in.close(); - return false; - } - TGA_Header header; - in.read((char *)&header, sizeof(header)); - if (!in.good()) { - in.close(); - std::cerr << "an error occured while reading the header\n"; - return false; - } - width = header.width; - height = header.height; - bytespp = header.bitsperpixel>>3; - if (width<=0 || height<=0 || (bytespp!=GRAYSCALE && bytespp!=RGB && bytespp!=RGBA)) { - in.close(); - std::cerr << "bad bpp (or width/height) value\n"; - return false; - } - unsigned long nbytes = bytespp*width*height; - data = new unsigned char[nbytes]; - if (3==header.datatypecode || 2==header.datatypecode) { - in.read((char *)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; - } - if (!(header.imagedescriptor & 0x20)) { - flip_vertically(); - } - if (header.imagedescriptor & 0x10) { - flip_horizontally(); - } - std::cerr << width << "x" << height << "/" << bytespp*8 << "\n"; - in.close(); - return true; + if (data) delete [] data; + data = NULL; + std::ifstream in; + in.open (filename, std::ios::binary); + if (!in.is_open()) { + std::cerr << "can't open file " << filename << "\n"; + in.close(); + return false; + } + TGA_Header header; + in.read((char *)&header, sizeof(header)); + if (!in.good()) { + in.close(); + std::cerr << "an error occured while reading the header\n"; + return false; + } + width = header.width; + height = header.height; + bytespp = header.bitsperpixel>>3; + if (width<=0 || height<=0 || (bytespp!=GRAYSCALE && bytespp!=RGB && bytespp!=RGBA)) { + in.close(); + std::cerr << "bad bpp (or width/height) value\n"; + return false; + } + unsigned long nbytes = bytespp*width*height; + data = new unsigned char[nbytes]; + if (3==header.datatypecode || 2==header.datatypecode) { + in.read((char *)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; + } + if (!(header.imagedescriptor & 0x20)) { + flip_vertically(); + } + if (header.imagedescriptor & 0x10) { + flip_horizontally(); + } + std::cerr << width << "x" << height << "/" << bytespp*8 << "\n"; + in.close(); + return true; } bool TGAImage::load_rle_data(std::ifstream &in) { - unsigned long pixelcount = width*height; - unsigned long currentpixel = 0; - unsigned long currentbyte = 0; - TGAColor colorbuffer; - do { - unsigned char chunkheader = 0; - chunkheader = in.get(); - if (!in.good()) { - std::cerr << "an error occured while reading the data\n"; - return false; - } - if (chunkheader<128) { - chunkheader++; - for (int i=0; ipixelcount) { - std::cerr << "Too many pixels read\n"; - return false; - } - } - } else { - chunkheader -= 127; - in.read((char *)colorbuffer.raw, bytespp); - if (!in.good()) { - std::cerr << "an error occured while reading the header\n"; - return false; - } - for (int i=0; ipixelcount) { - std::cerr << "Too many pixels read\n"; - return false; - } - } - } - } while (currentpixel < pixelcount); - return true; + unsigned long pixelcount = width*height; + unsigned long currentpixel = 0; + unsigned long currentbyte = 0; + TGAColor colorbuffer; + do { + unsigned char chunkheader = 0; + chunkheader = in.get(); + if (!in.good()) { + std::cerr << "an error occured while reading the data\n"; + return false; + } + if (chunkheader<128) { + chunkheader++; + for (int i=0; ipixelcount) { + std::cerr << "Too many pixels read\n"; + return false; + } + } + } else { + chunkheader -= 127; + in.read((char *)colorbuffer.bgra, bytespp); + if (!in.good()) { + std::cerr << "an error occured while reading the header\n"; + return false; + } + for (int i=0; ipixelcount) { + std::cerr << "Too many pixels read\n"; + return false; + } + } + } + } while (currentpixel < pixelcount); + return true; } bool TGAImage::write_tga_file(const char *filename, bool rle) { - unsigned char developer_area_ref[4] = {0, 0, 0, 0}; - unsigned char extension_area_ref[4] = {0, 0, 0, 0}; - unsigned char 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); - if (!out.is_open()) { - std::cerr << "can't open file " << filename << "\n"; - out.close(); - return false; - } - TGA_Header header; - memset((void *)&header, 0, sizeof(header)); - header.bitsperpixel = bytespp<<3; - header.width = width; - header.height = height; - header.datatypecode = (bytespp==GRAYSCALE?(rle?11:3):(rle?10:2)); - header.imagedescriptor = 0x20; // top-left origin - out.write((char *)&header, sizeof(header)); - if (!out.good()) { - out.close(); - std::cerr << "can't dump the tga file\n"; - return false; - } - if (!rle) { - out.write((char *)data, width*height*bytespp); - 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((char *)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((char *)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((char *)footer, sizeof(footer)); - if (!out.good()) { - std::cerr << "can't dump the tga file\n"; - out.close(); - return false; - } - out.close(); - return true; + unsigned char developer_area_ref[4] = {0, 0, 0, 0}; + unsigned char extension_area_ref[4] = {0, 0, 0, 0}; + unsigned char 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); + if (!out.is_open()) { + std::cerr << "can't open file " << filename << "\n"; + out.close(); + return false; + } + TGA_Header header; + memset((void *)&header, 0, sizeof(header)); + header.bitsperpixel = bytespp<<3; + header.width = width; + header.height = height; + header.datatypecode = (bytespp==GRAYSCALE?(rle?11:3):(rle?10:2)); + header.imagedescriptor = 0x20; // top-left origin + out.write((char *)&header, sizeof(header)); + if (!out.good()) { + out.close(); + std::cerr << "can't dump the tga file\n"; + return false; + } + if (!rle) { + out.write((char *)data, width*height*bytespp); + 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((char *)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((char *)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((char *)footer, sizeof(footer)); + if (!out.good()) { + std::cerr << "can't dump the tga file\n"; + out.close(); + return false; + } + out.close(); + return true; } // TODO: it is not necessary to break a raw chunk for two equal pixels (for the matter of the resulting size) bool TGAImage::unload_rle_data(std::ofstream &out) { - const unsigned char max_chunk_length = 128; - unsigned long npixels = width*height; - unsigned long curpix = 0; - while (curpix=width || y>=height) { - return TGAColor(); - } - return TGAColor(data+(x+y*width)*bytespp, bytespp); + if (!data || x<0 || y<0 || x>=width || y>=height) { + return TGAColor(); + } + return TGAColor(data+(x+y*width)*bytespp, bytespp); } -bool TGAImage::set(int x, int y, TGAColor c) { - if (!data || x<0 || y<0 || x>=width || y>=height) { - return false; - } - memcpy(data+(x+y*width)*bytespp, c.raw, bytespp); - return true; +bool TGAImage::set(int x, int y, TGAColor &c) { + if (!data || x<0 || y<0 || x>=width || y>=height) { + return false; + } + memcpy(data+(x+y*width)*bytespp, c.bgra, bytespp); + return true; +} + +bool TGAImage::set(int x, int y, const TGAColor &c) { + if (!data || x<0 || y<0 || x>=width || y>=height) { + return false; + } + memcpy(data+(x+y*width)*bytespp, c.bgra, bytespp); + return true; } int TGAImage::get_bytespp() { - return bytespp; + return bytespp; } int TGAImage::get_width() { - return width; + return width; } int TGAImage::get_height() { - return height; + return height; } bool TGAImage::flip_horizontally() { - if (!data) return false; - int half = width>>1; - for (int i=0; i>1; + for (int i=0; i>1; - for (int j=0; j>1; + for (int j=0; j=(int)width) { - errx -= width; - nx += bytespp; - memcpy(tdata+nscanline+nx, data+oscanline+ox, bytespp); - } - } - erry += h; - oscanline += olinebytes; - while (erry>=(int)height) { - if (erry>=(int)height<<1) // it means we jump over a scanline - memcpy(tdata+nscanline+nlinebytes, tdata+nscanline, nlinebytes); - erry -= height; - nscanline += nlinebytes; - } - } - delete [] data; - data = tdata; - width = w; - height = h; - return true; + if (w<=0 || h<=0 || !data) return false; + unsigned char *tdata = new unsigned char[w*h*bytespp]; + int nscanline = 0; + int oscanline = 0; + int erry = 0; + unsigned long nlinebytes = w*bytespp; + unsigned long olinebytes = width*bytespp; + for (int j=0; j=(int)width) { + errx -= width; + nx += bytespp; + memcpy(tdata+nscanline+nx, data+oscanline+ox, bytespp); + } + } + erry += h; + oscanline += olinebytes; + while (erry>=(int)height) { + if (erry>=(int)height<<1) // it means we jump over a scanline + memcpy(tdata+nscanline+nlinebytes, tdata+nscanline, nlinebytes); + erry -= height; + nscanline += nlinebytes; + } + } + delete [] data; + data = tdata; + width = w; + height = h; + return true; } diff --git a/tgaimage.h b/tgaimage.h index 78b9f372..22d14e72 100644 --- a/tgaimage.h +++ b/tgaimage.h @@ -5,92 +5,93 @@ #pragma pack(push,1) struct TGA_Header { - char idlength; - char colormaptype; - char datatypecode; - short colormaporigin; - short colormaplength; - char colormapdepth; - short x_origin; - short y_origin; - short width; - short height; - char bitsperpixel; - char imagedescriptor; + char idlength; + char colormaptype; + char datatypecode; + short colormaporigin; + short colormaplength; + char colormapdepth; + short x_origin; + short y_origin; + short width; + short height; + char bitsperpixel; + char imagedescriptor; }; #pragma pack(pop) struct TGAColor { - union { - struct { - unsigned char b, g, r, a; - }; - unsigned char raw[4]; - unsigned int val; - }; - int bytespp; - - TGAColor() : val(0), bytespp(1) { - } - - TGAColor(unsigned char R, unsigned char G, unsigned char B, unsigned char A=255) : b(B), g(G), r(R), a(A), bytespp(4) { - } - - TGAColor(int v, int bpp) : val(v), bytespp(bpp) { - } - - TGAColor(const TGAColor &c) : val(c.val), bytespp(c.bytespp) { - } - - TGAColor(const unsigned char *p, int bpp) : val(0), bytespp(bpp) { - for (int i=0; i