Last active
December 4, 2020 10:20
-
-
Save littlefuntik/179dbd4c686fc0b44e2085c902777d88 to your computer and use it in GitHub Desktop.
Read habr post and write code example habr.com/ru/post/334580/
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// clang -o program program.c $(sdl2-config --cflags --libs) && ls -lah && ./program | |
#include <SDL2/SDL.h> | |
#include <stdlib.h> | |
#include <time.h> | |
const int SCREEN_WIDTH = 640; | |
const int SCREEN_HEIGHT = 480; | |
const int LIGHT_TYPE_POINT = 1; | |
const int DRAW_POINTS_COUNT = 255; | |
///// | |
// types | |
///// | |
struct point | |
{ | |
double a, b, c; | |
struct color *color; | |
}; | |
struct vector | |
{ | |
double X, Y, Z; | |
}; | |
struct color | |
{ | |
Uint8 r, g, b, a; | |
}; | |
struct lighting | |
{ | |
double x, y, z; | |
Uint8 r, g, b; | |
int light_type; | |
int radius; | |
}; | |
struct camera | |
{ | |
int minX, minY, minZ; | |
int maxX, maxY, maxZ; | |
struct lighting *light; | |
}; | |
struct draw_objects | |
{ | |
struct point points[DRAW_POINTS_COUNT]; | |
}; | |
///// | |
// Helpers | |
///// | |
double degrees_to_radians(double angle_in_degrees) | |
{ | |
// return angle_in_degrees * M_PI / 180.0; | |
return angle_in_degrees / 57.29578; | |
} | |
double radians_to_degrees(double angle_in_radians) | |
{ | |
// return angle_in_radians * 180.0 / M_PI; | |
return angle_in_radians / 0.017453; | |
} | |
double randfrom(double min, double max) | |
{ | |
double range = (max - min); | |
double div = RAND_MAX / range; | |
return min + (rand() / div); | |
} | |
///// | |
// Constructors | |
///// | |
struct point *new_point(double a, double b, double c) | |
{ | |
struct point *p = malloc(sizeof(struct point)); | |
p->a = a; | |
p->b = b; | |
p->c = c; | |
return p; | |
} | |
struct vector *new_vector(double X, double Y, double Z) | |
{ | |
struct vector *v = malloc(sizeof(struct vector)); | |
v->X = X; | |
v->Y = Y; | |
v->Z = Z; | |
return v; | |
} | |
struct camera *new_camera(int minX, int maxX, int minY, int maxY, int minZ, int maxZ, struct lighting *light) | |
{ | |
struct camera *cam = malloc(sizeof(struct camera)); | |
cam->minX = minX; | |
cam->maxX = maxX; | |
cam->minY = minY; | |
cam->maxY = maxY; | |
cam->minZ = minZ; | |
cam->maxZ = maxZ; | |
cam->light = light; | |
return cam; | |
} | |
struct color *new_color(Uint8 r, Uint8 g, Uint8 b, Uint8 a) | |
{ | |
struct color *c = malloc(sizeof(struct color)); | |
c->r = r; | |
c->g = g; | |
c->b = b; | |
c->a = a; | |
return c; | |
} | |
struct color *copy_color(struct color *c) | |
{ | |
return new_color(c->r, c->g, c->b, c->a); | |
} | |
struct lighting *new_lighting(double x, double y, double z, Uint8 r, Uint8 g, Uint8 b, int light_type, int radius) | |
{ | |
struct lighting *l = malloc(sizeof(struct lighting)); | |
l->x = x; | |
l->y = y; | |
l->z = z; | |
l->r = r; | |
l->g = g; | |
l->b = b; | |
l->light_type = light_type; | |
l->radius = radius; | |
return l; | |
} | |
struct draw_objects *new_draw_objects() | |
{ | |
struct draw_objects *objects = malloc(sizeof(struct draw_objects)); | |
return objects; | |
} | |
///// | |
// Point | |
///// | |
void add_vector_to_point(struct vector *v, struct point *p) | |
{ | |
p->a = p->a + v->X; | |
p->b = p->b + v->Y; | |
p->c = p->c + v->Z; | |
} | |
void substract_vector_from_point(struct vector *v, struct point *p) | |
{ | |
p->a = p->a - v->X; | |
p->b = p->b - v->Y; | |
p->c = p->c - v->Z; | |
} | |
struct vector *substract_point_from_point(struct point *p1, struct point *p2) | |
{ | |
return new_vector(p1->a - p2->a, p1->b - p2->b, p1->c - p2->c); | |
} | |
double points_distance(struct point *p1, struct point *p2) | |
{ | |
return sqrt(pow(p1->a - p2->a, 2) + pow(p1->b - p2->b, 2) + pow(p1->c - p2->c, 2)); | |
} | |
int draw_point(struct point *p, SDL_Renderer *renderer) | |
{ | |
//SDL_Log("Point: %.2f %.2f %.2f\n", p->a, p->b, p->c); | |
int res; | |
if ((res = SDL_RenderDrawPoint(renderer, (int)round(p->a), (int)round(p->b))) != 0) | |
{ | |
SDL_Log("Cannot draw point! SDL_Error: %s\n", SDL_GetError()); | |
return res; | |
} | |
return 0; | |
} | |
void set_point_to_point(struct point *p1, struct point *p2) | |
{ | |
p1->a = p2->a; | |
p1->b = p2->b; | |
p1->c = p2->c; | |
} | |
///// | |
// Vector | |
///// | |
struct vector *add_vector_to_vector(struct vector *v1, struct vector *v2) | |
{ | |
return new_vector(v1->X + v2->X, v1->Y + v2->Y, v1->Z + v2->Z); | |
} | |
struct vector *substract_vector_from_vector(struct vector *v1, struct vector *v2) | |
{ | |
return new_vector(v1->X - v2->X, v1->Y - v2->Y, v1->Z - v2->Z); | |
} | |
void vector_rotate_xy(struct vector *v, double degrees) | |
{ | |
double radians = degrees_to_radians(degrees); | |
double b0 = cos(radians) * v->X - sin(radians) * v->Y; | |
double b1 = sin(radians) * v->X + cos(radians) * v->Y; | |
v->X = b0; | |
v->Y = b1; | |
} | |
void vector_rotate_xz(struct vector *v, double degrees) | |
{ | |
double radians = degrees_to_radians(degrees); | |
double b0 = cos(radians) * v->X + sin(radians) * v->Z; | |
double b2 = -1 * sin(radians) * v->X + cos(radians) * v->Z; | |
v->X = b0; | |
v->Z = b2; | |
} | |
void vector_rotate_yz(struct vector *v, double degrees) | |
{ | |
double radians = degrees_to_radians(degrees); | |
double b1 = cos(radians) * v->Y - sin(radians) * v->Z; | |
double b2 = sin(radians) * v->Y + cos(radians) * v->Z; | |
v->Y = b1; | |
v->Z = b2; | |
} | |
void vector_scale(struct vector *v, double s0, double s1, double s2) | |
{ | |
v->X = v->X * s0; | |
v->Y = v->Y * s1; | |
v->Z = v->Z * s2; | |
} | |
///// | |
// Camera | |
///// | |
int draw_scene(SDL_Renderer *renderer, struct camera *cam, struct draw_objects *objects) | |
{ | |
int res; | |
//SDL_Log("----- DRAW SCENE -----\n"); | |
struct color *color_black = new_color(0x00, 0x00, 0x00, 0); | |
// clear canvas | |
if ((res = SDL_SetRenderDrawColor(renderer, color_black->r, color_black->g, color_black->b, color_black->a)) != 0) | |
{ | |
SDL_Log("Cannot set render draw color! SDL_Error: %s\n", SDL_GetError()); | |
return res; | |
} | |
if ((res = SDL_RenderClear(renderer)) != 0) | |
{ | |
SDL_Log("Cannot render clear! SDL_Error: %s\n", SDL_GetError()); | |
return res; | |
} | |
int i; | |
double light_percentage; | |
struct point light_point; | |
for (i = 0; i < DRAW_POINTS_COUNT; i++) | |
{ | |
struct point *point_ptr = NULL; | |
point_ptr = &(objects->points[i]); | |
//SDL_Log("POINT COLOR %d %d %d\n", point_ptr->color->r, point_ptr->color->g, point_ptr->color->b); | |
// set draw color | |
if ((res = SDL_SetRenderDrawColor(renderer, point_ptr->color->r, point_ptr->color->g, point_ptr->color->b, point_ptr->color->a)) != 0) | |
{ | |
SDL_Log("Cannot set render draw color! SDL_Error: %s\n", SDL_GetError()); | |
return res; | |
} | |
// skeep camera out points | |
if (point_ptr->a < (double)cam->minX || point_ptr->a > (double)cam->maxX) | |
{ | |
//SDL_Log("Skeep point %.2f %.2f %.2f by X(%.2f..%.2f)\n", point_ptr->a, point_ptr->b, point_ptr->c, (double)cam->minX, (double)cam->maxX); | |
continue; | |
} | |
if (point_ptr->b < (double)cam->minY || point_ptr->b > (double)cam->maxY) | |
{ | |
//SDL_Log("Skeep point %.2f %.2f %.2f by Y(%.2f..%.2f)\n", point_ptr->a, point_ptr->b, point_ptr->c, (double)cam->minY, (double)cam->maxY); | |
continue; | |
} | |
if (point_ptr->c < (double)cam->minZ || point_ptr->c > (double)cam->maxZ) | |
{ | |
//SDL_Log("Skeep point %.2f %.2f %.2f by Z(%.2f..%.2f)\n", point_ptr->a, point_ptr->b, point_ptr->c, (double)cam->minZ, (double)cam->maxZ); | |
continue; | |
} | |
light_point.color = copy_color(point_ptr->color); | |
light_point.a = cam->light->x; | |
light_point.b = cam->light->y; | |
light_point.c = cam->light->z; | |
if (point_ptr->a >= (cam->light->x - cam->light->radius) && point_ptr->a <= (cam->light->x + cam->light->radius)) | |
{ | |
if (point_ptr->b >= (cam->light->y - cam->light->radius) && point_ptr->b <= (cam->light->y + cam->light->radius)) | |
{ | |
light_percentage = points_distance(point_ptr, &light_point) / cam->light->radius; | |
light_point.color->r = (Uint8)((double)light_point.color->r * light_percentage); | |
light_point.color->g = (Uint8)((double)light_point.color->g * light_percentage); | |
light_point.color->b = (Uint8)((double)light_point.color->b * light_percentage); | |
light_point.a = point_ptr->a; | |
light_point.b = point_ptr->b; | |
light_point.c = point_ptr->c; | |
//SDL_Log("lighting is %.2f (%d %d %d)!\n", light_percentage, light_point.color->r, light_point.color->g, light_point.color->b); | |
} | |
} | |
if ((res = draw_point(&light_point, renderer)) != 0) | |
{ | |
SDL_Log("Cannot draw point!\n"); | |
return res; | |
} | |
} | |
SDL_RenderPresent(renderer); | |
return 0; | |
} | |
///// | |
// Program | |
///// | |
void calculate_test(SDL_Renderer *renderer) | |
{ | |
struct point *point1 = new_point(1, 2, 1); | |
struct point *point2 = new_point(0, 4, 4); | |
struct vector *vector1 = new_vector(2, 0, 0); | |
struct vector *vector2; | |
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 100); | |
draw_point(point1, renderer); //должна вывести (1,2,1) | |
draw_point(point2, renderer); //должна вывести (0,4,4) | |
vector2 = substract_point_from_point(point1, point2); | |
vector1 = add_vector_to_vector(vector1, vector2); | |
add_vector_to_point(vector1, point1); | |
draw_point(point1, renderer); //должна вывести (4,0,-2) | |
substract_vector_from_point(vector2, point2); | |
draw_point(point2, renderer); //должна вывести (-1,6,7) | |
SDL_RenderDrawLine(renderer, 100, 100, 300, 300); | |
SDL_RenderPresent(renderer); | |
} | |
int main(int argc, char *argv[]) | |
{ | |
SDL_Window *window = NULL; | |
SDL_Surface *screen = NULL; | |
SDL_Renderer *renderer = NULL; | |
if (SDL_Init(SDL_INIT_VIDEO) != 0) | |
{ | |
SDL_Log("SDL could not initialize! SDL_Error: %s\n", SDL_GetError()); | |
SDL_Quit(); | |
return 1; | |
} | |
if ((window = SDL_CreateWindow("Test Project", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN)) == NULL) | |
{ | |
SDL_Log("Window could not created!\n"); | |
SDL_Quit(); | |
return 1; | |
} | |
if ((renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED)) == NULL) | |
{ | |
SDL_Log("Renderer could not found!\n"); | |
SDL_Quit(); | |
return 1; | |
} | |
// initialize random points | |
struct lighting *light = new_lighting(100, 100, 100, 0xFF, 0xFF, 0xFF, LIGHT_TYPE_POINT, 100); | |
struct camera *cam = new_camera(0, 150, 0, 150, 0, 100, light); | |
double camHalfWidth = round((double)(cam->maxX - cam->minX) / 2); | |
double camHalfHeight = round((double)(cam->maxY - cam->minY) / 2); | |
struct color *color_white = new_color(0xFF, 0xFF, 0xFF, 0); | |
struct draw_objects *objects = new_draw_objects(); | |
int i; | |
srand(time(NULL)); | |
for (i = 0; i < DRAW_POINTS_COUNT; i++) | |
{ | |
objects->points[i].a = randfrom(100, 300); | |
objects->points[i].b = randfrom(100, 300); | |
objects->points[i].c = randfrom(0, 100); | |
objects->points[i].color = color_white; | |
} | |
struct point *origin = new_point(0, 0, 0); | |
char running = 1; | |
while (running) | |
{ | |
SDL_Event e; | |
while (SDL_PollEvent(&e)) | |
{ | |
if (e.type == SDL_QUIT) | |
{ | |
running = 0; | |
break; | |
} | |
else if (e.type == SDL_KEYDOWN) | |
{ | |
if (e.key.keysym.sym == SDLK_q) | |
{ | |
running = 0; | |
break; | |
} | |
else if (e.key.keysym.sym == SDLK_d) | |
{ | |
if (draw_scene(renderer, cam, objects) != 0) | |
{ | |
SDL_Log("Cannot draw scene."); | |
} | |
} | |
else if (e.key.keysym.sym == SDLK_a) | |
{ | |
struct vector *temp_vector = NULL; | |
for (i = 0; i < DRAW_POINTS_COUNT; i++) | |
{ | |
temp_vector = substract_point_from_point(&(objects->points[i]), origin); | |
set_point_to_point(&(objects->points[i]), origin); | |
vector_scale(temp_vector, 0.5, 0.5, 0.5); | |
add_vector_to_point(temp_vector, &(objects->points[i])); | |
} | |
if (draw_scene(renderer, cam, objects) != 0) | |
{ | |
SDL_Log("Cannot draw scene."); | |
} | |
} | |
else if (e.key.keysym.sym == SDLK_s) | |
{ | |
struct vector *temp_vector = NULL; | |
for (i = 0; i < DRAW_POINTS_COUNT; i++) | |
{ | |
temp_vector = substract_point_from_point(&(objects->points[i]), origin); | |
set_point_to_point(&(objects->points[i]), origin); | |
vector_scale(temp_vector, 2.0, 2.0, 2.0); | |
add_vector_to_point(temp_vector, &(objects->points[i])); | |
} | |
if (draw_scene(renderer, cam, objects) != 0) | |
{ | |
SDL_Log("Cannot draw scene."); | |
} | |
} | |
else if (e.key.keysym.sym == SDLK_r) | |
{ | |
struct vector *temp_vector = NULL; | |
for (i = 0; i < DRAW_POINTS_COUNT; i++) | |
{ | |
temp_vector = substract_point_from_point(&(objects->points[i]), origin); | |
set_point_to_point(&(objects->points[i]), origin); | |
vector_rotate_xy(temp_vector, 15); | |
add_vector_to_point(temp_vector, &(objects->points[i])); | |
} | |
if (draw_scene(renderer, cam, objects) != 0) | |
{ | |
SDL_Log("Cannot draw scene."); | |
} | |
} | |
} else if (e.type == SDL_MOUSEMOTION) | |
{ | |
cam->minX = e.motion.x - (int)camHalfWidth; | |
cam->maxX = e.motion.x + (int)camHalfWidth; | |
cam->minY = e.motion.y - (int)camHalfHeight; | |
cam->maxY = e.motion.y + (int)camHalfHeight; | |
if (draw_scene(renderer, cam, objects) != 0) | |
{ | |
SDL_Log("Cannot draw scene."); | |
} | |
} | |
} | |
} | |
SDL_DestroyRenderer(renderer); | |
SDL_DestroyWindow(window); | |
SDL_Quit(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment