1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
#include <assert.h>
#include <math.h>
#include <stdlib.h>
#include <time.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL2_gfxPrimitives.h>
#include "sdl_wrapper.h"
const char WINDOW_TITLE[] = "CS 3";
const int WINDOW_WIDTH = 1000;
const int WINDOW_HEIGHT = 500;
/**
* The coordinate at the center of the screen.
*/
vector_t center;
/**
* The coordinate difference from the center to the top right corner.
*/
vector_t max_diff;
/**
* The SDL window where the scene is rendered.
*/
SDL_Window *window;
/**
* The renderer used to draw the scene.
*/
SDL_Renderer *renderer;
/**
* The value of clock() when time_since_last_tick() was last called.
* Initially 0.
*/
clock_t last_clock = 0;
/** Computes the center of the window in pixel coordinates */
vector_t get_window_center(void) {
int *width = malloc(sizeof(*width)),
*height = malloc(sizeof(*height));
assert(width != NULL);
assert(height != NULL);
SDL_GetWindowSize(window, width, height);
vector_t dimensions = {.x = *width, .y = *height};
free(width);
free(height);
return vec_multiply(0.5, dimensions);
}
/**
* Computes the scaling factor between scene coordinates and pixel coordinates.
* The scene is scaled by the same factor in the x and y dimensions,
* chosen to maximize the size of the scene while keeping it in the window.
*/
double get_scene_scale(vector_t window_center) {
// Scale scene so it fits entirely in the window
double x_scale = window_center.x / max_diff.x,
y_scale = window_center.y / max_diff.y;
return x_scale < y_scale ? x_scale : y_scale;
}
/** Maps a scene coordinate to a window coordinate */
vector_t get_window_position(vector_t scene_pos, vector_t window_center) {
// Scale scene coordinates by the scaling factor
// and map the center of the scene to the center of the window
vector_t scene_center_offset = vec_subtract(scene_pos, center);
double scale = get_scene_scale(window_center);
vector_t pixel_center_offset = vec_multiply(scale, scene_center_offset);
vector_t pixel = {
.x = round(window_center.x + pixel_center_offset.x),
// Flip y axis since positive y is down on the screen
.y = round(window_center.y - pixel_center_offset.y)
};
return pixel;
}
void sdl_init(vector_t min, vector_t max) {
// Check parameters
assert(min.x < max.x);
assert(min.y < max.y);
center = vec_multiply(0.5, vec_add(min, max)),
max_diff = vec_subtract(max, center);
SDL_Init(SDL_INIT_EVERYTHING);
window = SDL_CreateWindow(
WINDOW_TITLE,
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
WINDOW_WIDTH,
WINDOW_HEIGHT,
SDL_WINDOW_RESIZABLE
);
renderer = SDL_CreateRenderer(window, -1, 0);
}
bool sdl_is_done(void) {
SDL_Event *event = malloc(sizeof(*event));
assert(event != NULL);
bool quit = false;
while (SDL_PollEvent(event)) {
if (event->type == SDL_QUIT) {
quit = true;
break;
}
}
free(event);
return quit;
}
void sdl_clear(void) {
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
SDL_RenderClear(renderer);
}
void sdl_draw_polygon(vec_list_t *points, float r, float g, float b) {
// Check parameters
size_t n = vec_list_size(points);
assert(n >= 3);
assert(0 <= r && r <= 1);
assert(0 <= g && g <= 1);
assert(0 <= b && b <= 1);
vector_t window_center = get_window_center();
// Convert each vertex to a point on screen
int16_t *x_points = malloc(sizeof(*x_points) * n),
*y_points = malloc(sizeof(*y_points) * n);
assert(x_points != NULL);
assert(y_points != NULL);
for (size_t i = 0; i < n; i++) {
vector_t *vertex = vec_list_get(points, i);
vector_t pixel = get_window_position(*vertex, window_center);
x_points[i] = pixel.x;
y_points[i] = pixel.y;
}
// Draw polygon with the given color
filledPolygonRGBA(
renderer,
x_points, y_points, n,
r * 255, g * 255, b * 255, 255
);
free(x_points);
free(y_points);
}
void sdl_show(void) {
// Draw boundary lines
vector_t window_center = get_window_center();
vector_t max = vec_add(center, max_diff),
min = vec_subtract(center, max_diff);
vector_t max_pixel = get_window_position(max, window_center),
min_pixel = get_window_position(min, window_center);
SDL_Rect *boundary = malloc(sizeof(*boundary));
boundary->x = min_pixel.x;
boundary->y = max_pixel.y;
boundary->w = max_pixel.x - min_pixel.x;
boundary->h = min_pixel.y - max_pixel.y;
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderDrawRect(renderer, boundary);
free(boundary);
SDL_RenderPresent(renderer);
}
double time_since_last_tick(void) {
clock_t now = clock();
double difference = last_clock
? (double) (now - last_clock) / CLOCKS_PER_SEC
: 0.0; // return 0 the first time this is called
last_clock = now;
return difference;
}