sprite slice rays
This commit is contained in:
parent
a314f1b8f4
commit
6193d80983
125
src/sprite.c
125
src/sprite.c
@ -11,6 +11,7 @@
|
||||
#include "thread_local.h"
|
||||
#include "app.h"
|
||||
#include "renderer.h"
|
||||
#include "math.h"
|
||||
|
||||
#define CACHE_MEMORY_BUDGET (MEGABYTE(256))
|
||||
#define CACHE_BUCKETS_COUNT 1024
|
||||
@ -388,31 +389,36 @@ INTERNAL void cache_node_load_texture(struct cache_node *n, struct sprite_tag ta
|
||||
|
||||
INTERNAL struct sprite_sheet init_sheet_from_ase_result(struct arena *arena, struct ase_decode_sheet_result ase)
|
||||
{
|
||||
__prof;
|
||||
struct sprite_sheet sheet = { 0 };
|
||||
|
||||
ASSERT(ase.num_frames >= 1);
|
||||
|
||||
/* Init frames */
|
||||
sheet.image_size = ase.image_size;
|
||||
sheet.frame_size = ase.frame_size;
|
||||
sheet.frames = arena_push_array_zero(arena, struct sprite_sheet_frame, ase.num_frames);
|
||||
sheet.frames_count = ase.num_frames;
|
||||
for (struct ase_frame *ase_frame = ase.frame_head; ase_frame; ase_frame = ase_frame->next) {
|
||||
u32 index = ase_frame->index;
|
||||
{
|
||||
__profscope(init_frames);
|
||||
sheet.image_size = ase.image_size;
|
||||
sheet.frame_size = ase.frame_size;
|
||||
sheet.frames = arena_push_array_zero(arena, struct sprite_sheet_frame, ase.num_frames);
|
||||
sheet.frames_count = ase.num_frames;
|
||||
for (struct ase_frame *ase_frame = ase.frame_head; ase_frame; ase_frame = ase_frame->next) {
|
||||
u32 index = ase_frame->index;
|
||||
|
||||
struct v2 clip_p1 = { (f32)ase_frame->x1 / (f32)ase.image_size.x, (f32)ase_frame->y1 / (f32)ase.image_size.y };
|
||||
struct v2 clip_p2 = { (f32)ase_frame->x2 / (f32)ase.image_size.x, (f32)ase_frame->y2 / (f32)ase.image_size.y };
|
||||
struct v2 clip_p1 = { (f32)ase_frame->x1 / (f32)ase.image_size.x, (f32)ase_frame->y1 / (f32)ase.image_size.y };
|
||||
struct v2 clip_p2 = { (f32)ase_frame->x2 / (f32)ase.image_size.x, (f32)ase_frame->y2 / (f32)ase.image_size.y };
|
||||
|
||||
sheet.frames[index] = (struct sprite_sheet_frame) {
|
||||
.index = index,
|
||||
.duration = ase_frame->duration,
|
||||
.clip = (struct clip_rect) { clip_p1, clip_p2 }
|
||||
};
|
||||
sheet.frames[index] = (struct sprite_sheet_frame) {
|
||||
.index = index,
|
||||
.duration = ase_frame->duration,
|
||||
.clip = (struct clip_rect) { clip_p1, clip_p2 }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/* Init spans */
|
||||
sheet.spans_count = ase.num_spans;
|
||||
if (ase.num_spans > 0) {
|
||||
__profscope(init_spans);
|
||||
sheet.spans_dict = fixed_dict_init(arena, (u64)(ase.num_spans * SHEET_SPAN_LOOKUP_TABLE_BUCKET_RATIO));
|
||||
for (struct ase_span *ase_span = ase.span_head; ase_span; ase_span = ase_span->next) {
|
||||
struct string name = string_copy(arena, ase_span->name);
|
||||
@ -428,6 +434,7 @@ INTERNAL struct sprite_sheet init_sheet_from_ase_result(struct arena *arena, str
|
||||
|
||||
/* Init slices */
|
||||
if (ase.num_slice_keys > 0) {
|
||||
__profscope(init_slices);
|
||||
struct temp_arena scratch = scratch_begin(arena);
|
||||
|
||||
struct temp_ase_slice_key_node {
|
||||
@ -444,7 +451,7 @@ INTERNAL struct sprite_sheet init_sheet_from_ase_result(struct arena *arena, str
|
||||
struct temp_ase_slice_key_node *temp_ase_slice_key_head;
|
||||
struct temp_slice_group_node *next;
|
||||
|
||||
struct sprite_slice_group *final_slice_group;
|
||||
struct sprite_sheet_slice_group *final_slice_group;
|
||||
};
|
||||
|
||||
/* Group slices by name and find out counts per frame */
|
||||
@ -454,6 +461,7 @@ INTERNAL struct sprite_sheet init_sheet_from_ase_result(struct arena *arena, str
|
||||
struct fixed_dict temp_slice_dict = fixed_dict_init(scratch.arena, (u64)(ase.num_slice_keys * 2));
|
||||
for (struct ase_slice_key *ase_slice_key = ase.slice_key_head; ase_slice_key; ase_slice_key = ase_slice_key->next) {
|
||||
struct string name = ase_slice_key->name;
|
||||
|
||||
struct temp_slice_group_node *temp_slice_group_node = fixed_dict_get(&temp_slice_dict, name);
|
||||
if (!temp_slice_group_node) {
|
||||
temp_slice_group_node = arena_push_zero(scratch.arena, struct temp_slice_group_node);
|
||||
@ -468,7 +476,8 @@ INTERNAL struct sprite_sheet init_sheet_from_ase_result(struct arena *arena, str
|
||||
struct temp_ase_slice_key_node *node = arena_push_zero(scratch.arena, struct temp_ase_slice_key_node);
|
||||
node->key = ase_slice_key;
|
||||
node->next = temp_slice_group_node->temp_ase_slice_key_head;
|
||||
node->earliest_frame = node->key->slice_head->start; /* To be overwritten later after iterating */
|
||||
node->earliest_frame = U32_MAX; /* To be overwritten later after iterating */
|
||||
|
||||
temp_slice_group_node->temp_ase_slice_key_head = node;
|
||||
|
||||
++temp_slice_group_node->per_frame_count;
|
||||
@ -480,7 +489,7 @@ INTERNAL struct sprite_sheet init_sheet_from_ase_result(struct arena *arena, str
|
||||
sheet.slice_groups_dict = fixed_dict_init(arena, (u64)(num_temp_slice_group_nodes * SHEET_SLICE_LOOKUP_TABLE_BUCKET_RATIO));
|
||||
|
||||
for (struct temp_slice_group_node *temp_slice_group_node = temp_slice_group_head; temp_slice_group_node; temp_slice_group_node = temp_slice_group_node->next) {
|
||||
struct sprite_slice_group *slice_group = arena_push_zero(arena, struct sprite_slice_group);
|
||||
struct sprite_sheet_slice_group *slice_group = arena_push_zero(arena, struct sprite_sheet_slice_group);
|
||||
slice_group->name = string_copy(arena, temp_slice_group_node->name);
|
||||
slice_group->per_frame_count = temp_slice_group_node->per_frame_count;
|
||||
|
||||
@ -502,7 +511,9 @@ INTERNAL struct sprite_sheet init_sheet_from_ase_result(struct arena *arena, str
|
||||
f32 x2 = ase_slice->x2;
|
||||
f32 y2 = ase_slice->y2;
|
||||
|
||||
slice->center = V2(x1 + ((x2 - x1) / 2.f), y1 + ((y2 - y1) / 2.f));
|
||||
struct v2 center = V2(x1 + ((x2 - x1) / 2.f), y1 + ((y2 - y1) / 2.f));
|
||||
slice->center = center;
|
||||
slice->dir = V2(0, -1);
|
||||
|
||||
node->index_in_frame = index_in_frame;
|
||||
if (start < node->earliest_frame) {
|
||||
@ -519,7 +530,7 @@ INTERNAL struct sprite_sheet init_sheet_from_ase_result(struct arena *arena, str
|
||||
|
||||
/* Propogate original slices into next frames (and first slices into previous frames) */
|
||||
for (struct temp_slice_group_node *temp_slice_group_node = temp_slice_group_head; temp_slice_group_node; temp_slice_group_node = temp_slice_group_node->next) {
|
||||
struct sprite_slice_group *slice_group = temp_slice_group_node->final_slice_group;
|
||||
struct sprite_sheet_slice_group *slice_group = temp_slice_group_node->final_slice_group;
|
||||
|
||||
for (struct temp_ase_slice_key_node *node = temp_slice_group_node->temp_ase_slice_key_head; node; node = node->next) {
|
||||
struct ase_slice_key *key = node->key;
|
||||
@ -552,6 +563,36 @@ INTERNAL struct sprite_sheet init_sheet_from_ase_result(struct arena *arena, str
|
||||
}
|
||||
}
|
||||
|
||||
/* Calculate rays */
|
||||
for (struct temp_slice_group_node *temp_slice_group_node = temp_slice_group_head; temp_slice_group_node; temp_slice_group_node = temp_slice_group_node->next) {
|
||||
struct string ray_suffix = STR(".ray");
|
||||
|
||||
struct sprite_sheet_slice_group *ray_slice_group = temp_slice_group_node->final_slice_group;
|
||||
struct string ray_slice_name = ray_slice_group->name;
|
||||
if (string_ends_with(ray_slice_name, ray_suffix)) {
|
||||
struct string point_slice_name = ray_slice_name;
|
||||
point_slice_name.len -= ray_suffix.len;
|
||||
|
||||
struct sprite_sheet_slice_group *point_slice_group = fixed_dict_get(&sheet.slice_groups_dict, point_slice_name);
|
||||
if (point_slice_group) {
|
||||
u32 point_slices_per_frame = point_slice_group->per_frame_count;
|
||||
|
||||
for (u32 i = 0; i < ase.num_frames; ++i) {
|
||||
/* Use ray slice in ray group */
|
||||
struct sprite_sheet_slice *ray_slice = &ray_slice_group->frame_slices[i * point_slices_per_frame];
|
||||
struct v2 ray_end = ray_slice->center;
|
||||
|
||||
/* Apply to each point slice in point group */
|
||||
for (u32 j = 0; j < point_slices_per_frame; ++j) {
|
||||
struct sprite_sheet_slice *point_slice = &point_slice_group->frame_slices[(i * point_slices_per_frame) + j];
|
||||
point_slice->dir = v2_sub(ray_end, point_slice->center);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
@ -857,6 +898,22 @@ struct sprite_sheet *sprite_sheet_from_tag_async(struct sprite_scope *scope, str
|
||||
return (struct sprite_sheet *)data_from_tag_internal(scope, tag, CACHE_NODE_KIND_SHEET, false);
|
||||
}
|
||||
|
||||
struct sprite_sheet_frame sprite_sheet_get_frame(struct sprite_sheet *sheet, u32 index)
|
||||
{
|
||||
__prof;
|
||||
if (sheet->frames_count > 0) {
|
||||
index = min_u32(sheet->frames_count - 1, index);
|
||||
return sheet->frames[index];
|
||||
} else {
|
||||
return (struct sprite_sheet_frame)
|
||||
{
|
||||
.index = 0,
|
||||
.duration = 0.1,
|
||||
.clip = CLIP_ALL
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
struct sprite_sheet_span sprite_sheet_get_span(struct sprite_sheet *sheet, struct string name)
|
||||
{
|
||||
__prof;
|
||||
@ -870,19 +927,29 @@ struct sprite_sheet_span sprite_sheet_get_span(struct sprite_sheet *sheet, struc
|
||||
return res;
|
||||
}
|
||||
|
||||
struct sprite_sheet_frame sprite_sheet_get_frame(struct sprite_sheet *sheet, u32 index)
|
||||
struct sprite_sheet_slice sprite_sheet_get_slice(struct sprite_sheet *sheet, struct string name, u32 frame_index)
|
||||
{
|
||||
__prof;
|
||||
if (sheet->frames_count > 0) {
|
||||
index = min_u32(sheet->frames_count - 1, index);
|
||||
return sheet->frames[index];
|
||||
} else {
|
||||
return (struct sprite_sheet_frame) {
|
||||
.index = 0,
|
||||
.duration = 0.1,
|
||||
.clip = CLIP_ALL
|
||||
};
|
||||
struct sprite_sheet_slice res = { 0 };
|
||||
|
||||
struct sprite_sheet_slice_group *group = fixed_dict_get(&sheet->slice_groups_dict, name);
|
||||
if (group) {
|
||||
res = group->frame_slices[frame_index * group->per_frame_count];
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
struct sprite_sheet_slice_array sprite_sheet_get_slices(struct sprite_sheet *sheet, struct string name, u32 frame_index)
|
||||
{
|
||||
struct sprite_sheet_slice_array res = { 0 };
|
||||
|
||||
struct sprite_sheet_slice_group *group = fixed_dict_get(&sheet->slice_groups_dict, name);
|
||||
if (group) {
|
||||
res.count = group->per_frame_count;
|
||||
res.slices = &group->frame_slices[frame_index * group->per_frame_count];
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
|
||||
56
src/sprite.h
56
src/sprite.h
@ -35,7 +35,7 @@ struct sprite_scope *sprite_scope_begin(void);
|
||||
void sprite_scope_end(struct sprite_scope *scope);
|
||||
|
||||
/* ========================== *
|
||||
* Texture
|
||||
* Texture load
|
||||
* ========================== */
|
||||
|
||||
struct sprite_texture {
|
||||
@ -50,7 +50,7 @@ struct sprite_texture *sprite_texture_from_tag_await(struct sprite_scope *scope,
|
||||
struct sprite_texture *sprite_texture_from_tag_async(struct sprite_scope *scope, struct sprite_tag tag);
|
||||
|
||||
/* ========================== *
|
||||
* Sheet
|
||||
* Sheet load
|
||||
* ========================== */
|
||||
|
||||
struct sprite_sheet {
|
||||
@ -66,15 +66,17 @@ struct sprite_sheet {
|
||||
struct fixed_dict slice_groups_dict;
|
||||
};
|
||||
|
||||
struct sprite_sheet_slice {
|
||||
b32 original;
|
||||
struct v2 center;
|
||||
};
|
||||
struct sprite_sheet *sprite_sheet_from_tag_await(struct sprite_scope *scope, struct sprite_tag tag);
|
||||
struct sprite_sheet *sprite_sheet_from_tag_async(struct sprite_scope *scope, struct sprite_tag tag);
|
||||
|
||||
struct sprite_slice_group {
|
||||
struct string name;
|
||||
u64 per_frame_count;
|
||||
struct sprite_sheet_slice *frame_slices; /* 2d array of slices with length (num frames) * (num slices per frame). Index with [(frame index * per frame count) + slice index in frame] */
|
||||
/* ========================== *
|
||||
* Sheet query
|
||||
* ========================== */
|
||||
|
||||
struct sprite_sheet_frame {
|
||||
u32 index;
|
||||
f64 duration;
|
||||
struct clip_rect clip;
|
||||
};
|
||||
|
||||
struct sprite_sheet_span {
|
||||
@ -83,18 +85,34 @@ struct sprite_sheet_span {
|
||||
u32 end;
|
||||
};
|
||||
|
||||
struct sprite_sheet_frame {
|
||||
u32 index;
|
||||
f64 duration;
|
||||
struct clip_rect clip;
|
||||
struct sprite_sheet_slice {
|
||||
b32 original;
|
||||
struct v2 center;
|
||||
struct v2 dir;
|
||||
};
|
||||
|
||||
/* Load */
|
||||
struct sprite_sheet *sprite_sheet_from_tag_await(struct sprite_scope *scope, struct sprite_tag tag);
|
||||
struct sprite_sheet *sprite_sheet_from_tag_async(struct sprite_scope *scope, struct sprite_tag tag);
|
||||
struct sprite_sheet_slice_array {
|
||||
u64 count;
|
||||
struct sprite_sheet_slice *slices;
|
||||
};
|
||||
|
||||
struct sprite_sheet_slice_group {
|
||||
struct string name;
|
||||
u64 per_frame_count;
|
||||
|
||||
/* 2d array of slices with length (num frames) * (num slices per frame).
|
||||
* Index with [(frame index * num slices per frame) + slice index in frame] */
|
||||
struct sprite_sheet_slice *frame_slices;
|
||||
};
|
||||
|
||||
/* Index */
|
||||
struct sprite_sheet_span sprite_sheet_get_span(struct sprite_sheet *sheet, struct string name);
|
||||
struct sprite_sheet_frame sprite_sheet_get_frame(struct sprite_sheet *sheet, u32 index);
|
||||
|
||||
struct sprite_sheet_span sprite_sheet_get_span(struct sprite_sheet *sheet, struct string name);
|
||||
|
||||
/* Returns first slice with name in frame */
|
||||
struct sprite_sheet_slice sprite_sheet_get_slice(struct sprite_sheet *sheet, struct string name, u32 frame_index);
|
||||
|
||||
/* Returns all slices with name in frame */
|
||||
struct sprite_sheet_slice_array sprite_sheet_get_slices(struct sprite_sheet *sheet, struct string name, u32 frame_index);
|
||||
|
||||
#endif
|
||||
|
||||
101
src/user.c
101
src/user.c
@ -758,7 +758,6 @@ INTERNAL void user_update(void)
|
||||
|
||||
/* Draw sprite */
|
||||
if (!sprite_tag_is_nil(ent->sprite)) {
|
||||
#if 1
|
||||
struct sprite_tag sprite = ent->sprite;
|
||||
|
||||
/* Async load */
|
||||
@ -789,61 +788,35 @@ INTERNAL void user_update(void)
|
||||
|
||||
struct quad quad;
|
||||
{
|
||||
#if 1
|
||||
struct xform sprite_xf = XFORM_IDENT;
|
||||
{
|
||||
struct v2 sprite_size_meters = V2(
|
||||
sheet->frame_size.x / (f32)PIXELS_PER_UNIT,
|
||||
sheet->frame_size.y / (f32)PIXELS_PER_UNIT
|
||||
);
|
||||
struct v2 sprite_size_meters = v2_div(sheet->frame_size, (f32)PIXELS_PER_UNIT);
|
||||
|
||||
#if 1
|
||||
/* TODO: Cache these in slice */
|
||||
struct v2 pivot_pos;
|
||||
f32 pivot_rot;
|
||||
{
|
||||
struct v2 pivot_pos_norm = V2(0, 0); /* Pivot x & y are each normalized about sprite dimensions. <0, 0> is center, <1, 1> is bottom right corner, etc. */
|
||||
struct v2 half_size = v2_mul(sprite_size_meters, 0.5f);
|
||||
pivot_pos = v2_mul_v2(pivot_pos_norm, half_size);
|
||||
struct sprite_sheet_slice pivot_slice = sprite_sheet_get_slice(sheet, STR("pivot"), frame.index);
|
||||
|
||||
/* Pivot pos */
|
||||
struct v2 pivot_pos_norm = pivot_slice.center;
|
||||
pivot_pos_norm = v2_mul(pivot_pos_norm, 2);
|
||||
pivot_pos_norm = v2_sub(pivot_pos_norm, sheet->frame_size);
|
||||
pivot_pos_norm = v2_div_v2(pivot_pos_norm, sheet->frame_size);
|
||||
pivot_pos = v2_mul_v2(pivot_pos_norm, v2_mul(sprite_size_meters, 0.5f));
|
||||
|
||||
/* Pivot rot */
|
||||
pivot_rot = -v2_angle(pivot_slice.dir) - (TAU / 4.0f);
|
||||
}
|
||||
|
||||
/* Pivot */
|
||||
/* Apply Pivot */
|
||||
sprite_xf = xform_rotate(sprite_xf, pivot_rot);
|
||||
sprite_xf = xform_translate(sprite_xf, v2_neg(pivot_pos));
|
||||
sprite_xf = xform_scale(sprite_xf, sprite_size_meters);
|
||||
#else
|
||||
struct sprite_sheet_slice pivot_slice = sprite_sheet_get_slice(STR("pivot"), frame.index);
|
||||
struct v2 pivot_pos_norm = pivot_slice.center_norm;
|
||||
f32 pivot_rot = pivot_slice.rot;
|
||||
|
||||
/* Pivot */
|
||||
sprite_xf = xform_rotate(sprite_xf, pivot_rot);
|
||||
sprite_xf = xform_translate(sprite_xf, v2_neg(pivot_pos_norm));
|
||||
sprite_xf = xform_scale(sprite_xf, sprite_size_meters);
|
||||
#endif
|
||||
|
||||
/* Apply entity xform to sprite xform */
|
||||
/* Apply entity sprite xform */
|
||||
sprite_xf = xform_mul(sprite_xf, ent->sprite_quad_xform);
|
||||
}
|
||||
#else
|
||||
|
||||
struct v2 sprite_pos = V2(0, 0);
|
||||
f32 sprite_rot = 0;
|
||||
struct v2 sprite_size = V2(0.5f, 0.5f);
|
||||
// struct v2 sprite_size = sprite_sheet_size_meters(sprite_sheet_tag);
|
||||
|
||||
struct v2 sprite_pivot;
|
||||
{
|
||||
struct v2 sprite_pivot_norm = V2(0, 0); /* Pivot x & y are each normalized about sprite dimensions. <0, 0> is center, <1, 1> is bottom right corner, etc. */
|
||||
struct v2 half_size = v2_mul(sprite_size, 0.5f);
|
||||
sprite_pivot = v2_mul_v2(sprite_pivot_norm, half_size);
|
||||
}
|
||||
|
||||
struct xform sprite_xf = XFORM_POS(sprite_pos);
|
||||
sprite_xf = xform_rotate(sprite_xf, sprite_rot);
|
||||
sprite_xf = xform_translate(sprite_xf, v2_neg(sprite_pivot));
|
||||
sprite_xf = xform_scale(sprite_xf, sprite_size);
|
||||
|
||||
struct xform xf = { 0 };
|
||||
xf = xform_mul(ent->world_xform, sprite_xf);
|
||||
#endif
|
||||
|
||||
quad = quad_mul_xform(QUAD_UNIT_SQUARE_CENTERED, xform_mul(ent->world_xform, sprite_xf));
|
||||
}
|
||||
@ -852,46 +825,6 @@ INTERNAL void user_update(void)
|
||||
struct draw_sprite_params params = DRAW_SPRITE_PARAMS(.sprite = sprite, .tint = ent->sprite_tint, .clip = frame.clip);
|
||||
draw_sprite_quad(G.world_canvas, params, quad);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#else
|
||||
/* Draw texture */
|
||||
struct sprite_tag sprite = ent->sprite;
|
||||
|
||||
struct xform xf = xform_mul(ent->world_xform, ent->sprite_quad_xform);
|
||||
struct quad quad = quad_mul_xform(QUAD_UNIT_SQUARE_CENTERED, xf);
|
||||
|
||||
u32 tint = ent->sprite_tint;
|
||||
|
||||
struct sprite_sheet *sheet = sprite_sheet_from_tag_async(sprite_frame_scope, sprite);
|
||||
struct sprite_sheet_frame frame = { 0 };
|
||||
{
|
||||
struct sprite_sheet_span span = sprite_sheet_get_span(sheet, ent->sprite_span_name);
|
||||
u64 frame_index = span.start + ent->animation_frame;
|
||||
frame = sprite_sheet_get_frame(sheet, frame_index);
|
||||
if (entity_has_prop(ent, ENTITY_PROP_ANIMATING)) {
|
||||
f64 time_in_frame = ent->animation_time_in_frame;
|
||||
while (time_in_frame > frame.duration) {
|
||||
time_in_frame -= frame.duration;
|
||||
++frame_index;
|
||||
if (frame_index > span.end) {
|
||||
/* Loop animation */
|
||||
frame_index = span.start;
|
||||
}
|
||||
frame = sprite_sheet_get_frame(sheet, frame_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct draw_sprite_params params = DRAW_SPRITE_PARAMS(.sprite = sprite, .tint = tint, .clip = frame.clip);
|
||||
|
||||
/* TODO: Fade in a placeholder or something instead of drawing nothing. */
|
||||
struct sprite_texture *texture = sprite_texture_from_tag_async(sprite_frame_scope, sprite);
|
||||
if (sheet->loaded && texture->loaded) {
|
||||
draw_sprite_quad(G.world_canvas, params, quad);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Debug draw info */
|
||||
|
||||
Loading…
Reference in New Issue
Block a user