diff --git a/.gitignore b/.gitignore index 1ff9a75..4578b5d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ -main.exe -*.o \ No newline at end of file +src/main.exe +src/main +*.wo +*.uo +*.mo \ No newline at end of file diff --git a/Makefile b/Makefile deleted file mode 100644 index bc9395b..0000000 --- a/Makefile +++ /dev/null @@ -1,29 +0,0 @@ -CC = gcc -CFLAGS = -std=gnu23 -Wall -Wextra -LIBS = -lgdi32 - -TARGET = main.exe -SOURCES = main.c utils/utils.c -OBJECTS = $(SOURCES:.c=.o) - -all: $(TARGET) - -$(TARGET): $(OBJECTS) - $(CC) -o $@ $^ $(LIBS) - -%.o: %.c - $(CC) $(CFLAGS) -c $< -o $@ - -clean: - @if command -v rm >/dev/null 2>&1; then \ - rm -f $(TARGET) main.o utils/utils.o; \ - else \ - powershell -Command "Remove-Item -ErrorAction SilentlyContinue '$(TARGET)', 'main.o', 'utils/utils.o'"; \ - fi - -rebuild: clean all - -run: $(TARGET) - .\$(TARGET) - -.PHONY: all clean rebuild run \ No newline at end of file diff --git a/main.c b/main.c deleted file mode 100644 index 50d0288..0000000 --- a/main.c +++ /dev/null @@ -1,188 +0,0 @@ -#include -#include -#include - -#include "utils/utils.h" - -#define WINDOW_WIDTH 800.0f -#define WINDOW_HEIGHT 600.0f - -#define BG_COLOR BLACK_BRUSH -#define COLOR RGB(255, 255, 255) - -Point3D cube_points[] = {{0.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, - {1.0f, 1.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, - {0.0f, 0.0f, 1.0f}, {1.0f, 0.0f, 1.0f}, - {1.0f, 1.0f, 1.0f}, {0.0f, 1.0f, 1.0f}}; -int cube_edges[][2] = {{0, 1}, {1, 2}, {2, 3}, {3, 0}, {4, 5}, {5, 6}, - {6, 7}, {7, 4}, {0, 4}, {1, 5}, {2, 6}, {3, 7}}; -Point3D cube_position = {.coordinates = {3.0f, 6.0f, 5.0f}}; -float cube_speed[] = {0.03f, 0.0f, 0.0f}; -const Object cube = {.points = cube_points, - .edges = cube_edges, - .number_of_points = 8, - .number_of_edges = 12, - .position = &cube_position, - .rotate_speed = &cube_speed}; - -Point3D pyramid_points[] = {{-1.0f, 0.0f, -1.0f}, - {1.0f, 0.0f, -1.0f}, - {1.0f, 0.0f, 1.0f}, - {-1.0f, 0.0f, 1.0f}, - {0.0f, 1.5f, 0.0f}}; -int pyramid_edges[][2] = {{0, 1}, {1, 2}, {2, 3}, {3, 0}, - {0, 4}, {1, 4}, {2, 4}, {3, 4}}; -Point3D pyramid_position = {.coordinates = {6.0f, 3.0f, 5.0f}}; -float pyramid_speed[] = {0.0f, 0.0f, 0.03f}; -const Object pyramid = {.points = pyramid_points, - .edges = pyramid_edges, - .number_of_points = 5, - .number_of_edges = 8, - .position = &pyramid_position, - .rotate_speed = &pyramid_speed}; - -Point3D prism_points[] = {{0.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, - {0.5f, 0.0f, 1.0f}, {0.0f, 1.0f, 0.0f}, - {1.0f, 1.0f, 0.0f}, {0.5f, 1.0f, 1.0f}}; -int prism_edges[][2] = {{0, 1}, {1, 2}, {2, 0}, {3, 4}, {4, 5}, - {5, 3}, {0, 3}, {1, 4}, {2, 5}}; -Point3D prism_position = {.coordinates = {10.0f, 10.0f, 10.0f}}; -float prism_speed[] = {0.0f, 0.03f, 0.0f}; -const Object prism = {.points = prism_points, - .edges = prism_edges, - .number_of_points = 6, - .number_of_edges = 9, - .position = &prism_position, - .rotate_speed = &prism_speed}; - -const int number_of_objects = 3; -Object objects[] = {cube, pyramid, prism}; - -Camera camera = {.position = {0.0f, 0.0f, 0.0f}, - .target = {1.0f, 1.0f, 1.0f}, - .up = {-1.0f, -1.0f, 1.0f}, - .fov = 120.0f, - .max_distance = 20.0f, - .min_distance = .0f, - .aspect_ratio = WINDOW_WIDTH / WINDOW_HEIGHT}; - -float render_matrix[4][4]; - -LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, - LPARAM lParam) { - switch (uMsg) { - case WM_CREATE: - SetTimer(hwnd, 1, 50, NULL); - return 0; - case WM_PAINT: { - PAINTSTRUCT ps; - HDC hdc = BeginPaint(hwnd, &ps); - - RECT rect; - GetClientRect(hwnd, &rect); - FillRect(hdc, &rect, (HBRUSH)GetStockObject(BG_COLOR)); - float width = rect.right - rect.left; - float height = rect.bottom - rect.top; - - Screen screen = {.width = width, - .height = height, - .hdc = &hdc, - .render_matrix = &render_matrix}; - - HPEN hPen = CreatePen(PS_SOLID, 1, COLOR); - HPEN hOldPen = (HPEN)SelectObject(hdc, hPen); - - for (int i = 0; i < number_of_objects; i++) { - draw_object(&(objects[i]), &screen); - } - - SelectObject(hdc, hOldPen); - DeleteObject(hPen); - - EndPaint(hwnd, &ps); - return 0; - } - - case WM_DESTROY: - PostQuitMessage(0); - return 0; - - case WM_TIMER: - for (int i = 0; i < number_of_objects; i++) { - float reverse_translate_matrix[4][4]; - create_translate_matrix(objects[i].position, reverse_translate_matrix, - -1); - transform_object(&(objects[i]), 4, reverse_translate_matrix); - - Point3D center_of_object = calculate_centroid(&(objects[i])); - float reverse_center_translate_matrix[4][4]; - create_translate_matrix(¢er_of_object, - reverse_center_translate_matrix, -1); - transform_object(&(objects[i]), 4, reverse_center_translate_matrix); - - float rotate_matrix[3][3]; - create_rotate_matrix(*(objects[i].rotate_speed), rotate_matrix); - transform_object(&(objects[i]), 3, rotate_matrix); - - float center_translate_matrix[4][4]; - create_translate_matrix(¢er_of_object, center_translate_matrix, 1); - transform_object(&(objects[i]), 4, center_translate_matrix); - - float translate_matrix[4][4]; - create_translate_matrix(objects[i].position, translate_matrix, 1); - transform_object(&(objects[i]), 4, translate_matrix); - } - - InvalidateRect(hwnd, NULL, TRUE); - return 0; - - case WM_KEYDOWN: - return 0; - } - - return DefWindowProc(hwnd, uMsg, wParam, lParam); -} - -int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, - LPSTR lpCmdLine, int nCmdShow) { - const char CLASS_NAME[] = "C3DGraphicEngine"; - - WNDCLASS wc = {0}; - wc.lpfnWndProc = WindowProc; - wc.hInstance = hInstance; - wc.lpszClassName = CLASS_NAME; - wc.hCursor = LoadCursor(NULL, IDC_ARROW); - wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); - RegisterClass(&wc); - - HWND hwnd = CreateWindowEx(0, CLASS_NAME, CLASS_NAME, WS_OVERLAPPEDWINDOW, - CW_USEDEFAULT, CW_USEDEFAULT, WINDOW_WIDTH, - WINDOW_HEIGHT, NULL, NULL, hInstance, NULL); - - if (hwnd == NULL) { - return 0; - } - - float view_matrix[4][4]; - create_view_matrix(&camera, view_matrix); - float projection_matrix[4][4]; - create_projection_matrix(&camera, projection_matrix); - matrix_mult_matrix(4, projection_matrix, view_matrix, render_matrix); - - for (int i = 0; i < number_of_objects; i++) { - float translate_matrix[4][4]; - create_translate_matrix(objects[i].position, translate_matrix, 1); - transform_object(&(objects[i]), 4, translate_matrix); - } - - ShowWindow(hwnd, nCmdShow); - UpdateWindow(hwnd); - - MSG msg = {0}; - while (GetMessage(&msg, NULL, 0, 0)) { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - - return 0; -} diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..868908e --- /dev/null +++ b/src/Makefile @@ -0,0 +1,38 @@ +CC = gcc +CFLAGS = -std=gnu23 -Wall -Wextra -O2 +LIBS = -lgdi32 + +WIN_TARGET = main.exe +UNIX_TARGET = main + +BASE_SOURCES = main.c engine/engine.c engine/vector.c engine/matrix.c engine/point.c engine/camera.c engine/object.c +WIN_SOURCES = $(BASE_SOURCES) platforms/win.c +WIN_OBJECTS = $(WIN_SOURCES:.c=.wo) +UNIX_SOURCES = $(BASE_SOURCES) platforms/unix.c +UNIX_OBJECTS = $(UNIX_SOURCES:.c=.uo) +MICRO_SOURCES = $(BASE_SOURCES) platforms/micro.c +MICRO_OBJECTS = $(MICRO_SOURCES:.c=.mo) + +win: $(WIN_TARGET) +$(WIN_TARGET): $(WIN_OBJECTS) + $(CC) -o $@ $^ $(LIBS) + +%.wo: %.c + $(CC) $(CFLAGS) -DWIN -c $< -o $@ + +%.uo: %.c + $(CC) $(CFLAGS) -DUNIX -c $< -o $@ + +%.mo: %.c + $(CC) $(CFLAGS) -DMICRO -c $< -o $@ + +clean: + rm -f $(WIN_TARGET) $(WIN_OBJECTS) $(UNIX_OBJECTS) $(MICRO_OBJECTS); + +run_win: $(WIN_TARGET) + .\$(WIN_TARGET) + +run_unix: $(UNIX_TARGET) + .\$(UNIX_TARGET) + +.PHONY: all clean rebuild run \ No newline at end of file diff --git a/src/engine/camera.c b/src/engine/camera.c new file mode 100644 index 0000000..82d00d2 --- /dev/null +++ b/src/engine/camera.c @@ -0,0 +1,54 @@ +#include "camera.h" + +#include "math.h" +#include "vector.h" + +void camera_get_view_matrix(const Camera *const camera, + float view_matrix[4][4]) { + float forward[3]; + vector_substruct(3, camera->position->coordinates, + camera->target->coordinates, forward); + float normal_forward[3]; + vector_normalize(3, forward, normal_forward); + float right[3]; + cross_product_vectors(camera->up, forward, right); + float normal_right[3]; + vector_normalize(3, right, normal_right); + + float up[3]; + cross_product_vectors(normal_forward, normal_right, up); + float normal_up[3]; + vector_normalize(3, up, normal_up); + + float *vectors[] = {normal_right, normal_up, normal_forward}; + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + view_matrix[i][j] = 0; + if (i == 3) { + if (j == 3) + view_matrix[i][j] = 1; + } else if (j == 3) { + view_matrix[i][j] = + -1 * dot_product_vectors(vectors[i], camera->position->coordinates); + } else { + view_matrix[i][j] = vectors[i][j]; + } + } + } +} +void camera_get_projection_matrix(const Camera *const camera, + float projection_matrix[4][4]) { + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + projection_matrix[i][j] = 0; + } + } + float f = 1 / tan(camera->fov / 2); + projection_matrix[0][0] = f / camera->aspect_ratio; + projection_matrix[1][1] = f; + projection_matrix[2][2] = (camera->max_distance + camera->min_distance) / + (camera->min_distance - camera->max_distance); + projection_matrix[3][2] = -1; + projection_matrix[2][3] = (2 * camera->max_distance * camera->min_distance) / + (camera->min_distance - camera->max_distance); +} \ No newline at end of file diff --git a/src/engine/camera.h b/src/engine/camera.h new file mode 100644 index 0000000..2f39936 --- /dev/null +++ b/src/engine/camera.h @@ -0,0 +1,21 @@ +#ifndef CAMERA_H +#define CAMERA_H + +#include "point.h" + +typedef struct Camera { + Point *const position; + Point *const target; + float up[3]; + const float fov; + const float max_distance; + const float min_distance; + const float aspect_ratio; +} Camera; + +void camera_get_view_matrix(const Camera *const camera, + float view_matrix[4][4]); +void camera_get_projection_matrix(const Camera *const camera, + float projection_matrix[4][4]); + +#endif \ No newline at end of file diff --git a/src/engine/engine.c b/src/engine/engine.c new file mode 100644 index 0000000..18fa583 --- /dev/null +++ b/src/engine/engine.c @@ -0,0 +1 @@ +#include "engine.h" diff --git a/src/engine/engine.h b/src/engine/engine.h new file mode 100644 index 0000000..b55f079 --- /dev/null +++ b/src/engine/engine.h @@ -0,0 +1,10 @@ +#ifndef ENGINE_H +#define ENGINE_H + +#include "camera.h" +#include "matrix.h" +#include "object.h" +#include "point.h" +#include "vector.h" + +#endif \ No newline at end of file diff --git a/src/engine/matrix.c b/src/engine/matrix.c new file mode 100644 index 0000000..2404b46 --- /dev/null +++ b/src/engine/matrix.c @@ -0,0 +1,87 @@ +#include "matrix.h" + +#include + +void matrix_mult_matrix(int size, const float matrix1[size][size], + const float matrix2[size][size], + float result[size][size]) { + for (int i = 0; i < size; i++) { + for (int j = 0; j < size; j++) { + result[i][j] = 0; + } + } + for (int i = 0; i < size; i++) { + for (int j = 0; j < size; j++) { + for (int k = 0; k < size; k++) { + result[i][j] += matrix1[i][k] * matrix2[k][j]; + } + } + } +} +void matrix_mult_vector(int size, const float matrix[size][size], + const float vector[size], float result[size]) { + for (int i = 0; i < size; i++) + result[i] = 0; + for (int i = 0; i < size; i++) { + for (int j = 0; j < size; j++) { + result[i] += matrix[i][j] * vector[j]; + } + } +} +void create_axis_rotate_matrix(int axis, float angle, + float rotate_matrix[3][3]) { + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + rotate_matrix[i][j] = 0; + } + } + + float cos_angle = cosf(angle); + float sin_angle = sinf(angle); + + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + if (i == axis || j == axis) { + if (i == j) + rotate_matrix[i][j] = 1; + else + rotate_matrix[i][j] = 0; + } else { + if (i == j) { + rotate_matrix[i][j] = cos_angle; + } else { + if ((i < j && axis == 2) || (i > j && axis != 2)) { + rotate_matrix[i][j] = sin_angle; + } else { + rotate_matrix[i][j] = -sin_angle; + } + } + } + } + } +} + +void create_rotate_matrix(const float rotate_speed[3], + float rotate_matrix[3][3]) { + float x_rotate[3][3]; + create_axis_rotate_matrix(0, rotate_speed[0], x_rotate); + float y_rotate[3][3]; + create_axis_rotate_matrix(1, rotate_speed[1], y_rotate); + float z_rotate[3][3]; + create_axis_rotate_matrix(2, rotate_speed[2], z_rotate); + float xy_rotate[3][3]; + matrix_mult_matrix(3, x_rotate, y_rotate, xy_rotate); + matrix_mult_matrix(3, xy_rotate, z_rotate, rotate_matrix); +} + +// void print_matrix(int size, float matrix[size][size]) { +// for (int i = 0; i < size; i++) { +// printf("("); +// for (int j = 0; j < size; j++) { +// printf("%f", matrix[i][j]); +// if (j != size - 1) +// printf(",\t"); +// } +// printf(")\n"); +// } +// } \ No newline at end of file diff --git a/src/engine/matrix.h b/src/engine/matrix.h new file mode 100644 index 0000000..360f3d6 --- /dev/null +++ b/src/engine/matrix.h @@ -0,0 +1,16 @@ +#ifndef MATRIX_H +#define MATRIX_H + +void matrix_mult_matrix(int size, const float matrix1[size][size], + const float matrix2[size][size], + float result[size][size]); +void matrix_mult_vector(int size, const float matrix[size][size], + const float vector[size], float result[size]); + +void create_axis_rotate_matrix(int axis, float angle, + float rotate_matrix[3][3]); +void create_rotate_matrix(const float rotate_speed[3], + float rotate_matrix[3][3]); +// void print_matrix(int size, float matrix[size][size]); + +#endif \ No newline at end of file diff --git a/src/engine/object.c b/src/engine/object.c new file mode 100644 index 0000000..b03fae5 --- /dev/null +++ b/src/engine/object.c @@ -0,0 +1,41 @@ +#include "object.h" + +#include "../utils/screen.h" +#include "vector.h" + +void object_transform(Object *const object, int size, + float translate_matrix[size][size]) { + for (int i = 0; i < object->number_of_points; i++) { + point_transform(&(object->points[i]), size, translate_matrix); + } +} + +Point object_get_centroid(const Object *const object) { + Point centroid = {{0.0f, 0.0f, 0.0f}}; + + for (int i = 0; i < object->number_of_points; i++) { + centroid.coordinates[0] += object->points[i].coordinates[0]; + centroid.coordinates[1] += object->points[i].coordinates[1]; + centroid.coordinates[2] += object->points[i].coordinates[2]; + } + + float inv_n = 1.0f / (float)object->number_of_points; + centroid.coordinates[0] *= inv_n; + centroid.coordinates[1] *= inv_n; + centroid.coordinates[2] *= inv_n; + + return centroid; +} + +void object_draw(const Object *object, Screen *screen, + const float render_matrix[4][4]) { + for (int i = 0; i < object->number_of_edges; i++) { + Point point1 = object->points[object->edges[i][0]]; + ScreenPoint screen_point1 = + point_convert_to_screen_point(&point1, screen, render_matrix); + Point point2 = object->points[object->edges[i][1]]; + ScreenPoint screen_point2 = + point_convert_to_screen_point(&point2, screen, render_matrix); + screen->draw_line(&screen_point1, &screen_point2); + } +} \ No newline at end of file diff --git a/src/engine/object.h b/src/engine/object.h new file mode 100644 index 0000000..6f0887c --- /dev/null +++ b/src/engine/object.h @@ -0,0 +1,23 @@ +#ifndef OBJECT_H +#define OBJECT_H + +#include "../utils/screen.h" +#include "point.h" + +typedef struct Object { + const char *const name; + Point *const points; + const int (*const edges)[2]; + const int number_of_points; + const int number_of_edges; + Point *const position; + const float (*const rotate_speed)[3]; +} Object; + +void object_transform(Object *const object, int size, + float translate_matrix[size][size]); +Point object_get_centroid(const Object *const object); +void object_draw(const Object *object, Screen *screen, + const float render_matrix[4][4]); + +#endif \ No newline at end of file diff --git a/src/engine/point.c b/src/engine/point.c new file mode 100644 index 0000000..0849b05 --- /dev/null +++ b/src/engine/point.c @@ -0,0 +1,46 @@ +#include "point.h" + +#include "../utils/screen.h" +#include "matrix.h" + +void point_transform(Point *const point, int size, + const float translate_matrix[size][size]) { + float new_coordinates[3]; + float old_coordinates[] = {point->coordinates[0], point->coordinates[1], + point->coordinates[2], 1.0f}; + matrix_mult_vector(size, translate_matrix, old_coordinates, new_coordinates); + for (int i = 0; i < 3; i++) + point->coordinates[i] = new_coordinates[i]; +} +void point_create_translate_matrix(const Point *const position, + float translate_matrix[4][4], int k) { + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + translate_matrix[i][j] = 0; + if (i == j) + translate_matrix[i][j] = 1; + else if (j == 3) + translate_matrix[i][j] = position->coordinates[i] * k; + } + } +} + +ScreenPoint point_convert_to_screen_point(Point *point, Screen *screen, + const float render_matrix[4][4]) { + float tmp[] = {point->coordinates[0], point->coordinates[1], + point->coordinates[2], 1.0f}; + float point_projection_view[4]; + matrix_mult_vector(4, render_matrix, tmp, point_projection_view); + + float perspective_coordinates[3] = { + point_projection_view[0] / point_projection_view[3], + point_projection_view[1] / point_projection_view[3], + point_projection_view[2] / point_projection_view[3], + }; + ScreenPoint spoint = { + .coordinates = {((perspective_coordinates[0] + 1.0f) / 2.0f) * + (float)screen->width, + ((perspective_coordinates[1] + 1.0f) / 2.0f) * + (float)screen->height}}; + return spoint; +} \ No newline at end of file diff --git a/src/engine/point.h b/src/engine/point.h new file mode 100644 index 0000000..b3c65e1 --- /dev/null +++ b/src/engine/point.h @@ -0,0 +1,17 @@ +#ifndef POINT_H +#define POINT_H + +#include "../utils/screen.h" + +typedef struct Point { + float coordinates[3]; +} Point; + +void point_transform(Point *const point, int size, + const float translate_matrix[size][size]); +void point_create_translate_matrix(const Point *const position, + float translate_matrix[4][4], int k); +ScreenPoint point_convert_to_screen_point(Point *point, Screen *screen, + const float render_matrix[4][4]); + +#endif \ No newline at end of file diff --git a/src/engine/vector.c b/src/engine/vector.c new file mode 100644 index 0000000..5283b7b --- /dev/null +++ b/src/engine/vector.c @@ -0,0 +1,35 @@ +#include "vector.h" + +#include + +void vector_substruct(int size, const float v1[size], const float v2[size], + float r[size]) { + for (int i = 0; i < size; i++) + r[i] = v1[i] - v2[i]; +} +void cross_product_vectors(const float v1[3], const float v2[3], float r[3]) { + r[0] = v1[1] * v2[2] - v1[2] * v2[1]; + r[1] = v1[2] * v2[0] - v1[0] * v2[2]; + r[2] = v1[0] * v2[1] - v1[1] * v2[0]; +} +float dot_product_vectors(const float v1[3], const float v2[3]) { + return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]; +} +void vector_normalize(int size, const float v[size], float r[size]) { + float divider = 0; + for (int i = 0; i < size; i++) + divider += v[i] * v[i]; + divider = sqrt(divider); + for (int i = 0; i < size; i++) + r[i] = v[i] / divider; +} + +// void print_vector(int size, float vector[size]) { +// printf("("); +// for (int i = 0; i < size; i++) { +// printf("%f", vector[i]); +// if (i != size - 1) +// printf(",\t"); +// } +// printf(")\n"); +// } \ No newline at end of file diff --git a/src/engine/vector.h b/src/engine/vector.h new file mode 100644 index 0000000..b6789dd --- /dev/null +++ b/src/engine/vector.h @@ -0,0 +1,11 @@ +#ifndef VECTOR_H +#define VECTOR_H + +void vector_substruct(int size, const float v1[size], const float v2[size], + float r[size]); +void cross_product_vectors(const float v1[3], const float v2[3], float r[3]); +float dot_product_vectors(const float v1[3], const float v2[3]); +void vector_normalize(int size, const float v[size], float r[size]); +// void print_vector(int size, float vector[size]); + +#endif diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..391307b --- /dev/null +++ b/src/main.c @@ -0,0 +1,75 @@ +#include +#include + +#include "engine/engine.h" + +// #define WIN +// #define UNIX +// #define MICRO +#include "platforms/platform.h" + +#include "objects.h" + +float render_matrix[4][4]; + +void init_engine() { + printff(BLUE ITALIC, "Engine init..."); + + float view_matrix[4][4]; + camera_get_view_matrix(&camera, view_matrix); + printf("View matrix created\n"); + + float projection_matrix[4][4]; + camera_get_projection_matrix(&camera, projection_matrix); + printf("Projection matrix created\n"); + matrix_mult_matrix(4, projection_matrix, view_matrix, render_matrix); + printf("Render matrix created\n"); + + for (int i = 0; i < number_of_objects; i++) { + float translate_matrix[4][4]; + point_create_translate_matrix(objects[i].position, translate_matrix, 1); + object_transform(&(objects[i]), 4, translate_matrix); + printf("Go %s to (%f, %f, %f)\n", objects[i].name, + objects[i].position->coordinates[0], + objects[i].position->coordinates[1], + objects[i].position->coordinates[2]); + } + + printff(BLUE BOLD UNDERLINE, "Engine init complete!"); +} + +void render(Screen screen) { + for (int i = 0; i < number_of_objects; i++) { + object_draw(&(objects[i]), &screen, render_matrix); + } +} + +void tic() { + for (int i = 0; i < number_of_objects; i++) { + float reverse_translate_matrix[4][4]; + point_create_translate_matrix(objects[i].position, reverse_translate_matrix, + -1); + object_transform(&(objects[i]), 4, reverse_translate_matrix); + + Point center_of_object = object_get_centroid(&(objects[i])); + float reverse_center_translate_matrix[4][4]; + point_create_translate_matrix(¢er_of_object, + reverse_center_translate_matrix, -1); + object_transform(&(objects[i]), 4, reverse_center_translate_matrix); + + float rotate_matrix[3][3]; + create_rotate_matrix(*(objects[i].rotate_speed), rotate_matrix); + object_transform(&(objects[i]), 3, rotate_matrix); + + float center_translate_matrix[4][4]; + point_create_translate_matrix(¢er_of_object, center_translate_matrix, + 1); + object_transform(&(objects[i]), 4, center_translate_matrix); + + float translate_matrix[4][4]; + point_create_translate_matrix(objects[i].position, translate_matrix, 1); + object_transform(&(objects[i]), 4, translate_matrix); + } +} + +void destroy() {} \ No newline at end of file diff --git a/src/objects.h b/src/objects.h new file mode 100644 index 0000000..f13fc08 --- /dev/null +++ b/src/objects.h @@ -0,0 +1,70 @@ +#ifndef OBJECTS_H +#define OBJECTS_H + +#include "engine/engine.h" + +Point cube_points[] = { + {.coordinates = {0.0f, 0.0f, 0.0f}}, {.coordinates = {1.0f, 0.0f, 0.0f}}, + {.coordinates = {1.0f, 1.0f, 0.0f}}, {.coordinates = {0.0f, 1.0f, 0.0f}}, + {.coordinates = {0.0f, 0.0f, 1.0f}}, {.coordinates = {1.0f, 0.0f, 1.0f}}, + {.coordinates = {1.0f, 1.0f, 1.0f}}, {.coordinates = {0.0f, 1.0f, 1.0f}}}; + +Point cube_position = {.coordinates = {3.0f, 6.0f, 5.0f}}; +const int cube_edges[][2] = {{0, 1}, {1, 2}, {2, 3}, {3, 0}, {4, 5}, {5, 6}, + {6, 7}, {7, 4}, {0, 4}, {1, 5}, {2, 6}, {3, 7}}; +const float cube_speed[] = {0.03f, 0.0f, 0.0f}; +const Object cube = {.name = "cube", + .points = cube_points, + .edges = cube_edges, + .number_of_points = 8, + .number_of_edges = 12, + .position = &cube_position, + .rotate_speed = &cube_speed}; + +Point pyramid_points[] = {{.coordinates = {-1.0f, 0.0f, -1.0f}}, + {.coordinates = {1.0f, 0.0f, -1.0f}}, + {.coordinates = {1.0f, 0.0f, 1.0f}}, + {.coordinates = {-1.0f, 0.0f, 1.0f}}, + {.coordinates = {0.0f, 1.5f, 0.0f}}}; +Point pyramid_position = {.coordinates = {6.0f, 3.0f, 5.0f}}; +const int pyramid_edges[][2] = {{0, 1}, {1, 2}, {2, 3}, {3, 0}, + {0, 4}, {1, 4}, {2, 4}, {3, 4}}; +const float pyramid_speed[] = {0.0f, 0.0f, 0.03f}; +const Object pyramid = {.name = "pyramid", + .points = pyramid_points, + .edges = pyramid_edges, + .number_of_points = 5, + .number_of_edges = 8, + .position = &pyramid_position, + .rotate_speed = &pyramid_speed}; + +Point prism_points[] = { + {.coordinates = {0.0f, 0.0f, 0.0f}}, {.coordinates = {1.0f, 0.0f, 0.0f}}, + {.coordinates = {0.5f, 0.0f, 1.0f}}, {.coordinates = {0.0f, 1.0f, 0.0f}}, + {.coordinates = {1.0f, 1.0f, 0.0f}}, {.coordinates = {0.5f, 1.0f, 1.0f}}}; +Point prism_position = {.coordinates = {10.0f, 10.0f, 10.0f}}; +const int prism_edges[][2] = {{0, 1}, {1, 2}, {2, 0}, {3, 4}, {4, 5}, + {5, 3}, {0, 3}, {1, 4}, {2, 5}}; +const float prism_speed[] = {0.0f, 0.03f, 0.0f}; +const Object prism = {.name = "prism", + .points = prism_points, + .edges = prism_edges, + .number_of_points = 6, + .number_of_edges = 9, + .position = &prism_position, + .rotate_speed = &prism_speed}; + +const int number_of_objects = 3; +Object objects[] = {cube, pyramid, prism}; + +Point camera_position = {.coordinates = {0.0f, 0.0f, 0.0f}}; +Point camera_target = {.coordinates = {1.0f, 1.0f, 1.0f}}; +const Camera camera = {.position = &camera_position, + .target = &camera_target, + .up = {-1.0f, -1.0f, 1.0f}, + .fov = 120.0f, + .max_distance = 20.0f, + .min_distance = .0f, + .aspect_ratio = WINDOW_WIDTH / WINDOW_HEIGHT}; + +#endif \ No newline at end of file diff --git a/src/platforms/log.h b/src/platforms/log.h new file mode 100644 index 0000000..446a113 --- /dev/null +++ b/src/platforms/log.h @@ -0,0 +1,75 @@ +#ifndef LOG_H +#define LOG_H + +#if defined(WIN) || defined(UNIX) + +#include +// Определения цветов и стилей +#define RESET "\033[0m" +#define BOLD "\033[1m" +#define ITALIC "\033[3m" +#define UNDERLINE "\033[4m" +// Цвета текста +#define BLACK "\033[30m" +#define RED "\033[31m" +#define GREEN "\033[32m" +#define YELLOW "\033[33m" +#define BLUE "\033[34m" +#define MAGENTA "\033[35m" +#define CYAN "\033[36m" +#define WHITE "\033[37m" +// Фоновые цвета +#define BG_BLACK "\033[40m" +#define BG_RED "\033[41m" +#define BG_GREEN "\033[42m" +#define BG_YELLOW "\033[43m" +#define BG_BLUE "\033[44m" +#define BG_MAGENTA "\033[45m" +#define BG_CYAN "\033[46m" +#define BG_WHITE "\033[47m" + +#define printff(format_codes, ...) \ + do { \ + printf("%s", format_codes); \ + printf(__VA_ARGS__); \ + printf("\033[0m\n"); \ + } while (0) + +#ifdef DEBUG_MODE +#define logf(fmt, ...) \ + do { \ + printf("[%s:%d] ", __FILE__, __LINE__); \ + printf(fmt, ##__VA_ARGS__); \ + printf("\n"); \ + } while (0) +#define logff(format_codes, fmt, ...) \ + do { \ + printf("%s", format_codes); \ + printf("[%s:%d] ", __FILE__, __LINE__); \ + printf(fmt, ##__VA_ARGS__); \ + printf("\n"); \ + printf("\033[0m\n"); \ + } while (0) +#define loge(fmt, ...) logff(RED UNDERLINE, fmt, ##__VA_ARGS__) +#else +#define logf(fmt, ...) +#define logff(format_codes, fmt, ...) +#define loge(fmt, ...) +#endif // DEBUG_MODE + +#elif MICRO + +#define printff(format_codes, ...) // TODO +#ifdef DEBUG_MODE +#define logf(fmt, ...) // TODO +#define logff(format_codes, fmt, ...) // TODO +#define loge(fmt, ...) logff(RED UNDERLINE, fmt, ##__VA_ARGS__) // TODO +#else +#define logf(fmt, ...) +#define logff(format_codes, fmt, ...) +#define loge(fmt, ...) +#endif // DEBUG_MODE + +#endif // WIN || UNIX || MICRO + +#endif // UTILS_STYLES_H diff --git a/src/platforms/platform.h b/src/platforms/platform.h new file mode 100644 index 0000000..70329a9 --- /dev/null +++ b/src/platforms/platform.h @@ -0,0 +1,22 @@ +#ifndef PLATFORM_H +#define PLATFORM_H + +#include "../utils/screen.h" +#include "log.h" + +#ifdef WIN +#include "win.h" + +#define FPS 10 +#define WINDOW_WIDTH 800.0f +#define WINDOW_HEIGHT 600.0f +#define BG_COLOR BLACK_BRUSH +#define COLOR RGB(255, 255, 255) +#endif + +void init_engine(); +void render(Screen screen); +void tic(); +void destroy(); + +#endif \ No newline at end of file diff --git a/src/platforms/win.c b/src/platforms/win.c new file mode 100644 index 0000000..7c812e8 --- /dev/null +++ b/src/platforms/win.c @@ -0,0 +1,88 @@ +#include "platform.h" + +#include "win.h" + +LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, + LPARAM lParam) { + switch (uMsg) { + case WM_CREATE: + SetTimer(hwnd, 1, 50, NULL); + init_engine(); + return 0; + case WM_PAINT: { + PAINTSTRUCT ps; + HDC hdc = BeginPaint(hwnd, &ps); + + RECT rect; + GetClientRect(hwnd, &rect); + FillRect(hdc, &rect, (HBRUSH)GetStockObject(BG_COLOR)); + float width = rect.right - rect.left; + float height = rect.bottom - rect.top; + + HPEN hPen = CreatePen(PS_SOLID, 1, COLOR); + HPEN hOldPen = (HPEN)SelectObject(hdc, hPen); + + void draw_line(const ScreenPoint *sp1, const ScreenPoint *sp2) { + MoveToEx(hdc, sp1->coordinates[0], sp1->coordinates[1], NULL); + LineTo(hdc, sp2->coordinates[0], sp2->coordinates[1]); + }; + + Screen screen = {.width = width, .height = height, .draw_line = &draw_line}; + + render(screen); + + SelectObject(hdc, hOldPen); + DeleteObject(hPen); + + EndPaint(hwnd, &ps); + return 0; + } + + case WM_DESTROY: + PostQuitMessage(0); + return 0; + + case WM_TIMER: + tic(); + + InvalidateRect(hwnd, NULL, TRUE); + return 0; + + case WM_KEYDOWN: + return 0; + } + + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, + LPSTR lpCmdLine, int nCmdShow) { + const char CLASS_NAME[] = "C3DGraphicEngine"; + + WNDCLASS wc = {0}; + wc.lpfnWndProc = WindowProc; + wc.hInstance = hInstance; + wc.lpszClassName = CLASS_NAME; + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); + RegisterClass(&wc); + + HWND hwnd = CreateWindowEx(0, CLASS_NAME, CLASS_NAME, WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, CW_USEDEFAULT, WINDOW_WIDTH, + WINDOW_HEIGHT, NULL, NULL, hInstance, NULL); + + if (hwnd == NULL) { + return 0; + } + + ShowWindow(hwnd, nCmdShow); + UpdateWindow(hwnd); + + MSG msg = {0}; + while (GetMessage(&msg, NULL, 0, 0)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + return 0; +} \ No newline at end of file diff --git a/src/platforms/win.h b/src/platforms/win.h new file mode 100644 index 0000000..93104a2 --- /dev/null +++ b/src/platforms/win.h @@ -0,0 +1,6 @@ +#ifndef WIN_H +#define WIN_H + +#include + +#endif \ No newline at end of file diff --git a/src/utils/screen.h b/src/utils/screen.h new file mode 100644 index 0000000..5feb1bf --- /dev/null +++ b/src/utils/screen.h @@ -0,0 +1,16 @@ +#ifndef UTILS_H +#define UTILS_H + +struct ScreenPoint { + int coordinates[2]; +}; +typedef struct ScreenPoint ScreenPoint; + +struct Screen { + int width; + int height; + void (*draw_line)(const ScreenPoint *sp1, const ScreenPoint *sp2); +}; +typedef struct Screen Screen; + +#endif \ No newline at end of file diff --git a/utils/utils.c b/utils/utils.c deleted file mode 100644 index a104d5a..0000000 --- a/utils/utils.c +++ /dev/null @@ -1,246 +0,0 @@ -#include "utils.h" - -#include -#include -#include - -// === Vectors === -void vector_substruct(int size, float v1[size], float v2[size], float r[size]) { - for (int i = 0; i < size; i++) - r[i] = v1[i] - v2[i]; -} -void cross_product_vectors(float v1[3], float v2[3], float r[3]) { - r[0] = v1[1] * v2[2] - v1[2] * v2[1]; - r[1] = v1[2] * v2[0] - v1[0] * v2[2]; - r[2] = v1[0] * v2[1] - v1[1] * v2[0]; -} -float dot_product_vectors(float v1[3], float v2[3]) { - return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]; -} -void vector_normalize(int size, float coordinates[size]) { - float divider = 0; - for (int i = 0; i < size; i++) - divider += coordinates[i] * coordinates[i]; - divider = sqrt(divider); - float new_coordinates[size]; - for (int i = 0; i < size; i++) - coordinates[i] /= divider; -} -void print_vector(int size, float vector[size]) { - printf("("); - for (int i = 0; i < size; i++) { - printf("%f", vector[i]); - if (i != size - 1) - printf(",\t"); - } - printf(")\n"); -} - -// === Matrices === -void print_matrix(int size, float matrix[size][size]) { - for (int i = 0; i < size; i++) { - printf("("); - for (int j = 0; j < size; j++) { - printf("%f", matrix[i][j]); - if (j != size - 1) - printf(",\t"); - } - printf(")\n"); - } -} -void matrix_mult_matrix(int size, float matrix1[size][size], - float matrix2[size][size], float result[size][size]) { - for (int i = 0; i < size; i++) { - for (int j = 0; j < size; j++) { - result[i][j] = 0; - } - } - for (int i = 0; i < size; i++) { - for (int j = 0; j < size; j++) { - for (int k = 0; k < size; k++) { - result[i][j] += matrix1[i][k] * matrix2[k][j]; - } - } - } -} -void matrix_mult_vector(int size, float matrix[size][size], float vector[size], - float result[size]) { - for (int i = 0; i < size; i++) - result[i] = 0; - for (int i = 0; i < size; i++) { - for (int j = 0; j < size; j++) { - result[i] += matrix[i][j] * vector[j]; - } - } -} -void create_axis_rotate_matrix(int axis, float angle, - float rotate_matrix[3][3]) { - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 3; j++) { - rotate_matrix[i][j] = 0; - } - } - - float cos_angle = cosf(angle); - float sin_angle = sinf(angle); - - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 3; j++) { - if (i == axis || j == axis) { - if (i == j) - rotate_matrix[i][j] = 1; - else - rotate_matrix[i][j] = 0; - } else { - if (i == j) { - rotate_matrix[i][j] = cos_angle; - } else { - if ((i < j && axis == 2) || (i > j && axis != 2)) { - rotate_matrix[i][j] = sin_angle; - } else { - rotate_matrix[i][j] = -sin_angle; - } - } - } - } - } -} - -void create_rotate_matrix(float rotate_speed[3], float rotate_matrix[3][3]) { - float x_rotate[3][3]; - create_axis_rotate_matrix(0, rotate_speed[0], x_rotate); - float y_rotate[3][3]; - create_axis_rotate_matrix(1, rotate_speed[1], y_rotate); - float z_rotate[3][3]; - create_axis_rotate_matrix(2, rotate_speed[2], z_rotate); - float xy_rotate[3][3]; - matrix_mult_matrix(3, x_rotate, y_rotate, xy_rotate); - matrix_mult_matrix(3, xy_rotate, z_rotate, rotate_matrix); -} - -// === Points in scene === -void transform_point(Point3D *point, int size, - float translate_matrix[size][size]) { - float new_coordinates[3]; - float old_coordinates[] = {point->coordinates[0], point->coordinates[1], - point->coordinates[2], 1.0f}; - matrix_mult_vector(size, translate_matrix, old_coordinates, new_coordinates); - for (int i = 0; i < 3; i++) - point->coordinates[i] = new_coordinates[i]; -} -void create_translate_matrix(Point3D *position, float translate_matrix[4][4], - int k) { - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 4; j++) { - translate_matrix[i][j] = 0; - if (i == j) - translate_matrix[i][j] = 1; - else if (j == 3) - translate_matrix[i][j] = position->coordinates[i] * k; - } - } -} - -// === Points on screen === -ScreenPoint convert_to_screen_point(Point3D *point, Screen *screen) { - float tmp[] = {point->coordinates[0], point->coordinates[1], - point->coordinates[2], 1.0f}; - float point_projection_view[4]; - matrix_mult_vector(4, *(screen->render_matrix), tmp, point_projection_view); - - float perspective_coordinates[3] = { - point_projection_view[0] / point_projection_view[3], - point_projection_view[1] / point_projection_view[3], - point_projection_view[2] / point_projection_view[3], - }; - ScreenPoint spoint = { - .coordinates = {((perspective_coordinates[0] + 1.0f) / 2.0f) * - (float)screen->width, - ((perspective_coordinates[1] + 1.0f) / 2.0f) * - (float)screen->height}}; - return spoint; -} - -void draw_line(Screen *screen, ScreenPoint *sp1, ScreenPoint *sp2) { - MoveToEx(*(screen->hdc), sp1->coordinates[0], sp1->coordinates[1], NULL); - LineTo(*(screen->hdc), sp2->coordinates[0], sp2->coordinates[1]); -} - -// === Camera === -void create_view_matrix(Camera *camera, float view_matrix[4][4]) { - float forward[3]; - vector_substruct(3, camera->position.coordinates, camera->target.coordinates, - forward); - vector_normalize(3, forward); - float right[3]; - cross_product_vectors(camera->up, forward, right); - vector_normalize(3, right); - - float up[3]; - cross_product_vectors(forward, right, up); - vector_normalize(3, up); - - float *vectors[] = {right, up, forward}; - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 4; j++) { - view_matrix[i][j] = 0; - if (i == 3) { - if (j == 3) - view_matrix[i][j] = 1; - } else if (j == 3) { - view_matrix[i][j] = - -1 * dot_product_vectors(vectors[i], camera->position.coordinates); - } else { - view_matrix[i][j] = vectors[i][j]; - } - } - } -} -void create_projection_matrix(Camera *camera, float projection_matrix[4][4]) { - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 4; j++) { - projection_matrix[i][j] = 0; - } - } - float f = 1 / tan(camera->fov / 2); - projection_matrix[0][0] = f / camera->aspect_ratio; - projection_matrix[1][1] = f; - projection_matrix[2][2] = (camera->max_distance + camera->min_distance) / - (camera->min_distance - camera->max_distance); - projection_matrix[3][2] = -1; - projection_matrix[2][3] = (2 * camera->max_distance * camera->min_distance) / - (camera->min_distance - camera->max_distance); -} - -// === Composite objects === -void transform_object(const Object *object, int size, - float translate_matrix[size][size]) { - for (int i = 0; i < object->number_of_points; i++) { - transform_point(&(object->points[i]), size, translate_matrix); - } -} -void draw_object(const Object *object, Screen *screen) { - for (int i = 0; i < object->number_of_edges; i++) { - Point3D point1 = object->points[object->edges[i][0]]; - ScreenPoint screen_point1 = convert_to_screen_point(&point1, screen); - Point3D point2 = object->points[object->edges[i][1]]; - ScreenPoint screen_point2 = convert_to_screen_point(&point2, screen); - draw_line(screen, &screen_point1, &screen_point2); - } -} -Point3D calculate_centroid(const Object *object) { - Point3D centroid = {{0.0f, 0.0f, 0.0f}}; - - for (int i = 0; i < object->number_of_points; i++) { - centroid.coordinates[0] += object->points[i].coordinates[0]; - centroid.coordinates[1] += object->points[i].coordinates[1]; - centroid.coordinates[2] += object->points[i].coordinates[2]; - } - - float inv_n = 1.0f / (float)object->number_of_points; - centroid.coordinates[0] *= inv_n; - centroid.coordinates[1] *= inv_n; - centroid.coordinates[2] *= inv_n; - - return centroid; -} \ No newline at end of file diff --git a/utils/utils.h b/utils/utils.h deleted file mode 100644 index 95c2f4f..0000000 --- a/utils/utils.h +++ /dev/null @@ -1,80 +0,0 @@ -#ifndef OBJECTS_H -#define OBJECTS_H - -#include - -// === Vectors === -void vector_substruct(int size, float v1[size], float v2[size], float r[size]); -void cross_product_vectors(float v1[3], float v2[3], float r[3]); -float dot_product_vectors(float v1[3], float v2[3]); -void vector_normalize(int size, float coordinates[size]); -void print_vector(int size, float vector[size]); - -// === Matrix === -void print_matrix(int size, float matrix[size][size]); -void matrix_mult_matrix(int size, float matrix1[size][size], - float matrix2[size][size], float result[size][size]); -void matrix_mult_vector(int size, float matrix[size][size], float vector[size], - float result[size]); - -void create_axis_rotate_matrix(int axis, float angle, - float rotate_matrix[3][3]); -void create_rotate_matrix(float rotate_speed[3], float rotate_matrix[3][3]); - -// === Point in scene === -struct Point3D { - float coordinates[3]; -}; -typedef struct Point3D Point3D; -void transform_point(Point3D *point, int size, - float translate_matrix[size][size]); -void create_translate_matrix(Point3D *position, float translate_matrix[4][4], - int k); - -// === Screen summary === -struct Screen { - int width; - int height; - HDC *hdc; - float (*render_matrix)[4][4]; -}; -typedef struct Screen Screen; - -// === Point on screen === -struct ScreenPoint { - int coordinates[2]; -}; -typedef struct ScreenPoint ScreenPoint; -ScreenPoint convert_to_screen_point(Point3D *point, Screen *screen); -void draw_line(Screen *screen, ScreenPoint *sp1, ScreenPoint *sp2); - -// === Camera in scene === -struct Camera { - Point3D position; - Point3D target; - float up[3]; - float fov; - float max_distance; - float min_distance; - float aspect_ratio; -}; -typedef struct Camera Camera; -void create_view_matrix(Camera *camera, float view_matrix[4][4]); -void create_projection_matrix(Camera *camera, float projection_matrix[4][4]); - -// === Composite object in scene === -struct Object { - Point3D *points; - int (*edges)[2]; - int number_of_points; - int number_of_edges; - Point3D *position; - float (*rotate_speed)[3]; -}; -typedef struct Object Object; -void transform_object(const Object *object, int size, - float translate_matrix[size][size]); -void draw_object(const Object *object, Screen *screen); -Point3D calculate_centroid(const Object *object); - -#endif \ No newline at end of file