mirror of
https://github.com/StepanovPlaton/C3DGraphicEngine.git
synced 2026-04-03 20:30:42 +04:00
Begin cross platform support
This commit is contained in:
7
.gitignore
vendored
7
.gitignore
vendored
@@ -1,2 +1,5 @@
|
|||||||
main.exe
|
src/main.exe
|
||||||
*.o
|
src/main
|
||||||
|
*.wo
|
||||||
|
*.uo
|
||||||
|
*.mo
|
||||||
29
Makefile
29
Makefile
@@ -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
|
|
||||||
188
main.c
188
main.c
@@ -1,188 +0,0 @@
|
|||||||
#include <math.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
#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;
|
|
||||||
}
|
|
||||||
38
src/Makefile
Normal file
38
src/Makefile
Normal file
@@ -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
|
||||||
54
src/engine/camera.c
Normal file
54
src/engine/camera.c
Normal file
@@ -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);
|
||||||
|
}
|
||||||
21
src/engine/camera.h
Normal file
21
src/engine/camera.h
Normal file
@@ -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
|
||||||
1
src/engine/engine.c
Normal file
1
src/engine/engine.c
Normal file
@@ -0,0 +1 @@
|
|||||||
|
#include "engine.h"
|
||||||
10
src/engine/engine.h
Normal file
10
src/engine/engine.h
Normal file
@@ -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
|
||||||
87
src/engine/matrix.c
Normal file
87
src/engine/matrix.c
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
#include "matrix.h"
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
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");
|
||||||
|
// }
|
||||||
|
// }
|
||||||
16
src/engine/matrix.h
Normal file
16
src/engine/matrix.h
Normal file
@@ -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
|
||||||
41
src/engine/object.c
Normal file
41
src/engine/object.c
Normal file
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
23
src/engine/object.h
Normal file
23
src/engine/object.h
Normal file
@@ -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
|
||||||
46
src/engine/point.c
Normal file
46
src/engine/point.c
Normal file
@@ -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;
|
||||||
|
}
|
||||||
17
src/engine/point.h
Normal file
17
src/engine/point.h
Normal file
@@ -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
|
||||||
35
src/engine/vector.c
Normal file
35
src/engine/vector.c
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
#include "vector.h"
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
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");
|
||||||
|
// }
|
||||||
11
src/engine/vector.h
Normal file
11
src/engine/vector.h
Normal file
@@ -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
|
||||||
75
src/main.c
Normal file
75
src/main.c
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
#include <math.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#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() {}
|
||||||
70
src/objects.h
Normal file
70
src/objects.h
Normal file
@@ -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
|
||||||
75
src/platforms/log.h
Normal file
75
src/platforms/log.h
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
#ifndef LOG_H
|
||||||
|
#define LOG_H
|
||||||
|
|
||||||
|
#if defined(WIN) || defined(UNIX)
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
// Определения цветов и стилей
|
||||||
|
#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
|
||||||
22
src/platforms/platform.h
Normal file
22
src/platforms/platform.h
Normal file
@@ -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
|
||||||
88
src/platforms/win.c
Normal file
88
src/platforms/win.c
Normal file
@@ -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;
|
||||||
|
}
|
||||||
6
src/platforms/win.h
Normal file
6
src/platforms/win.h
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#ifndef WIN_H
|
||||||
|
#define WIN_H
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#endif
|
||||||
16
src/utils/screen.h
Normal file
16
src/utils/screen.h
Normal file
@@ -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
|
||||||
246
utils/utils.c
246
utils/utils.c
@@ -1,246 +0,0 @@
|
|||||||
#include "utils.h"
|
|
||||||
|
|
||||||
#include <math.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
// === 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;
|
|
||||||
}
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
#ifndef OBJECTS_H
|
|
||||||
#define OBJECTS_H
|
|
||||||
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
// === 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
|
|
||||||
Reference in New Issue
Block a user