opengl | test opengl renderer | | Search

This C++ code defines a 3D transformation system using SDL for rendering, which consists of classes and functions for representing points, vectors, and matrices, as well as applying transformations such as rotation, translation, and connection drawing. The system uses the SDL library for rendering and includes functions for calculating dot products, applying composite transformations, and getting rotation matrices.

Run example

npm run import -- "opengl frame"

opengl frame

#include <vector>
#include <cmath>
#include <SDL.h>

class Point {
  public:
    double x, y, z;

    Point() {
        this->x = 0;
        this->y = 0;
        this->z = 0;
    }

    Point(double x, double y, double z) {
        this->x = x;
        this->y = y;
        this->z = z;
    }

    Point(double x, double y) {
        this->x = x;
        this->y = y;
        this->z = 0;
    }

    double operator[](int i) const {
        if (i == 0) return this->x;
        if (i == 1) return this->y;
        return this->z;
    }

    double& operator[](int i) {
        if (i == 0) return this->x;
        if (i == 1) return this->y;
        return this->z;
    }
};

typedef std::vector<double> Vector;
typedef std::vector<Vector> Matrix;

Matrix dot(const Matrix& a, const Matrix& b) {
    Matrix result = Matrix(a.size(), Vector(b[0].size(), 0));
    for (int i=0; i<a.size(); i++) {
        for (int j=0; j<b[0].size(); j++) {
            for (int k=0; k<b.size(); k++) {
                result[i][j] += a[i][k] * b[k][j];
            }
        }
    }
    return result;
}

Point transform(const Matrix& matrix, const Point& point) {
    Matrix p = {{point.x}, {point.y}, {point.z}};
    Matrix r = dot(matrix, p);
    return Point(r[0][0], r[1][0], r[2][0]);
}

Point translate(const Point& shift, const Point& point) {
    return Point(
        point.x + shift.x,
        point.y + shift.y,
        point.z + shift.z
    );
}

void connect(SDL_Renderer* const renderer, const std::vector<Point> &points, int i, int j) {
    SDL_RenderDrawLine(
        renderer,
        points[i].x,
        points[i].y,
        points[j].x,
        points[j].y
    );
}

Matrix getRotationMatrix() {
    double alpha = 0.001;
    Matrix rotationX = {
        {1, 0, 0},
        {0, cos(alpha), -sin(alpha)},
        {0, sin(alpha), cos(alpha)}
    };

    double beta = 0.002;
    Matrix rotationY = {
        {cos(beta), 0, sin(beta)},
        {0, 1, 0},
        {-sin(beta), 0, cos(beta)}
    };

    double gamma = 0.003;
    Matrix rotationZ = {
        {cos(gamma), -sin(gamma), 0},
        {sin(gamma), cos(gamma), 0},
        {0, 0, 1}
    };

    return dot(rotationZ, dot(rotationY, rotationX));
}
  

#if __cplusplus
extern "C" {
#endif


int WIDTH = 1000;
int HEIGHT = 800;

static bool first = false;
static SDL_Renderer* renderer;
std::vector<Point> points;
Matrix rotationXYZ;

Point screenShift;
Point screenShiftOpposite;

void beginFrame(int windowId) {
    SDL_Window *window = SDL_GetWindowFromID(windowId);
    SDL_Event event;
    while(SDL_PollEvent(&event)){
        if(event.type == SDL_QUIT) {
            SDL_DestroyWindow(window);
            SDL_Quit();
            return;
        }
    }
  if(!first) {
    first = true;
    
    renderer = SDL_CreateRenderer(
        window,
        -1,
        SDL_RENDERER_ACCELERATED
    );

    points = {
        Point(-1, 1, 1),
        Point(1, 1, 1),
        Point(1, -1, 1),
        Point(-1, -1, 1),
        Point(-1, 1, -1),
        Point(1, 1, -1),
        Point(1, -1, -1),
        Point(-1, -1, -1)
    };

    screenShift = Point(WIDTH / 2, HEIGHT / 2);
    screenShiftOpposite = Point(-WIDTH / 2, -HEIGHT / 2);
    int scale = 200;

    for (Point& p : points) {
        p.x = (scale * p.x + screenShift.x);
        p.y = (scale * p.y + screenShift.y);
        p.z = (scale * p.z + screenShift.z);
    }

    rotationXYZ = getRotationMatrix();
  }


  for (Point &p : points) {
    p = translate(screenShiftOpposite, p);
    p = transform(rotationXYZ, p);
    p = translate(screenShift, p);
  }

  SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
  SDL_RenderClear(renderer);
  SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
  for (int i=0; i<4; i++) {
      connect(renderer, points, i, (i + 1) % 4);
      connect(renderer, points, i + 4, ((i + 1) % 4) + 4);
      connect(renderer, points, i, i + 4);
  }
  SDL_RenderPresent(renderer);
  SDL_Delay(3);
}

void endFrame(int windowId) {
    SDL_Window *window = SDL_GetWindowFromID(windowId);
  SDL_GL_SwapWindow(window);
}


#if __cplusplus
}
#endif

What the code could have been:

cpp
#include <vector>
#include <cmath>
#include <SDL.h>

// Define a 2D and 3D vector class
class Vector2D {
public:
    double x, y;

    Vector2D() : x(0), y(0) {}
    Vector2D(double x, double y) : x(x), y(y) {}

    double& operator[](int i) {
        if (i == 0) return x;
        return y;
    }

    double operator[](int i) const {
        if (i == 0) return x;
        return y;
    }
};

class Vector3D {
public:
    double x, y, z;

    Vector3D() : x(0), y(0), z(0) {}
    Vector3D(double x, double y, double z) : x(x), y(y), z(z) {}

    double& operator[](int i) {
        if (i == 0) return x;
        if (i == 1) return y;
        return z;
    }

    double operator[](int i) const {
        if (i == 0) return x;
        if (i == 1) return y;
        return z;
    }
};

// Define a 2D and 3D point class
class Point2D {
public:
    Vector2D coords;

    Point2D() {}
    Point2D(double x, double y) : coords(x, y) {}

    Vector2D operator[](int i) const {
        return coords;
    }
};

class Point3D {
public:
    Vector3D coords;

    Point3D() {}
    Point3D(double x, double y, double z) : coords(x, y, z) {}

    Vector3D operator[](int i) const {
        return coords;
    }
};

// Define a 3D matrix class
class Matrix3D {
public:
    std::vector<std::vector<double>> data;

    Matrix3D(size_t rows, size_t cols) : data(rows, std::vector<double>(cols, 0)) {}

    double& operator()(size_t i, size_t j) {
        return data[i][j];
    }

    double operator()(size_t i, size_t j) const {
        return data[i][j];
    }
};

// Function to multiply two 3D matrices
Matrix3D dot(const Matrix3D& a, const Matrix3D& b) {
    Matrix3D result(a.rows(), b.cols());

    for (size_t i = 0; i < a.rows(); ++i) {
        for (size_t j = 0; j < b.cols(); ++j) {
            for (size_t k = 0; k < a.cols(); ++k) {
                result(i, j) += a(i, k) * b(k, j);
            }
        }
    }

    return result;
}

// Function to transform a 3D point using a rotation matrix
Point3D transform(const Matrix3D& matrix, const Point3D& point) {
    Matrix3D p({1, 0, 0},
              {0, 1, 0},
              {0, 0, 1});

    for (size_t i = 0; i < 3; ++i) {
        p(i, 0) = point[i];
    }

    Matrix3D r = dot(matrix, p);

    return Point3D(r(0, 0), r(1, 0), r(2, 0));
}

// Function to translate a point
Point3D translate(const Point3D& point, const Vector3D& offset) {
    return Point3D(point[0] + offset[0], point[1] + offset[1], point[2] + offset[2]);
}

// Function to render a frame
void renderFrame(SDL_Renderer* renderer, const std::vector<Point3D>& points, const Matrix3D& rotationMatrix, const Point3D& screenShift, const Point3D& screenShiftOpposite) {
    SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
    SDL_RenderClear(renderer);
    SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);

    for (const auto& point : points) {
        point = translate(screenShiftOpposite, point);
        point = transform(rotationMatrix, point);
        point = translate(screenShift, point);

        connect(renderer, points, std::distance(points.begin(), std::find(points.begin(), points.end(), point)), std::distance(points.begin(), std::find(points.begin(), points.end(), *(std::next(std::find(points.begin(), points.end(), point))))));
    }

    SDL_RenderPresent(renderer);
    SDL_Delay(3);
}

// Function to get the rotation matrix
Matrix3D getRotationMatrix() {
    double alpha = 0.001;
    Matrix3D rotationX({1, 0, 0,
                       0, cos(alpha), -sin(alpha),
                       0, sin(alpha), cos(alpha)});

    double beta = 0.002;
    Matrix3D rotationY({cos(beta), 0, sin(beta),
                       0, 1, 0,
                       -sin(beta), 0, cos(beta)});

    double gamma = 0.003;
    Matrix3D rotationZ({cos(gamma), -sin(gamma), 0,
                       sin(gamma), cos(gamma), 0,
                       0, 0, 1});

    return dot(rotationZ, dot(rotationY, rotationX));
}

// Function to connect two points
void connect(SDL_Renderer* renderer, const std::vector<Point3D>& points, int i, int j) {
    SDL_RenderDrawLine(renderer, points[i].coords[0], points[i].coords[1], points[j].coords[0], points[j].coords[1]);
}

int main() {
    // Initialize SDL
    SDL_Init(SDL_INIT_VIDEO);
    SDL_Window* window = SDL_CreateWindow("Window", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1000, 800, 0);

    // Create renderer
    SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);

    // Define points
    std::vector<Point3D> points = {
        {1, 1, 1},
        {1, -1, 1},
        {1, -1, -1},
        {1, 1, -1},
        {1, 1, 1},
        {1, -1, -1},
        {1, -1, 1},
        {1, 1, -1},
        {1, -1, 1},
        {1, 1, -1},
        {-1, -1, -1},
        {-1, -1, 1},
        {-1, 1, -1},
        {-1, 1, 1},
        {-1, -1, -1},
        {-1, -1, 1},
        {-1, 1, -1},
        {-1, 1, 1}
    };

    // Define rotation matrix
    Matrix3D rotationMatrix = getRotationMatrix();

    // Define screen shift
    Point3D screenShift(WIDTH / 2, HEIGHT / 2, 0);
    Point3D screenShiftOpposite(-WIDTH / 2, -HEIGHT / 2, 0);

    // Render frames
    int frame = 0;
    while (true) {
        renderFrame(renderer, points, rotationMatrix, screenShift, screenShiftOpposite);
        frame++;
    }

    // Clean up
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    SDL_Quit();

    return 0;
}

Overview

This code defines a 3D transformation system using C++ and the SDL library for rendering.

Classes and Functions

  1. Point: Represents a 3D point with x, y, and z coordinates. It has a constructor that initializes the point with default values (0, 0, 0) and overloaded constructors to initialize the point with any combination of x, y, and z coordinates.
  2. operator[]: Overloads the array indexing operator to allow accessing the point's coordinates using point[i].
  3. Vector and Matrix: Type definitions for std::vector<double> and std::vector<std::vector<double>>, respectively, used to represent vectors and matrices.
  4. dot: Calculates the dot product of two matrices.
  5. transform: Applies a transformation to a point using a matrix.
  6. translate: Shifts a point by a given amount.
  7. connect: Connects two points on a 2D surface using the SDL library to draw a line between them.
  8. getRotationMatrix: Returns a rotation matrix for rotation around the x, y, and z axes.

Notes