Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <SDL/SDL.h>
- #include <cmath>
- #include <algorithm>
- #include <iostream>
- #include <bits/stdc++.h>
- using namespace std;
- const int SCREEN_WIDTH = 640, SCREEN_HEIGHT = 480;
- void setpixel(SDL_Surface * screen, int x, int y, Uint32 color) {
- if (x < 0 || x >= SCREEN_WIDTH || y < 0 || y >= SCREEN_HEIGHT) return ;
- Uint32 * pixels = (Uint32*)screen->pixels;
- pixels[y * SCREEN_WIDTH + x] = color;
- }
- double z_buffer[SCREEN_HEIGHT][SCREEN_WIDTH];
- struct Camera {
- double ze, zv, phi, theta, gama;
- Camera() : ze(-500), zv(-200), phi(0), theta(0), gama(0) { }
- };
- struct Point {
- double x, y, z;
- Point(double cx = 0, double cy = 0, double cz = 0):
- x(cx), y(cy), z(cz) { }
- //transformations
- Point rotateY(double t) const {
- double nz = z * cos(t) - x * sin(t);
- double nx = z * sin(t) + x * cos(t);
- return Point(nx, y, nz);
- }
- Point rotateZ(double t) const {
- double nx = x * cos(t) - y * sin(t);
- double ny = x * sin(t) + y * cos(t);
- return Point(nx, ny, z);
- }
- Point rotateX(double t) const {
- double ny = y * cos(t) - z * sin(t);
- double nz = y * sin(t) + z * cos(t);
- return Point(x, ny, nz);
- }
- //crude pipelining steps
- Point toVC(const Camera & cam) const {
- return rotateY(-cam.phi).rotateX(-cam.theta);
- }
- Point project(const Camera & cam) const {
- double f = (cam.ze - cam.zv) / (cam.ze - z);
- double xp = x * f, yp = y * f;
- return Point(xp, yp, cam.zv);
- }
- Point to2dview() const {
- return Point(x + SCREEN_WIDTH / 2, y + SCREEN_HEIGHT / 2, z);
- }
- //vector math
- Point operator-(const Point & b) const {
- return Point(x - b.x, y - b.y, z - b.z);
- }
- double magnitude() const {
- return sqrt(x * x + y * y + z * z);
- }
- double crossZ(const Point & b) const {//returns only the z component of the cross product
- return x * b.y - y * b.x;
- }
- Point cross(const Point & b) const {
- double rx = y * b.z - z * b.y;
- double ry = -(x * b.z - z * b.x);
- double rz = x * b.y - y * b.x;
- return Point(rx, ry, rz);
- }
- };
- void line(SDL_Surface * screen, const Point & a, const Point & b, Uint32 color) {
- double dist = (b - a).magnitude();
- double theta = atan2(b.y - a.y, b.x - a.x);
- double fa = cos(theta), fb = sin(theta);
- for (double r = 0; r <= dist; r += 0.1) {
- double lx = a.x + fa * r, ly = a.y + fb * r;
- setpixel(screen, lx, ly, color);
- }
- }
- bool pointInsideTriangle(const Point & p, const Point & a, const Point & b, const Point & c) {
- double x = (p - a).crossZ(b - a);
- double y = (p - b).crossZ(c - b);
- double z = (p - c).crossZ(a - c);
- return (x >= 0 && y >= 0 && z >= 0) || (x < 0 && y < 0 && z < 0);
- }
- //normalized color i.e. 0 <= r, g, b <= 1
- struct Color {
- double r, g, b;
- Color(double ar = 0, double ag = 0, double ab = 0) : r(ar), g(ag), b(ab) { }
- Color operator-(const Color & d) const {
- return Color(r - d.r, g - d.g, b - d.b);
- }
- };
- double interpolate(const Point & a, const Point & b, double ypos) {
- if (b.y == a.y) throw "error";
- double invm = (b.x - a.x) / (b.y - a.y);
- double intx = a.x + (ypos - a.y) * invm;
- return intx;
- }
- //assumes a, b, c are sorted according to y coordinates, i.e. a.y <= b.y <= c.y
- //returns the scanline range according to the yposition
- void getEndPoints(const Point & a, const Point & b, const Point & c, double ypos, double & xstart, double & xend) {
- xstart = xend = 0;//dummy
- if (a.y == c.y) return ; //straight line with slope 0, do nothing
- assert(a.y <= b.y && b.y <= c.y);
- if (a.y == b.y) {
- //intersection of y = ypos with AC and BC
- double intac = interpolate(a, c, ypos);
- double intbc = interpolate(b, c, ypos);
- xstart = intac;
- xend = intbc;
- } else if (b.y == c.y) {
- double intab = interpolate(a, b, ypos);
- double intac = interpolate(a, c, ypos);
- xstart = intab;
- xend = intac;
- } else { //general triangle
- if (ypos <= b.y) { //if ypos <= midy
- double intab = interpolate(a, b, ypos);
- double intac = interpolate(a, c, ypos);
- xstart = intab;
- xend = intac;
- } else {
- double intcb = interpolate(b, c, ypos);
- double intac = interpolate(a, c, ypos);
- xstart = intcb;
- xend = intac;
- }
- }
- if (xstart > xend) {
- swap(xstart, xend);
- }
- }
- void triangleFill2(SDL_Surface * screen, const Point & a, const Point & b, const Point & c, Uint32 color, const Camera & cam) {
- Point vca = a.toVC(cam), vcb = b.toVC(cam), vcc = c.toVC(cam);
- Point normal = (vcb - vca).cross(vcc - vca); //obtain the triangle normal, i.e. a, b, c components of the plane
- 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
- Point pa = vca.project(cam).to2dview(), pb = vcb.project(cam).to2dview(), pc = vcc.project(cam).to2dview();
- pa.y = int(pa.y);
- pb.y = int(pb.y);
- pc.y = int(pc.y);
- if (pa.y > pb.y) swap(pa, pb);
- if (pb.y > pc.y) swap(pb, pc);
- if (pa.y > pb.y) swap(pa, pb);
- if (pa.y == pc.y) return ;
- double miny = pa.y;
- double maxy = pc.y;
- for (int i = miny; i <= maxy; ++i) {
- if (i < 0) continue;
- if (i >= SCREEN_HEIGHT) break;
- double xs = 0, xe = 0;
- getEndPoints(pa, pb, pc, i, xs, xe);
- std::cout << xs << " " << xe << "\n";
- for (int j = xs; j <= xe; ++j) {
- double D = cam.ze - cam.zv;
- double xp = j - SCREEN_WIDTH / 2, yp = i - SCREEN_HEIGHT / 2;
- double F = normal.x * xp + normal.y * yp - normal.z * D;
- double point_z = ((normal.x * xp + normal.y * yp) * cam.ze + d * D) / F;
- if (point_z < z_buffer[i][j]) {
- z_buffer[i][j] = point_z;
- setpixel(screen, j, i, color);
- }
- }
- }
- }
- //z buffering implemented here
- void triangleFill(SDL_Surface * screen, const Point & a, const Point & b, const Point & c, Uint32 color, const Camera & cam) {
- Point vca = a.toVC(cam), vcb = b.toVC(cam), vcc = c.toVC(cam);
- Point normal = (vcb - vca).cross(vcc - vca); //obtain the triangle normal, i.e. a, b, c components of the plane
- 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
- Point pa = vca.project(cam).to2dview(), pb = vcb.project(cam).to2dview(), pc = vcc.project(cam).to2dview();
- double minx = min(pa.x, min(pb.x, pc.x)), miny = min(pa.y, min(pb.y, pc.y));
- double maxx = max(pa.x, max(pb.x, pc.x)), maxy = max(pa.y, max(pb.y, pc.y));
- for (int i = miny; i <= maxy; ++i) {
- if (i < 0) continue;
- if (i >= SCREEN_HEIGHT) break;
- bool inside = 0;
- for (int j = max(minx, 0.0); j <= maxx; ++j) {
- if (j >= SCREEN_WIDTH) break;
- if (pointInsideTriangle(Point(j, i, 0), pa, pb, pc)) {
- inside = 1;
- double D = cam.ze - cam.zv;
- double xp = j - SCREEN_WIDTH / 2, yp = i - SCREEN_HEIGHT / 2;
- double F = normal.x * xp + normal.y * yp - normal.z * D;
- double point_z = ((normal.x * xp + normal.y * yp) * cam.ze + d * D) / F;
- if (point_z < z_buffer[i][j]) {
- z_buffer[i][j] = point_z;
- setpixel(screen, j, i, color);
- }
- } else if (inside) break;
- }
- }
- }
- struct Triangle {
- Point a, b, c;
- Triangle(const Point & pa, const Point & pb, const Point & pc) : a(pa), b(pb), c(pc) { }
- void draw(SDL_Surface * screen, Uint32 color, const Camera & cam) const {
- triangleFill2(screen, a, b, c, color, cam);
- }
- };
- struct Cuboid {
- Point a, b, c, d, e, f, g, h;
- Cuboid(double ox, double oy, double oz, double length, double breadth, double height) {
- a = Point(ox, oy, oz);
- b = Point(ox + length, oy, oz);
- c = Point(ox + length, oy + breadth, oz);
- d = Point(ox, oy + breadth, oz);
- e = Point(ox, oy, oz + height);
- f = Point(ox + length, oy, oz + height);
- g = Point(ox + length, oy + breadth, oz + height);
- h = Point(ox, oy + breadth, oz + height);
- }
- void draw(SDL_Surface * screen, const Camera & cam) const {
- triangleFill2(screen, a, b, c, 0xff0000, cam);
- triangleFill2(screen, a, d, c, 0xff0000, cam);
- triangleFill2(screen, e, f, g, 0x00ff00, cam);
- triangleFill2(screen, e, h, g, 0x00ff00, cam);
- triangleFill2(screen, a, d, e, 0xff00ff, cam);
- triangleFill2(screen, h, d, e, 0xff00ff, cam);
- triangleFill2(screen, b, f, g, 0, cam);
- triangleFill2(screen, c, b, g, 0, cam);
- triangleFill2(screen, a, e, b, 0x0000ff, cam);
- triangleFill2(screen, e, b, f, 0x0000ff, cam);
- }
- };
- void clearZBuffer() {
- for (int i = 0; i < SCREEN_HEIGHT; ++i) {
- for (int j = 0; j < SCREEN_WIDTH; ++j) z_buffer[i][j] = 999999999.0; //infinity
- }
- }
- int main(int argc, char ** argv) {
- SDL_Init(SDL_INIT_EVERYTHING);
- SDL_Surface * screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, 32, SDL_SWSURFACE);
- SDL_Event event;
- bool run = 1;
- Camera camera;
- Cuboid cb(0, 0, 0, 50, -50, 100);
- while (run) {
- while (SDL_PollEvent(&event)) {
- if (event.type == SDL_QUIT || (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_ESCAPE)) run = 0;
- }
- //logic
- Uint8 *keys = SDL_GetKeyState(0);
- if (keys[SDLK_a]) camera.phi += 0.1;
- if (keys[SDLK_d]) camera.phi -= 0.1;
- if (keys[SDLK_q]) camera.theta += 0.1;
- if (keys[SDLK_e]) camera.theta -= 0.1;
- const int delta = 2;
- if (keys[SDLK_z]) camera.ze += delta, camera.zv += delta; //zoom in
- if (keys[SDLK_x]) camera.ze -= delta, camera.zv -= delta; //zoom out
- //rendering
- SDL_FillRect(screen, &screen->clip_rect, 0xFFFFFF);
- clearZBuffer();
- cb.draw(screen, camera);
- SDL_Flip(screen);
- SDL_Delay(10);
- }
- SDL_Quit();
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement