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

scene.c (5093B)


      1 #include <stdint.h>
      2 #include <stdlib.h>
      3 #include <stddef.h>
      4 #include <stdbool.h>
      5 #include "fixed.h"
      6 #include "fb.h"
      7 #include "image.h"
      8 #include "text.h"
      9 #include "shapes.h"
     10 
     11 typedef struct {
     12 	const uint8_t *data;
     13 	ta_text *text;
     14 	uint32_t length;
     15 	uint32_t x;
     16 	uint32_t y;
     17 	uint32_t width;
     18 	uint32_t height;
     19 	uint16_t frame;
     20 	uint32_t shape_type;
     21 	uint32_t shape_args[6];
     22 	uint32_t color;
     23 	uint8_t sprites_after;
     24 } ta_scene_op;
     25 
     26 static ta_scene_op *ops[2];
     27 static size_t counts[2];
     28 static size_t capacities[2];
     29 static uint8_t current;
     30 static bool valid;
     31 static uint16_t last_width;
     32 static uint16_t last_height;
     33 static uint8_t last_bpp;
     34 
     35 static bool same(const ta_scene_op *a, const ta_scene_op *b) {
     36 	return a->data == b->data
     37 		&& a->text == b->text
     38 		&& a->length == b->length
     39 		&& a->x == b->x
     40 		&& a->y == b->y
     41 		&& a->width == b->width
     42 		&& a->height == b->height
     43 		&& a->frame == b->frame
     44 		&& a->shape_type == b->shape_type
     45 		&& a->color == b->color
     46 		&& a->shape_args[0] == b->shape_args[0]
     47 		&& a->shape_args[1] == b->shape_args[1]
     48 		&& a->shape_args[2] == b->shape_args[2]
     49 		&& a->shape_args[3] == b->shape_args[3]
     50 		&& a->shape_args[4] == b->shape_args[4]
     51 		&& a->shape_args[5] == b->shape_args[5];
     52 }
     53 
     54 static ta_scene_op *push(void) {
     55 	if (counts[current] == capacities[current]) {
     56 		size_t new_capacity = capacities[current] + 1;
     57 		ta_scene_op *grown = (ta_scene_op *)malloc(new_capacity * sizeof(ta_scene_op));
     58 
     59 		if (grown == NULL) {
     60 			return NULL;
     61 		}
     62 
     63 		for (size_t i = 0; i < counts[current]; i++) {
     64 			grown[i] = ops[current][i];
     65 		}
     66 
     67 		free(ops[current]);
     68 
     69 		ops[current] = grown;
     70 		capacities[current] = new_capacity;
     71 	}
     72 
     73 	ta_scene_op *op = &ops[current][counts[current]++];
     74 
     75 	op->data = NULL;
     76 	op->text = NULL;
     77 	op->length = 0;
     78 	op->x = 0;
     79 	op->y = 0;
     80 	op->width = 0;
     81 	op->height = 0;
     82 	op->frame = 0;
     83 	op->shape_type = 0;
     84     
     85     for (uint32_t i = 0; i < 6; i++) {
     86         op->shape_args[i] = 0;
     87     }
     88 
     89     op->color = 0;
     90 	op->sprites_after = 0;
     91 
     92 	return op;
     93 }
     94 
     95 static void sprites_trim(uint8_t count) {
     96 	while (ta_display_sprites && ta_display_sprites->count > count) {
     97 		ta_display_sprite_free(ta_display_sprites->sprites[ta_display_sprites->count - 1]);
     98 	}
     99 }
    100 
    101 void ta_scene_invalidate(void) {
    102 	valid = false;
    103 }
    104 
    105 void ta_scene_begin(void) {
    106 	counts[current] = 0;
    107 
    108 	if (ta_display->width != last_width || ta_display->height != last_height || ta_display->bpp != last_bpp) {
    109 		last_width = ta_display->width;
    110 		last_height = ta_display->height;
    111 		last_bpp = ta_display->bpp;
    112 		valid = false;
    113 	}
    114 }
    115 
    116 bool ta_scene_image(const uint8_t *data, uint32_t length, ta_fixed x, ta_fixed y, ta_fixed width, ta_fixed height, uint16_t frame) {
    117 	ta_scene_op *op = push();
    118 
    119 	if (op == NULL) {
    120 		return false;
    121 	}
    122 
    123 	op->data = data;
    124 	op->length = length;
    125 	op->x = x;
    126 	op->y = y;
    127 	op->width = width;
    128 	op->height = height;
    129 	op->frame = frame;
    130 
    131 	return true;
    132 }
    133 
    134 bool ta_scene_shape(uint32_t type, const uint32_t *args, uint32_t color) {
    135 	ta_scene_op *op = push();
    136 	
    137     if (op == NULL || args == NULL || type < 1 || type > 4) {
    138         return false;
    139     }
    140 	
    141     op->shape_type = type;
    142 	op->color = color;
    143 	
    144     for (uint32_t i = 0; i < 6; i++) {
    145         op->shape_args[i] = args[i];
    146     }
    147 
    148     return true;
    149 }
    150 
    151 bool ta_scene_text(ta_text *text, uint32_t x, uint32_t y) {
    152 	ta_scene_op *op = push();
    153 
    154 	if (op == NULL) {
    155 		return false;
    156 	}
    157 
    158 	op->text = text;
    159 	op->color = ((uint32_t)text->red << 16) | ((uint32_t)text->green << 8) | text->blue;
    160 	op->x = x;
    161 	op->y = y;
    162 
    163 	return true;
    164 }
    165 
    166 bool ta_scene_end(void) {
    167 	ta_scene_op *now = ops[current];
    168 	ta_scene_op *before = ops[current ^ 1];
    169 	size_t now_count = counts[current];
    170 	size_t before_count = counts[current ^ 1];
    171 	size_t prefix = 0;
    172 
    173 	if (valid) {
    174 		while (prefix < now_count && prefix < before_count && same(&now[prefix], &before[prefix])) {
    175 			prefix++;
    176 		}
    177 
    178 		if (prefix == now_count && prefix == before_count) {
    179             return false;
    180 		}
    181 	}
    182 
    183 	size_t start = ta_display->sprite_mode ? prefix : 0;
    184 
    185 	if (start == 0) {
    186 		ta_fb_clear(ta_display);
    187 	} else {
    188 		sprites_trim(before[start - 1].sprites_after);
    189 
    190 		for (size_t i = 0; i < start; i++) {
    191 			now[i].sprites_after = before[i].sprites_after;
    192 		}
    193 	}
    194 
    195 	for (size_t i = start; i < now_count; i++) {
    196 		ta_scene_op *op = &now[i];
    197 
    198 		if (op->shape_type != 0) {
    199 			uint32_t *a = op->shape_args;
    200 			if (op->shape_type == 1) {
    201                 ta_shapes_draw_pixel(a[0], a[1], op->color);
    202             } else if (op->shape_type == 2) {
    203                 ta_shapes_draw_rectangle(a[0], a[1], a[2], a[3], op->color);
    204             } else if (op->shape_type == 3) {
    205                 ta_shapes_draw_triangle(a[0], a[1], a[2], a[3], a[4], a[5], op->color);
    206             } else {
    207                 ta_shapes_draw_oval(a[0], a[1], a[2], a[3], op->color);
    208             }
    209 		} else if (op->text != NULL) {
    210 			op->text->x = op->x;
    211 			op->text->y = op->y;
    212 			ta_text_draw(op->text);
    213 		} else {
    214 			ta_image_draw(op->data, op->length, op->x, op->y, op->width, op->height, op->frame);
    215 		}
    216 
    217 		op->sprites_after = ta_display_sprites ? ta_display_sprites->count : 0;
    218 	}
    219 
    220 	valid = true;
    221 	current ^= 1;
    222 
    223 	return true;
    224 }