123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248 |
- // This example renders a rotating triangle.
- // This idea is that you can take this code and compile it to different platforms with different rendering machanisms:
- // native with SDL, WebAssembly with HTML5 canvas, etc.
- #define OLIVEC_IMPLEMENTATION
- #include "olive.c"
- #define WIDTH 800
- #define HEIGHT 600
- #define BACKGROUND_COLOR 0xFF181818
- #define CIRCLE_RADIUS 100
- #define CIRCLE_COLOR 0x99AA2020
- static uint32_t pixels[WIDTH*HEIGHT];
- static float triangle_angle = 0;
- static float circle_x = WIDTH/2;
- static float circle_y = HEIGHT/2;
- static float circle_dx = 100;
- static float circle_dy = 100;
- float sqrtf(float x);
- float atan2f(float y, float x);
- float sinf(float x);
- float cosf(float x);
- #define PI 3.14159265359
- static inline void rotate_point(float *x, float *y)
- {
- float dx = *x - WIDTH/2;
- float dy = *y - HEIGHT/2;
- float mag = sqrtf(dx*dx + dy*dy);
- float dir = atan2f(dy, dx) + triangle_angle;
- *x = cosf(dir)*mag + WIDTH/2;
- *y = sinf(dir)*mag + HEIGHT/2;
- }
- uint32_t *render(float dt)
- {
- Olivec_Canvas oc = olivec_canvas(pixels, WIDTH, HEIGHT);
- olivec_fill(oc, BACKGROUND_COLOR);
- // Triangle
- {
- triangle_angle += 0.5f*PI*dt;
- float x1 = WIDTH/2, y1 = HEIGHT/8;
- float x2 = WIDTH/8, y2 = HEIGHT/2;
- float x3 = WIDTH*7/8, y3 = HEIGHT*7/8;
- rotate_point(&x1, &y1);
- rotate_point(&x2, &y2);
- rotate_point(&x3, &y3);
- olivec_triangle(oc, x1, y1, x2, y2, x3, y3, 0xFF2020AA);
- }
- // Circle
- {
- float x = circle_x + circle_dx*dt;
- if (x - CIRCLE_RADIUS < 0 || x + CIRCLE_RADIUS >= WIDTH) {
- circle_dx *= -1;
- } else {
- circle_x = x;
- }
- float y = circle_y + circle_dy*dt;
- if (y - CIRCLE_RADIUS < 0 || y + CIRCLE_RADIUS >= HEIGHT) {
- circle_dy *= -1;
- } else {
- circle_y = y;
- }
- olivec_circle(oc, circle_x, circle_y, CIRCLE_RADIUS, CIRCLE_COLOR);
- }
- return pixels;
- }
- #define WASM_PLATFORM 0
- #define SDL_PLATFORM 1
- #define TERM_PLATFORM 2
- #if PLATFORM == SDL_PLATFORM
- #include <stdio.h>
- #include <SDL2/SDL.h>
- #define return_defer(value) do { result = (value); goto defer; } while (0)
- int main(void)
- {
- int result = 0;
- SDL_Window *window = NULL;
- SDL_Renderer *renderer = NULL;
- SDL_Texture *texture = NULL;
- {
- if (SDL_Init(SDL_INIT_VIDEO) < 0) return_defer(1);
- window = SDL_CreateWindow("Olivec", 0, 0, WIDTH, HEIGHT, 0);
- if (window == NULL) return_defer(1);
- renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
- if (renderer == NULL) return_defer(1);
- texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_STREAMING, WIDTH, HEIGHT);
- if (texture == NULL) return_defer(1);
- Uint32 prev = SDL_GetTicks();
- for (;;) {
- // Compute Delta Time
- Uint32 curr = SDL_GetTicks();
- float dt = (curr - prev)/1000.f;
- prev = curr;
- // Flush the events
- SDL_Event event;
- while (SDL_PollEvent(&event)) if (event.type == SDL_QUIT) return_defer(0);
- // Render the texture
- SDL_Rect window_rect = {0, 0, WIDTH, HEIGHT};
- uint32_t *pixels_src = render(dt);
- void *pixels_dst;
- int pitch;
- if (SDL_LockTexture(texture, &window_rect, &pixels_dst, &pitch) < 0) return_defer(1);
- for (size_t y = 0; y < HEIGHT; ++y) {
- memcpy(pixels_dst + y*pitch, pixels_src + y*WIDTH, WIDTH*sizeof(uint32_t));
- }
- SDL_UnlockTexture(texture);
- // Display the texture
- if (SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0) < 0) return_defer(1);
- if (SDL_RenderClear(renderer) < 0) return_defer(1);
- if (SDL_RenderCopy(renderer, texture, &window_rect, &window_rect) < 0) return_defer(1);
- SDL_RenderPresent(renderer);
- }
- }
- defer:
- switch (result) {
- case 0:
- printf("OK\n");
- break;
- default:
- fprintf(stderr, "SDL ERROR: %s\n", SDL_GetError());
- }
- if (texture) SDL_DestroyTexture(texture);
- if (renderer) SDL_DestroyRenderer(renderer);
- if (window) SDL_DestroyWindow(window);
- SDL_Quit();
- return result;
- }
- #elif PLATFORM == TERM_PLATFORM
- #include <assert.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <errno.h>
- #include <time.h>
- #include <unistd.h>
- #define SCALE_DOWN_FACTOR 40
- static_assert(WIDTH%SCALE_DOWN_FACTOR == 0, "WIDTH must be divisible by the SCALE_DOWN_FACTOR");
- #define SCALED_DOWN_WIDTH (WIDTH/SCALE_DOWN_FACTOR)
- static_assert(HEIGHT%SCALE_DOWN_FACTOR == 0, "HEIGHT must be divisible by the SCALE_DOWN_FACTOR");
- #define SCALED_DOWN_HEIGHT (HEIGHT/SCALE_DOWN_FACTOR)
- char char_canvas[SCALED_DOWN_WIDTH*SCALED_DOWN_HEIGHT];
- char color_to_char(uint32_t pixel)
- {
- char table[] = " .:a@#";
- size_t n = sizeof(table) - 1;
- size_t r = (0x000000FF&pixel)>>(8*0);
- size_t g = (0x0000FF00&pixel)>>(8*1);
- size_t b = (0x00FF0000&pixel)>>(8*2);
- size_t bright = r;
- if (bright < g) bright = g;
- if (bright < b) bright = b;
- return table[bright*n/256];
- }
- #define OLIVEC_RED(color) (((color)&0x000000FF)>>(8*0))
- #define OLIVEC_GREEN(color) (((color)&0x0000FF00)>>(8*1))
- #define OLIVEC_BLUE(color) (((color)&0x00FF0000)>>(8*2))
- #define OLIVEC_ALPHA(color) (((color)&0xFF000000)>>(8*3))
- #define OLIVEC_RGBA(r, g, b, a) ((((r)&0xFF)<<(8*0)) | (((g)&0xFF)<<(8*1)) | (((b)&0xFF)<<(8*2)) | (((a)&0xFF)<<(8*3)))
- uint32_t compress_pixels_chunk(Olivec_Canvas oc)
- {
- size_t r = 0;
- size_t g = 0;
- size_t b = 0;
- size_t a = 0;
- for (size_t y = 0; y < oc.height; ++y) {
- for (size_t x = 0; x < oc.width; ++x) {
- r += OLIVEC_RED(OLIVEC_PIXEL(oc, x, y));
- g += OLIVEC_GREEN(OLIVEC_PIXEL(oc, x, y));
- b += OLIVEC_BLUE(OLIVEC_PIXEL(oc, x, y));
- a += OLIVEC_ALPHA(OLIVEC_PIXEL(oc, x, y));
- }
- }
- r /= oc.width*oc.height;
- g /= oc.width*oc.height;
- b /= oc.width*oc.height;
- a /= oc.width*oc.height;
- return OLIVEC_RGBA(r, g, b, a);
- }
- void compress_pixels(uint32_t *pixels)
- {
- Olivec_Canvas oc = olivec_canvas(pixels, WIDTH, HEIGHT);
- for (size_t y = 0; y < SCALED_DOWN_HEIGHT; ++y) {
- for (size_t x = 0; x < SCALED_DOWN_WIDTH; ++x) {
- Olivec_Canvas soc = olivec_subcanvas(oc, x*SCALE_DOWN_FACTOR, y*SCALE_DOWN_FACTOR, SCALE_DOWN_FACTOR,
- SCALE_DOWN_FACTOR);
- char_canvas[y*SCALED_DOWN_WIDTH + x] = color_to_char(compress_pixels_chunk(soc));
- }
- }
- }
- int main(void)
- {
- for (;;) {
- compress_pixels(render(1.f/60.f));
- for (size_t y = 0; y < SCALED_DOWN_HEIGHT; ++y) {
- for (size_t x = 0; x < SCALED_DOWN_WIDTH; ++x) {
- putc(char_canvas[y*SCALED_DOWN_WIDTH + x], stdout);
- putc(char_canvas[y*SCALED_DOWN_WIDTH + x], stdout);
- }
- putc('\n', stdout);
- }
- usleep(1000*1000/60);
- printf("\033[%dA", SCALED_DOWN_HEIGHT);
- printf("\033[%dD", SCALED_DOWN_WIDTH);
- }
- return 0;
- }
- #elif PLATFORM == WASM_PLATFORM
- // Do nothing
- #else
- #error "Unknown platform"
- #endif // SDL_PLATFORM
|