Advertisement
Guest User

graphics

a guest
Feb 27th, 2015
194
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 9.35 KB | None | 0 0
  1. #include <SDL/SDL.h>
  2. #include <cmath>
  3. #include <algorithm>
  4. #include <iostream>
  5. #include <bits/stdc++.h>
  6. using namespace std;
  7. const int SCREEN_WIDTH = 640, SCREEN_HEIGHT = 480;
  8. void setpixel(SDL_Surface * screen, int x, int y, Uint32 color) {
  9.     if (x < 0 || x >= SCREEN_WIDTH || y < 0 || y >= SCREEN_HEIGHT) return ;
  10.     Uint32 * pixels = (Uint32*)screen->pixels;
  11.     pixels[y * SCREEN_WIDTH + x] = color;
  12. }
  13. double z_buffer[SCREEN_HEIGHT][SCREEN_WIDTH];
  14. struct Camera {
  15.     double ze, zv, phi, theta, gama;
  16.     Camera() : ze(-500), zv(-200), phi(0), theta(0), gama(0) { }
  17. };
  18. struct Point {
  19.     double x, y, z;
  20.     Point(double cx = 0, double cy = 0, double cz = 0):
  21.         x(cx), y(cy), z(cz) { }
  22.     //transformations
  23.     Point rotateY(double t) const {
  24.         double nz = z * cos(t) - x * sin(t);
  25.         double nx = z * sin(t) + x * cos(t);
  26.         return Point(nx, y, nz);
  27.     }
  28.     Point rotateZ(double t) const {
  29.         double nx = x * cos(t) - y * sin(t);
  30.         double ny = x * sin(t) + y * cos(t);
  31.         return Point(nx, ny, z);
  32.     }
  33.     Point rotateX(double t) const {
  34.         double ny = y * cos(t) - z * sin(t);
  35.         double nz = y * sin(t) + z * cos(t);
  36.         return Point(x, ny, nz);
  37.     }
  38.     //crude pipelining steps
  39.     Point toVC(const Camera & cam) const {
  40.         return rotateY(-cam.phi).rotateX(-cam.theta);
  41.     }
  42.     Point project(const Camera & cam) const {
  43.         double f = (cam.ze - cam.zv) / (cam.ze - z);
  44.         double xp = x * f, yp = y * f;
  45.         return Point(xp, yp, cam.zv);
  46.     }
  47.     Point to2dview() const {
  48.         return Point(x + SCREEN_WIDTH / 2, y + SCREEN_HEIGHT / 2, z);
  49.     }
  50.     //vector math
  51.     Point operator-(const Point & b) const {
  52.         return Point(x - b.x, y - b.y, z - b.z);
  53.     }
  54.     double magnitude() const {
  55.         return sqrt(x * x + y * y + z * z);
  56.     }
  57.     double crossZ(const Point & b) const {//returns only the z component of the cross product
  58.         return x * b.y - y * b.x;
  59.     }
  60.     Point cross(const Point & b) const {
  61.         double rx = y * b.z - z * b.y;
  62.         double ry = -(x * b.z - z * b.x);
  63.         double rz = x * b.y - y * b.x;
  64.         return Point(rx, ry, rz);
  65.     }
  66. };
  67. void line(SDL_Surface * screen, const Point & a, const Point & b, Uint32 color) {
  68.     double dist = (b - a).magnitude();
  69.     double theta = atan2(b.y - a.y, b.x - a.x);
  70.     double fa = cos(theta), fb = sin(theta);
  71.     for (double r = 0; r <= dist; r += 0.1) {
  72.         double lx = a.x + fa * r, ly = a.y + fb * r;
  73.         setpixel(screen, lx, ly, color);
  74.     }
  75. }
  76. bool pointInsideTriangle(const Point & p, const Point & a, const Point & b, const Point & c) {
  77.     double x = (p - a).crossZ(b - a);
  78.     double y = (p - b).crossZ(c - b);
  79.     double z = (p - c).crossZ(a - c);
  80.     return (x >= 0 && y >= 0 && z >= 0) || (x < 0 && y < 0 && z < 0);
  81. }
  82. //normalized color i.e. 0 <= r, g, b <= 1
  83. struct Color {
  84.     double r, g, b;
  85.     Color(double ar = 0, double ag = 0, double ab = 0) : r(ar), g(ag), b(ab) { }
  86.     Color operator-(const Color & d) const {
  87.         return Color(r - d.r, g - d.g, b - d.b);
  88.     }
  89. };
  90. double interpolate(const Point & a, const Point & b, double ypos) {
  91.     if (b.y == a.y) throw "error";
  92.     double invm = (b.x - a.x) / (b.y - a.y);
  93.     double intx = a.x + (ypos - a.y) * invm;
  94.     return intx;
  95. }
  96. //assumes a, b, c are sorted according to y coordinates, i.e. a.y <= b.y <= c.y
  97. //returns the scanline range according to the yposition
  98. void getEndPoints(const Point & a, const Point & b, const Point & c, double ypos, double & xstart, double & xend) {
  99.     xstart = xend = 0;//dummy
  100.     if (a.y == c.y) return ; //straight line with slope 0, do nothing
  101.     assert(a.y <= b.y && b.y <= c.y);
  102.     if (a.y == b.y) {
  103.         //intersection of y = ypos with AC and BC  
  104.         double intac = interpolate(a, c, ypos);
  105.         double intbc = interpolate(b, c, ypos);
  106.         xstart = intac;
  107.         xend = intbc;
  108.     } else if (b.y == c.y) {
  109.         double intab = interpolate(a, b, ypos);
  110.         double intac = interpolate(a, c, ypos);
  111.         xstart = intab;
  112.         xend = intac;
  113.     } else { //general triangle
  114.         if (ypos <= b.y) { //if ypos <= midy
  115.             double intab = interpolate(a, b, ypos);
  116.             double intac = interpolate(a, c, ypos);
  117.             xstart = intab;
  118.             xend = intac;
  119.         } else {
  120.             double intcb = interpolate(b, c, ypos);
  121.             double intac = interpolate(a, c, ypos);
  122.             xstart = intcb;
  123.             xend = intac;
  124.         }
  125.     }
  126.     if (xstart > xend) {
  127.         swap(xstart, xend);
  128.     }
  129. }
  130. void triangleFill2(SDL_Surface * screen, const Point & a, const Point & b, const Point & c, Uint32 color, const Camera & cam) {
  131.     Point vca = a.toVC(cam), vcb = b.toVC(cam), vcc = c.toVC(cam);
  132.     Point normal = (vcb - vca).cross(vcc - vca); //obtain the triangle normal, i.e. a, b, c components of the plane
  133.     double d = -(normal.x * vca.x + normal.y * vca.y + normal.z * vca.z); // ax + by + cz + d = 0, d = -(ax + by + cz), put point vca
  134.     Point pa = vca.project(cam).to2dview(), pb = vcb.project(cam).to2dview(), pc = vcc.project(cam).to2dview();
  135.     pa.y = int(pa.y);
  136.     pb.y = int(pb.y);
  137.     pc.y = int(pc.y);
  138.     if (pa.y > pb.y) swap(pa, pb);
  139.     if (pb.y > pc.y) swap(pb, pc);
  140.     if (pa.y > pb.y) swap(pa, pb);
  141.     if (pa.y == pc.y) return ;
  142.     double miny = pa.y;
  143.     double maxy = pc.y;
  144.     for (int i = miny; i <= maxy; ++i) {
  145.         if (i < 0) continue;
  146.         if (i >= SCREEN_HEIGHT) break;
  147.         double xs = 0, xe = 0;
  148.         getEndPoints(pa, pb, pc, i, xs, xe);
  149.         std::cout << xs << " " << xe << "\n";
  150.         for (int j = xs; j <= xe; ++j) {
  151.             double D = cam.ze - cam.zv;
  152.             double xp = j - SCREEN_WIDTH / 2, yp = i - SCREEN_HEIGHT / 2;
  153.             double F = normal.x * xp + normal.y * yp - normal.z * D;
  154.             double point_z = ((normal.x * xp + normal.y * yp) * cam.ze + d * D) / F;
  155.             if (point_z < z_buffer[i][j]) {
  156.                 z_buffer[i][j] = point_z;
  157.                 setpixel(screen, j, i, color);
  158.             }
  159.         }
  160.     }
  161. }
  162. //z buffering implemented here
  163. void triangleFill(SDL_Surface * screen, const Point & a, const Point & b, const Point & c, Uint32 color, const Camera & cam) {
  164.     Point vca = a.toVC(cam), vcb = b.toVC(cam), vcc = c.toVC(cam);
  165.     Point normal = (vcb - vca).cross(vcc - vca); //obtain the triangle normal, i.e. a, b, c components of the plane
  166.     double d = -(normal.x * vca.x + normal.y * vca.y + normal.z * vca.z); // ax + by + cz + d = 0, d = -(ax + by + cz), put point vca
  167.     Point pa = vca.project(cam).to2dview(), pb = vcb.project(cam).to2dview(), pc = vcc.project(cam).to2dview();
  168.     double minx = min(pa.x, min(pb.x, pc.x)), miny = min(pa.y, min(pb.y, pc.y));
  169.     double maxx = max(pa.x, max(pb.x, pc.x)), maxy = max(pa.y, max(pb.y, pc.y));
  170.     for (int i = miny; i <= maxy; ++i) {
  171.         if (i < 0) continue;
  172.         if (i >= SCREEN_HEIGHT) break;
  173.         bool inside = 0;
  174.         for (int j = max(minx, 0.0); j <= maxx; ++j) {
  175.             if (j >= SCREEN_WIDTH) break;
  176.             if (pointInsideTriangle(Point(j, i, 0), pa, pb, pc)) {
  177.                 inside = 1;
  178.                 double D = cam.ze - cam.zv;
  179.                 double xp = j - SCREEN_WIDTH / 2, yp = i - SCREEN_HEIGHT / 2;
  180.                 double F = normal.x * xp + normal.y * yp - normal.z * D;
  181.                 double point_z = ((normal.x * xp + normal.y * yp) * cam.ze + d * D) / F;
  182.                 if (point_z < z_buffer[i][j]) {
  183.                     z_buffer[i][j] = point_z;
  184.                     setpixel(screen, j, i, color);
  185.                 }
  186.             } else if (inside) break;
  187.         }
  188.     }
  189. }
  190. struct Triangle {
  191.   Point a, b, c;
  192.   Triangle(const Point & pa, const Point & pb, const Point & pc) : a(pa), b(pb), c(pc) { }
  193.   void draw(SDL_Surface * screen, Uint32 color, const Camera & cam) const {
  194.     triangleFill2(screen, a, b, c, color, cam);
  195.   }
  196. };
  197. struct Cuboid {
  198.   Point a, b, c, d, e, f, g, h;
  199.   Cuboid(double ox, double oy, double oz, double length, double breadth, double height) {
  200.     a = Point(ox, oy, oz);
  201.     b = Point(ox + length, oy, oz);
  202.     c = Point(ox + length, oy + breadth, oz);
  203.     d = Point(ox, oy + breadth, oz);
  204.     e = Point(ox, oy, oz + height);
  205.     f = Point(ox + length, oy, oz + height);
  206.     g = Point(ox + length, oy + breadth, oz + height);
  207.     h = Point(ox, oy + breadth, oz + height);
  208.   }
  209.   void draw(SDL_Surface * screen, const Camera & cam) const {
  210.     triangleFill2(screen, a, b, c, 0xff0000, cam);
  211.     triangleFill2(screen, a, d, c, 0xff0000, cam);
  212.     triangleFill2(screen, e, f, g, 0x00ff00, cam);
  213.     triangleFill2(screen, e, h, g, 0x00ff00, cam);
  214.    
  215.     triangleFill2(screen, a, d, e, 0xff00ff, cam);
  216.     triangleFill2(screen, h, d, e, 0xff00ff, cam);
  217.  
  218.     triangleFill2(screen, b, f, g, 0, cam);
  219.     triangleFill2(screen, c, b, g, 0, cam);
  220.    
  221.     triangleFill2(screen, a, e, b, 0x0000ff, cam);
  222.     triangleFill2(screen, e, b, f, 0x0000ff, cam);
  223.    
  224.    
  225.    
  226.   }
  227.  
  228. };
  229. void clearZBuffer() {
  230.   for (int i =  0; i < SCREEN_HEIGHT; ++i) {
  231.     for (int j = 0; j < SCREEN_WIDTH; ++j) z_buffer[i][j] = 999999999.0; //infinity
  232.   }
  233. }
  234.  
  235. int main(int argc, char ** argv) {
  236.   SDL_Init(SDL_INIT_EVERYTHING);
  237.   SDL_Surface * screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, 32, SDL_SWSURFACE);
  238.   SDL_Event event;
  239.   bool run = 1;
  240.   Camera camera;
  241.   Cuboid cb(0, 0, 0, 50, -50, 100);
  242.   while (run) {
  243.     while (SDL_PollEvent(&event)) {
  244.       if (event.type == SDL_QUIT || (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_ESCAPE)) run = 0;
  245.     }
  246.     //logic
  247.     Uint8 *keys = SDL_GetKeyState(0);
  248.     if (keys[SDLK_a]) camera.phi += 0.1;
  249.     if (keys[SDLK_d]) camera.phi -= 0.1;
  250.    
  251.     if (keys[SDLK_q]) camera.theta += 0.1;
  252.     if (keys[SDLK_e]) camera.theta -= 0.1;
  253.     const int delta = 2;
  254.     if (keys[SDLK_z]) camera.ze += delta, camera.zv += delta; //zoom in
  255.     if (keys[SDLK_x]) camera.ze -= delta, camera.zv -= delta; //zoom out
  256.    
  257.    
  258.     //rendering
  259.     SDL_FillRect(screen, &screen->clip_rect, 0xFFFFFF);
  260.     clearZBuffer();
  261.     cb.draw(screen, camera);
  262.  
  263.     SDL_Flip(screen);
  264.     SDL_Delay(10);
  265.   }
  266.   SDL_Quit();
  267.   return 0;
  268. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement