Skip to content

Instantly share code, notes, and snippets.

@littlefuntik
Last active December 4, 2020 10:20
Show Gist options
  • Save littlefuntik/179dbd4c686fc0b44e2085c902777d88 to your computer and use it in GitHub Desktop.
Save littlefuntik/179dbd4c686fc0b44e2085c902777d88 to your computer and use it in GitHub Desktop.
Read habr post and write code example habr.com/ru/post/334580/
// 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