triangle.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. // This example renders a rotating triangle.
  2. // This idea is that you can take this code and compile it to different platforms with different rendering machanisms:
  3. // native with SDL, WebAssembly with HTML5 canvas, etc.
  4. #define OLIVEC_IMPLEMENTATION
  5. #include "olive.c"
  6. #define WIDTH 800
  7. #define HEIGHT 600
  8. #define BACKGROUND_COLOR 0xFF181818
  9. #define CIRCLE_RADIUS 100
  10. #define CIRCLE_COLOR 0x99AA2020
  11. static uint32_t pixels[WIDTH*HEIGHT];
  12. static float triangle_angle = 0;
  13. static float circle_x = WIDTH/2;
  14. static float circle_y = HEIGHT/2;
  15. static float circle_dx = 100;
  16. static float circle_dy = 100;
  17. float sqrtf(float x);
  18. float atan2f(float y, float x);
  19. float sinf(float x);
  20. float cosf(float x);
  21. #define PI 3.14159265359
  22. static inline void rotate_point(float *x, float *y)
  23. {
  24. float dx = *x - WIDTH/2;
  25. float dy = *y - HEIGHT/2;
  26. float mag = sqrtf(dx*dx + dy*dy);
  27. float dir = atan2f(dy, dx) + triangle_angle;
  28. *x = cosf(dir)*mag + WIDTH/2;
  29. *y = sinf(dir)*mag + HEIGHT/2;
  30. }
  31. uint32_t *render(float dt)
  32. {
  33. Olivec_Canvas oc = olivec_canvas(pixels, WIDTH, HEIGHT);
  34. olivec_fill(oc, BACKGROUND_COLOR);
  35. // Triangle
  36. {
  37. triangle_angle += 0.5f*PI*dt;
  38. float x1 = WIDTH/2, y1 = HEIGHT/8;
  39. float x2 = WIDTH/8, y2 = HEIGHT/2;
  40. float x3 = WIDTH*7/8, y3 = HEIGHT*7/8;
  41. rotate_point(&x1, &y1);
  42. rotate_point(&x2, &y2);
  43. rotate_point(&x3, &y3);
  44. olivec_triangle(oc, x1, y1, x2, y2, x3, y3, 0xFF2020AA);
  45. }
  46. // Circle
  47. {
  48. float x = circle_x + circle_dx*dt;
  49. if (x - CIRCLE_RADIUS < 0 || x + CIRCLE_RADIUS >= WIDTH) {
  50. circle_dx *= -1;
  51. } else {
  52. circle_x = x;
  53. }
  54. float y = circle_y + circle_dy*dt;
  55. if (y - CIRCLE_RADIUS < 0 || y + CIRCLE_RADIUS >= HEIGHT) {
  56. circle_dy *= -1;
  57. } else {
  58. circle_y = y;
  59. }
  60. olivec_circle(oc, circle_x, circle_y, CIRCLE_RADIUS, CIRCLE_COLOR);
  61. }
  62. return pixels;
  63. }
  64. #define WASM_PLATFORM 0
  65. #define SDL_PLATFORM 1
  66. #define TERM_PLATFORM 2
  67. #if PLATFORM == SDL_PLATFORM
  68. #include <stdio.h>
  69. #include <SDL2/SDL.h>
  70. #define return_defer(value) do { result = (value); goto defer; } while (0)
  71. int main(void)
  72. {
  73. int result = 0;
  74. SDL_Window *window = NULL;
  75. SDL_Renderer *renderer = NULL;
  76. SDL_Texture *texture = NULL;
  77. {
  78. if (SDL_Init(SDL_INIT_VIDEO) < 0) return_defer(1);
  79. window = SDL_CreateWindow("Olivec", 0, 0, WIDTH, HEIGHT, 0);
  80. if (window == NULL) return_defer(1);
  81. renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
  82. if (renderer == NULL) return_defer(1);
  83. texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_STREAMING, WIDTH, HEIGHT);
  84. if (texture == NULL) return_defer(1);
  85. Uint32 prev = SDL_GetTicks();
  86. for (;;) {
  87. // Compute Delta Time
  88. Uint32 curr = SDL_GetTicks();
  89. float dt = (curr - prev)/1000.f;
  90. prev = curr;
  91. // Flush the events
  92. SDL_Event event;
  93. while (SDL_PollEvent(&event)) if (event.type == SDL_QUIT) return_defer(0);
  94. // Render the texture
  95. SDL_Rect window_rect = {0, 0, WIDTH, HEIGHT};
  96. uint32_t *pixels_src = render(dt);
  97. void *pixels_dst;
  98. int pitch;
  99. if (SDL_LockTexture(texture, &window_rect, &pixels_dst, &pitch) < 0) return_defer(1);
  100. for (size_t y = 0; y < HEIGHT; ++y) {
  101. memcpy(pixels_dst + y*pitch, pixels_src + y*WIDTH, WIDTH*sizeof(uint32_t));
  102. }
  103. SDL_UnlockTexture(texture);
  104. // Display the texture
  105. if (SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0) < 0) return_defer(1);
  106. if (SDL_RenderClear(renderer) < 0) return_defer(1);
  107. if (SDL_RenderCopy(renderer, texture, &window_rect, &window_rect) < 0) return_defer(1);
  108. SDL_RenderPresent(renderer);
  109. }
  110. }
  111. defer:
  112. switch (result) {
  113. case 0:
  114. printf("OK\n");
  115. break;
  116. default:
  117. fprintf(stderr, "SDL ERROR: %s\n", SDL_GetError());
  118. }
  119. if (texture) SDL_DestroyTexture(texture);
  120. if (renderer) SDL_DestroyRenderer(renderer);
  121. if (window) SDL_DestroyWindow(window);
  122. SDL_Quit();
  123. return result;
  124. }
  125. #elif PLATFORM == TERM_PLATFORM
  126. #include <assert.h>
  127. #include <stdio.h>
  128. #include <stdlib.h>
  129. #include <string.h>
  130. #include <errno.h>
  131. #include <time.h>
  132. #include <unistd.h>
  133. #define SCALE_DOWN_FACTOR 40
  134. static_assert(WIDTH%SCALE_DOWN_FACTOR == 0, "WIDTH must be divisible by the SCALE_DOWN_FACTOR");
  135. #define SCALED_DOWN_WIDTH (WIDTH/SCALE_DOWN_FACTOR)
  136. static_assert(HEIGHT%SCALE_DOWN_FACTOR == 0, "HEIGHT must be divisible by the SCALE_DOWN_FACTOR");
  137. #define SCALED_DOWN_HEIGHT (HEIGHT/SCALE_DOWN_FACTOR)
  138. char char_canvas[SCALED_DOWN_WIDTH*SCALED_DOWN_HEIGHT];
  139. char color_to_char(uint32_t pixel)
  140. {
  141. char table[] = " .:a@#";
  142. size_t n = sizeof(table) - 1;
  143. size_t r = (0x000000FF&pixel)>>(8*0);
  144. size_t g = (0x0000FF00&pixel)>>(8*1);
  145. size_t b = (0x00FF0000&pixel)>>(8*2);
  146. size_t bright = r;
  147. if (bright < g) bright = g;
  148. if (bright < b) bright = b;
  149. return table[bright*n/256];
  150. }
  151. #define OLIVEC_RED(color) (((color)&0x000000FF)>>(8*0))
  152. #define OLIVEC_GREEN(color) (((color)&0x0000FF00)>>(8*1))
  153. #define OLIVEC_BLUE(color) (((color)&0x00FF0000)>>(8*2))
  154. #define OLIVEC_ALPHA(color) (((color)&0xFF000000)>>(8*3))
  155. #define OLIVEC_RGBA(r, g, b, a) ((((r)&0xFF)<<(8*0)) | (((g)&0xFF)<<(8*1)) | (((b)&0xFF)<<(8*2)) | (((a)&0xFF)<<(8*3)))
  156. uint32_t compress_pixels_chunk(Olivec_Canvas oc)
  157. {
  158. size_t r = 0;
  159. size_t g = 0;
  160. size_t b = 0;
  161. size_t a = 0;
  162. for (size_t y = 0; y < oc.height; ++y) {
  163. for (size_t x = 0; x < oc.width; ++x) {
  164. r += OLIVEC_RED(OLIVEC_PIXEL(oc, x, y));
  165. g += OLIVEC_GREEN(OLIVEC_PIXEL(oc, x, y));
  166. b += OLIVEC_BLUE(OLIVEC_PIXEL(oc, x, y));
  167. a += OLIVEC_ALPHA(OLIVEC_PIXEL(oc, x, y));
  168. }
  169. }
  170. r /= oc.width*oc.height;
  171. g /= oc.width*oc.height;
  172. b /= oc.width*oc.height;
  173. a /= oc.width*oc.height;
  174. return OLIVEC_RGBA(r, g, b, a);
  175. }
  176. void compress_pixels(uint32_t *pixels)
  177. {
  178. Olivec_Canvas oc = olivec_canvas(pixels, WIDTH, HEIGHT);
  179. for (size_t y = 0; y < SCALED_DOWN_HEIGHT; ++y) {
  180. for (size_t x = 0; x < SCALED_DOWN_WIDTH; ++x) {
  181. Olivec_Canvas soc = olivec_subcanvas(oc, x*SCALE_DOWN_FACTOR, y*SCALE_DOWN_FACTOR, SCALE_DOWN_FACTOR,
  182. SCALE_DOWN_FACTOR);
  183. char_canvas[y*SCALED_DOWN_WIDTH + x] = color_to_char(compress_pixels_chunk(soc));
  184. }
  185. }
  186. }
  187. int main(void)
  188. {
  189. for (;;) {
  190. compress_pixels(render(1.f/60.f));
  191. for (size_t y = 0; y < SCALED_DOWN_HEIGHT; ++y) {
  192. for (size_t x = 0; x < SCALED_DOWN_WIDTH; ++x) {
  193. putc(char_canvas[y*SCALED_DOWN_WIDTH + x], stdout);
  194. putc(char_canvas[y*SCALED_DOWN_WIDTH + x], stdout);
  195. }
  196. putc('\n', stdout);
  197. }
  198. usleep(1000*1000/60);
  199. printf("\033[%dA", SCALED_DOWN_HEIGHT);
  200. printf("\033[%dD", SCALED_DOWN_WIDTH);
  201. }
  202. return 0;
  203. }
  204. #elif PLATFORM == WASM_PLATFORM
  205. // Do nothing
  206. #else
  207. #error "Unknown platform"
  208. #endif // SDL_PLATFORM