tuxanci2-engine
Game engine for tuxanci2
Log | Files | Refs | README | LICENSE

shapes.c (5165B)


      1 #include <stdint.h>
      2 #include <stdlib.h>
      3 #include <stdbool.h>
      4 #include <stddef.h>
      5 #include "display.h"
      6 
      7 typedef struct {
      8     uint32_t x;
      9     uint32_t y;
     10     uint32_t width;
     11     uint32_t height;
     12     ta_display_sprite *sprite;
     13 } ta_shape_target;
     14 
     15 static ta_shape_target target;
     16 
     17 static bool target_begin(uint32_t x, uint32_t y, uint32_t width, uint32_t height) {
     18     if (width == 0 || height == 0 || x >= ta_display->width || y >= ta_display->height) return false;
     19     if (width > ta_display->width - x) width = ta_display->width - x;
     20     if (height > ta_display->height - y) height = ta_display->height - y;
     21     target.x = x;
     22     target.y = y;
     23     target.width = width;
     24     target.height = height;
     25     target.sprite = NULL;
     26     if (ta_display->sprite_mode) {
     27         if (ta_display->bpp != 32) return false;
     28         target.sprite = ta_display_sprite_create((uint16_t)width, (uint16_t)height);
     29         if (!target.sprite) return false;
     30         target.sprite->x = (uint16_t)x;
     31         target.sprite->y = (uint16_t)y;
     32         for (size_t i = 0; i < (size_t)width * height * 4; i++) target.sprite->pixels[i] = 0;
     33     } else if (!ta_display->buffers[1] || (ta_display->bpp != 8 && ta_display->bpp != 32)) {
     34         return false;
     35     }
     36     return true;
     37 }
     38 
     39 static void target_pixel(uint32_t x, uint32_t y, uint32_t color) {
     40     if (x < target.x || y < target.y || x - target.x >= target.width || y - target.y >= target.height) return;
     41     size_t local = (size_t)(y - target.y) * target.width + (x - target.x);
     42     if (target.sprite) {
     43         ((uint32_t *)target.sprite->pixels)[local] = ((color & 0xffffffu) << 8) | 0xffu;
     44     } else {
     45         size_t index = (size_t)y * ta_display->width + x;
     46         if (ta_display->bpp == 32) {
     47             ((uint32_t *)ta_display->buffers[1])[index] = color & 0xffffffu;
     48         } else {
     49             uint32_t red = (color >> 16) & 255;
     50             uint32_t green = (color >> 8) & 255;
     51             uint32_t blue = color & 255;
     52             ((uint8_t *)ta_display->buffers[1])[index] = (uint8_t)((red & 0xe0) | ((green >> 3) & 0x1c) | (blue >> 6));
     53         }
     54     }
     55 }
     56 
     57 static void target_end(void) {
     58     if (target.sprite && !ta_display_sprite_add(target.sprite)) free(target.sprite);
     59     target.sprite = NULL;
     60 }
     61 
     62 void ta_shapes_draw_pixel(uint32_t x, uint32_t y, uint32_t color) {
     63     if (!target_begin(x, y, 1, 1)) return;
     64     target_pixel(x, y, color);
     65     target_end();
     66 }
     67 
     68 void ta_shapes_draw_rectangle(uint32_t x, uint32_t y, uint32_t width, uint32_t height, uint32_t color) {
     69     if (!target_begin(x, y, width, height)) return;
     70     uint32_t end_x = target.x + target.width;
     71     uint32_t end_y = target.y + target.height;
     72     for (uint32_t py = target.y; py < end_y; py++)
     73         for (uint32_t px = target.x; px < end_x; px++) target_pixel(px, py, color);
     74     target_end();
     75 }
     76 
     77 static int64_t edge(int32_t ax, int32_t ay, int32_t bx, int32_t by, int32_t px, int32_t py) {
     78     return ((int64_t)px - ax) * ((int64_t)by - ay) - ((int64_t)py - ay) * ((int64_t)bx - ax);
     79 }
     80 
     81 void ta_shapes_draw_triangle(uint32_t x1, uint32_t y1, uint32_t x2, uint32_t y2, uint32_t x3, uint32_t y3, uint32_t color) {
     82     uint32_t min_x = x1, max_x = x1, min_y = y1, max_y = y1;
     83     if (x2 < min_x) min_x = x2;
     84     if (x3 < min_x) min_x = x3;
     85     if (x2 > max_x) max_x = x2;
     86     if (x3 > max_x) max_x = x3;
     87     if (y2 < min_y) min_y = y2;
     88     if (y3 < min_y) min_y = y3;
     89     if (y2 > max_y) max_y = y2;
     90     if (y3 > max_y) max_y = y3;
     91     if (max_x == 0xffffffffu || max_y == 0xffffffffu) return;
     92     uint32_t width = max_x - min_x + 1, height = max_y - min_y + 1;
     93     if (!target_begin(min_x, min_y, width, height)) return;
     94     int64_t area = edge((int32_t)x1, (int32_t)y1, (int32_t)x2, (int32_t)y2, (int32_t)x3, (int32_t)y3);
     95     if (area != 0) {
     96         uint32_t end_x = target.x + target.width, end_y = target.y + target.height;
     97         for (uint32_t y = target.y; y < end_y; y++) for (uint32_t x = target.x; x < end_x; x++) {
     98             int64_t a = edge((int32_t)x1, (int32_t)y1, (int32_t)x2, (int32_t)y2, (int32_t)x, (int32_t)y);
     99             int64_t b = edge((int32_t)x2, (int32_t)y2, (int32_t)x3, (int32_t)y3, (int32_t)x, (int32_t)y);
    100             int64_t c = edge((int32_t)x3, (int32_t)y3, (int32_t)x1, (int32_t)y1, (int32_t)x, (int32_t)y);
    101             if ((area > 0 && a >= 0 && b >= 0 && c >= 0) || (area < 0 && a <= 0 && b <= 0 && c <= 0)) target_pixel(x, y, color);
    102         }
    103     }
    104     target_end();
    105 }
    106 
    107 void ta_shapes_draw_oval(uint32_t x, uint32_t y, uint32_t width, uint32_t height, uint32_t color) {
    108     if (!target_begin(x, y, width, height)) return;
    109     int64_t rx = (int64_t)width / 2;
    110     int64_t ry = (int64_t)height / 2;
    111     int64_t cx = (int64_t)x + rx;
    112     int64_t cy = (int64_t)y + ry;
    113     int64_t rx2 = rx * rx, ry2 = ry * ry;
    114     if (rx2 == 0) rx2 = 1;
    115     if (ry2 == 0) ry2 = 1;
    116     uint32_t end_x = target.x + target.width, end_y = target.y + target.height;
    117     for (uint32_t py = target.y; py < end_y; py++) for (uint32_t px = target.x; px < end_x; px++) {
    118         int64_t dx = (int64_t)px - cx, dy = (int64_t)py - cy;
    119         if (dx * dx * ry2 + dy * dy * rx2 <= rx2 * ry2) target_pixel(px, py, color);
    120     }
    121     target_end();
    122 }