mirror of
https://github.com/xtreme8000/CavEX.git
synced 2025-01-22 09:11:55 -05:00
Add particles for block breaking/hits
This commit is contained in:
parent
448c96d812
commit
b9d7cb7fe2
16 changed files with 412 additions and 4 deletions
|
@ -124,6 +124,7 @@ add_executable(cavex
|
|||
source/util.c
|
||||
source/world.c
|
||||
source/config.c
|
||||
source/particle.c
|
||||
|
||||
source/lodepng/lodepng.c
|
||||
|
||||
|
|
|
@ -107,3 +107,8 @@ bool aabb_intersection(struct AABB* a, struct AABB* b) {
|
|||
&& (a->y1 <= b->y2 && b->y1 <= a->y2)
|
||||
&& (a->z1 <= b->z2 && b->z1 <= a->z2);
|
||||
}
|
||||
|
||||
bool aabb_intersection_point(struct AABB* a, float x, float y, float z) {
|
||||
return (x >= a->x1 && x <= a->x2) && (y >= a->y1 && y <= a->y2)
|
||||
&& (z >= a->z1 && z <= a->z2);
|
||||
}
|
||||
|
|
|
@ -39,5 +39,6 @@ void aabb_setsize_centered(struct AABB* a, float sx, float sy, float sz);
|
|||
void aabb_translate(struct AABB* a, float x, float y, float z);
|
||||
bool aabb_intersection_ray(struct AABB* a, struct ray* r, enum side* s);
|
||||
bool aabb_intersection(struct AABB* a, struct AABB* b);
|
||||
bool aabb_intersection_point(struct AABB* a, float x, float y, float z);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "../../graphics/gui_util.h"
|
||||
#include "../../graphics/render_model.h"
|
||||
#include "../../network/server_interface.h"
|
||||
#include "../../particle.h"
|
||||
#include "../../platform/gfx.h"
|
||||
#include "../../platform/input.h"
|
||||
#include "../game_state.h"
|
||||
|
@ -225,6 +226,31 @@ static void screen_ingame_update(struct screen* s, float dt) {
|
|||
>= 0.2F) {
|
||||
gstate.held_item_animation.punch.start = time_get();
|
||||
gstate.held_item_animation.punch.place = false;
|
||||
|
||||
if(gstate.camera_hit.hit) {
|
||||
struct block_data blk
|
||||
= world_get_block(&gstate.world, gstate.camera_hit.x,
|
||||
gstate.camera_hit.y, gstate.camera_hit.z);
|
||||
|
||||
struct block_data neighbours[6];
|
||||
|
||||
for(int k = 0; k < SIDE_MAX; k++) {
|
||||
int ox, oy, oz;
|
||||
blocks_side_offset((enum side)k, &ox, &oy, &oz);
|
||||
|
||||
neighbours[k] = world_get_block(
|
||||
&gstate.world, gstate.camera_hit.x + ox,
|
||||
gstate.camera_hit.y + oy, gstate.camera_hit.z + oz);
|
||||
}
|
||||
|
||||
particle_generate_side(
|
||||
&(struct block_info) {.block = &blk,
|
||||
.neighbours = neighbours,
|
||||
.x = gstate.camera_hit.x,
|
||||
.y = gstate.camera_hit.y,
|
||||
.z = gstate.camera_hit.z},
|
||||
gstate.camera_hit.side);
|
||||
}
|
||||
}
|
||||
|
||||
size_t slot = inventory_get_hotbar(
|
||||
|
@ -360,6 +386,7 @@ static void screen_ingame_render2D(struct screen* s, int width, int height) {
|
|||
|
||||
gfx_blending(MODE_BLEND);
|
||||
gfx_bind_texture(&texture_gui2);
|
||||
|
||||
// draw hotbar selection
|
||||
gutil_texquad((width - 182 * 2) / 2 - 2
|
||||
+ 20 * 2
|
||||
|
|
|
@ -210,11 +210,9 @@ static void screen_inventory_render2D(struct screen* s, int width, int height) {
|
|||
= windowc_get_latest(gstate.windows[WINDOWC_INVENTORY]);
|
||||
|
||||
// darken background
|
||||
gfx_blending(MODE_BLEND);
|
||||
gfx_texture(false);
|
||||
gutil_texquad_col(0, 0, 0, 0, 0, 0, width, height, 0, 0, 0, 180);
|
||||
gfx_texture(true);
|
||||
gfx_blending(MODE_OFF);
|
||||
|
||||
int off_x = (width - GUI_WIDTH * 2) / 2;
|
||||
int off_y = (height - GUI_HEIGHT * 2) / 2;
|
||||
|
@ -272,10 +270,8 @@ static void screen_inventory_render2D(struct screen* s, int width, int height) {
|
|||
|
||||
gfx_bind_texture(&texture_gui2);
|
||||
|
||||
gfx_blending(MODE_BLEND);
|
||||
gutil_texquad(off_x + selection->x - 8, off_y + selection->y - 8, 208, 0,
|
||||
24, 24, 24 * 2, 24 * 2);
|
||||
gfx_blending(MODE_OFF);
|
||||
|
||||
int icon_offset = 32;
|
||||
icon_offset += gutil_control_icon(icon_offset, IB_GUI_UP, "Move");
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include "network/client_interface.h"
|
||||
#include "network/server_interface.h"
|
||||
#include "network/server_local.h"
|
||||
#include "particle.h"
|
||||
#include "platform/gfx.h"
|
||||
#include "platform/input.h"
|
||||
#include "world.h"
|
||||
|
@ -79,11 +80,13 @@ int main(void) {
|
|||
clin_init();
|
||||
svin_init();
|
||||
chunk_mesher_init();
|
||||
particle_init();
|
||||
|
||||
struct server_local server;
|
||||
server_local_create(&server);
|
||||
|
||||
ptime_t last_frame = time_get();
|
||||
ptime_t last_tick = last_frame;
|
||||
|
||||
while(!gstate.quit) {
|
||||
ptime_t this_frame = time_get();
|
||||
|
@ -100,6 +103,14 @@ int main(void) {
|
|||
|
||||
clin_update();
|
||||
|
||||
float tick_delta = time_diff_s(last_tick, time_get()) / 0.05F;
|
||||
|
||||
while(tick_delta >= 1.0F) {
|
||||
last_tick = time_add_ms(last_tick, 50);
|
||||
tick_delta -= 1.0F;
|
||||
particle_update();
|
||||
}
|
||||
|
||||
bool render_world
|
||||
= gstate.current_screen->render_world && gstate.world_loaded;
|
||||
|
||||
|
@ -160,6 +171,11 @@ int main(void) {
|
|||
|
||||
gstate.stats.chunks_rendered
|
||||
= world_render(&gstate.world, &gstate.camera, false);
|
||||
|
||||
particle_render(
|
||||
gstate.camera.view,
|
||||
(vec3) {gstate.camera.x, gstate.camera.y, gstate.camera.z},
|
||||
tick_delta);
|
||||
} else {
|
||||
gstate.stats.chunks_rendered = 0;
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include "client_interface.h"
|
||||
#include "../game/game_state.h"
|
||||
#include "../particle.h"
|
||||
#include "../platform/thread.h"
|
||||
#include "server_interface.h"
|
||||
|
||||
|
@ -146,10 +147,36 @@ void clin_process(struct client_rpc* call) {
|
|||
gstate.world_time_start = time_get();
|
||||
break;
|
||||
case CRPC_SET_BLOCK:
|
||||
if(call->payload.set_block.block.type == BLOCK_AIR) {
|
||||
struct block_data blk = world_get_block(
|
||||
&gstate.world, call->payload.set_block.x,
|
||||
call->payload.set_block.y, call->payload.set_block.z);
|
||||
struct block_data neighbours[6];
|
||||
|
||||
for(int k = 0; k < SIDE_MAX; k++) {
|
||||
int ox, oy, oz;
|
||||
blocks_side_offset((enum side)k, &ox, &oy, &oz);
|
||||
|
||||
neighbours[k] = world_get_block(
|
||||
&gstate.world, call->payload.set_block.x + ox,
|
||||
call->payload.set_block.y + oy,
|
||||
call->payload.set_block.z + oz);
|
||||
}
|
||||
|
||||
particle_generate_block(&(struct block_info) {
|
||||
.block = &blk,
|
||||
.neighbours = neighbours,
|
||||
.x = call->payload.set_block.x,
|
||||
.y = call->payload.set_block.y,
|
||||
.z = call->payload.set_block.z,
|
||||
});
|
||||
}
|
||||
|
||||
world_set_block(&gstate.world, call->payload.set_block.x,
|
||||
call->payload.set_block.y,
|
||||
call->payload.set_block.z,
|
||||
call->payload.set_block.block, true);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
232
source/particle.c
Normal file
232
source/particle.c
Normal file
|
@ -0,0 +1,232 @@
|
|||
/*
|
||||
Copyright (c) 2023 ByteBit/xtreme8000
|
||||
|
||||
This file is part of CavEX.
|
||||
|
||||
CavEX is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
CavEX is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with CavEX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "game/game_state.h"
|
||||
#include "graphics/render_block.h"
|
||||
#include "particle.h"
|
||||
#include "platform/gfx.h"
|
||||
|
||||
#define PARTICLES_AREA 8
|
||||
#define PARTICLES_VOLUME 64
|
||||
|
||||
ARRAY_DEF(array_particle, struct particle, M_POD_OPLIST)
|
||||
|
||||
array_particle_t particles;
|
||||
|
||||
void particle_init() {
|
||||
array_particle_init(particles);
|
||||
}
|
||||
|
||||
static void particle_add(vec3 pos, vec3 vel, uint8_t tex) {
|
||||
assert(pos && vel);
|
||||
|
||||
struct particle* p = array_particle_push_new(particles);
|
||||
|
||||
if(p) {
|
||||
glm_vec3_copy(pos, p->pos);
|
||||
glm_vec3_copy(pos, p->pos_old);
|
||||
glm_vec3_copy(vel, p->vel);
|
||||
p->tex_uv[0]
|
||||
= (TEX_OFFSET(TEXTURE_X(tex)) + rand_flt() * 12.0F) / 256.0F;
|
||||
p->tex_uv[1]
|
||||
= (TEX_OFFSET(TEXTURE_Y(tex)) + rand_flt() * 12.0F) / 256.0F;
|
||||
p->age = 4.0F / (rand_flt() * 0.9F + 0.1F);
|
||||
p->size = (rand_flt() + 1.0F) * 0.03125F;
|
||||
}
|
||||
}
|
||||
|
||||
void particle_generate_block(struct block_info* info) {
|
||||
assert(info && info->block && info->neighbours);
|
||||
|
||||
if(!blocks[info->block->type])
|
||||
return;
|
||||
|
||||
struct AABB aabb;
|
||||
blocks[info->block->type]->getBoundingBox(info, false, &aabb);
|
||||
|
||||
float volume
|
||||
= (aabb.x2 - aabb.x1) * (aabb.y2 - aabb.y1) * (aabb.z2 - aabb.z1);
|
||||
|
||||
uint8_t tex = blocks[info->block->type]->getTextureIndex(info, SIDE_FRONT);
|
||||
|
||||
for(int k = 0; k < volume * PARTICLES_VOLUME; k++) {
|
||||
float x = rand_flt() * (aabb.x2 - aabb.x1) + aabb.x1;
|
||||
float y = rand_flt() * (aabb.y2 - aabb.y1) + aabb.y1;
|
||||
float z = rand_flt() * (aabb.z2 - aabb.z1) + aabb.z1;
|
||||
|
||||
vec3 vel = {rand_flt() - 0.5F, rand_flt() - 0.5F, rand_flt() - 0.5F};
|
||||
glm_vec3_normalize(vel);
|
||||
glm_vec3_scale(vel, (2.0F * rand_flt() + 0.5F) * 0.05F, vel);
|
||||
|
||||
particle_add((vec3) {info->x + x, info->y + y, info->z + z}, vel, tex);
|
||||
}
|
||||
}
|
||||
|
||||
void particle_generate_side(struct block_info* info, enum side s) {
|
||||
assert(info && info->block && info->neighbours);
|
||||
|
||||
if(!blocks[info->block->type])
|
||||
return;
|
||||
|
||||
struct AABB aabb;
|
||||
blocks[info->block->type]->getBoundingBox(info, false, &aabb);
|
||||
|
||||
float area;
|
||||
switch(s) {
|
||||
case SIDE_RIGHT:
|
||||
case SIDE_LEFT: area = (aabb.y2 - aabb.y1) * (aabb.z2 - aabb.z1); break;
|
||||
case SIDE_BOTTOM:
|
||||
case SIDE_TOP: area = (aabb.x2 - aabb.x1) * (aabb.z2 - aabb.z1); break;
|
||||
case SIDE_FRONT:
|
||||
case SIDE_BACK: area = (aabb.x2 - aabb.x1) * (aabb.y2 - aabb.y1); break;
|
||||
default: return;
|
||||
}
|
||||
|
||||
uint8_t tex = blocks[info->block->type]->getTextureIndex(info, s);
|
||||
float offset = 0.0625F;
|
||||
|
||||
for(int k = 0; k < area * PARTICLES_AREA; k++) {
|
||||
float x = rand_flt() * (aabb.x2 - aabb.x1) + aabb.x1;
|
||||
float y = rand_flt() * (aabb.y2 - aabb.y1) + aabb.y1;
|
||||
float z = rand_flt() * (aabb.z2 - aabb.z1) + aabb.z1;
|
||||
|
||||
switch(s) {
|
||||
case SIDE_LEFT: x = aabb.x1 - offset; break;
|
||||
case SIDE_RIGHT: x = aabb.x2 + offset; break;
|
||||
case SIDE_BOTTOM: y = aabb.y1 - offset; break;
|
||||
case SIDE_TOP: y = aabb.y2 + offset; break;
|
||||
case SIDE_FRONT: z = aabb.z1 - offset; break;
|
||||
case SIDE_BACK: z = aabb.z2 + offset; break;
|
||||
default: return;
|
||||
}
|
||||
|
||||
vec3 vel = {rand_flt() - 0.5F, rand_flt() - 0.5F, rand_flt() - 0.5F};
|
||||
glm_vec3_normalize(vel);
|
||||
glm_vec3_scale(vel, (2.0F * rand_flt() + 0.5F) * 0.05F, vel);
|
||||
|
||||
particle_add((vec3) {info->x + x, info->y + y, info->z + z}, vel, tex);
|
||||
}
|
||||
}
|
||||
|
||||
static void render_single(struct particle* p, vec3 camera, float delta) {
|
||||
assert(p && camera);
|
||||
|
||||
vec3 pos_lerp;
|
||||
glm_vec3_lerp(p->pos_old, p->pos, delta, pos_lerp);
|
||||
|
||||
vec3 v, s, t;
|
||||
glm_vec3_sub(pos_lerp, camera, v);
|
||||
glm_vec3_crossn(v, (vec3) {0.0F, 1.0F, 0.0F}, s);
|
||||
glm_vec3_crossn(v, s, t);
|
||||
|
||||
glm_vec3_scale(s, p->size, s);
|
||||
glm_vec3_scale(t, p->size, t);
|
||||
|
||||
struct block_data in_block
|
||||
= world_get_block(&gstate.world, floorf(pos_lerp[0]),
|
||||
floorf(pos_lerp[1]), floorf(pos_lerp[2]));
|
||||
uint8_t light = roundf(
|
||||
gfx_lookup_light((in_block.torch_light << 4) | in_block.sky_light)
|
||||
* 255.0F * 0.8F);
|
||||
|
||||
gfx_draw_quads_flt(
|
||||
4,
|
||||
(float[]) {-s[0] - t[0] + pos_lerp[0], -s[1] - t[1] + pos_lerp[1],
|
||||
-s[2] - t[2] + pos_lerp[2], s[0] - t[0] + pos_lerp[0],
|
||||
s[1] - t[1] + pos_lerp[1], s[2] - t[2] + pos_lerp[2],
|
||||
s[0] + t[0] + pos_lerp[0], s[1] + t[1] + pos_lerp[1],
|
||||
s[2] + t[2] + pos_lerp[2], -s[0] + t[0] + pos_lerp[0],
|
||||
-s[1] + t[1] + pos_lerp[1], -s[2] + t[2] + pos_lerp[2]},
|
||||
(uint8_t[]) {light, light, light, 255, light, light, light, 255, light,
|
||||
light, light, 255, light, light, light, 255},
|
||||
(float[]) {p->tex_uv[0], p->tex_uv[1], p->tex_uv[0] + 4.0F / 256.0F,
|
||||
p->tex_uv[1], p->tex_uv[0] + 4.0F / 256.0F,
|
||||
p->tex_uv[1] + 4.0F / 256.0F, p->tex_uv[0],
|
||||
p->tex_uv[1] + 4.0F / 256.0F});
|
||||
}
|
||||
|
||||
void particle_update() {
|
||||
array_particle_it_t it;
|
||||
array_particle_it(it, particles);
|
||||
|
||||
while(!array_particle_end_p(it)) {
|
||||
struct particle* p = array_particle_ref(it);
|
||||
|
||||
glm_vec3_copy(p->pos, p->pos_old);
|
||||
|
||||
vec3 new_pos;
|
||||
glm_vec3_add(p->pos, p->vel, new_pos);
|
||||
|
||||
w_coord_t bx = floorf(new_pos[0]);
|
||||
w_coord_t by = floorf(new_pos[1]);
|
||||
w_coord_t bz = floorf(new_pos[2]);
|
||||
struct block_data in_block = world_get_block(&gstate.world, bx, by, bz);
|
||||
|
||||
bool intersect = false;
|
||||
struct AABB aabb;
|
||||
if(blocks[in_block.type]
|
||||
&& blocks[in_block.type]->getBoundingBox(
|
||||
&(struct block_info) {.block = &in_block,
|
||||
.neighbours = NULL,
|
||||
.x = bx,
|
||||
.y = by,
|
||||
.z = bz},
|
||||
true, &aabb)) {
|
||||
aabb_translate(&aabb, bx, by, bz);
|
||||
intersect = aabb_intersection_point(&aabb, new_pos[0], new_pos[1],
|
||||
new_pos[2]);
|
||||
}
|
||||
|
||||
if(!intersect) {
|
||||
glm_vec3_copy(new_pos, p->pos);
|
||||
} else {
|
||||
glm_vec3_zero(p->vel);
|
||||
}
|
||||
|
||||
p->vel[1] -= 0.04F;
|
||||
glm_vec3_scale(p->vel, 0.98F, p->vel);
|
||||
p->age--;
|
||||
|
||||
if(p->age > 0) {
|
||||
array_particle_next(it);
|
||||
} else {
|
||||
array_particle_remove(particles, it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void particle_render(mat4 view, vec3 camera, float delta) {
|
||||
assert(view && camera);
|
||||
|
||||
gfx_matrix_modelview(view);
|
||||
gfx_bind_texture(&texture_terrain);
|
||||
gfx_lighting(false);
|
||||
|
||||
array_particle_it_t it;
|
||||
array_particle_it(it, particles);
|
||||
|
||||
while(!array_particle_end_p(it)) {
|
||||
render_single(array_particle_ref(it), camera, delta);
|
||||
array_particle_next(it);
|
||||
}
|
||||
|
||||
gfx_lighting(true);
|
||||
}
|
42
source/particle.h
Normal file
42
source/particle.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
Copyright (c) 2023 ByteBit/xtreme8000
|
||||
|
||||
This file is part of CavEX.
|
||||
|
||||
CavEX is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
CavEX is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with CavEX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PARTICLE_H
|
||||
#define PARTICLE_H
|
||||
|
||||
#include "cglm/cglm.h"
|
||||
#include "platform/time.h"
|
||||
#include "world.h"
|
||||
|
||||
struct particle {
|
||||
vec3 pos;
|
||||
vec3 pos_old;
|
||||
vec3 vel;
|
||||
vec2 tex_uv;
|
||||
float size;
|
||||
int age;
|
||||
};
|
||||
|
||||
void particle_init(void);
|
||||
void particle_generate_block(struct block_info* info);
|
||||
void particle_generate_side(struct block_info* info, enum side s);
|
||||
void particle_update(void);
|
||||
void particle_render(mat4 view, vec3 camera, float delta);
|
||||
|
||||
#endif
|
|
@ -80,5 +80,7 @@ void gfx_draw_lines(size_t vertex_count, const int16_t* vertices,
|
|||
const uint8_t* colors);
|
||||
void gfx_draw_quads(size_t vertex_count, const int16_t* vertices,
|
||||
const uint8_t* colors, const uint16_t* texcoords);
|
||||
void gfx_draw_quads_flt(size_t vertex_count, const float* vertices,
|
||||
const uint8_t* colors, const float* texcoords);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -429,3 +429,22 @@ void gfx_draw_quads(size_t vertex_count, const int16_t* vertices,
|
|||
glDisableVertexAttribArray(1);
|
||||
glDisableVertexAttribArray(2);
|
||||
}
|
||||
|
||||
void gfx_draw_quads_flt(size_t vertex_count, const float* vertices,
|
||||
const uint8_t* colors, const float* texcoords) {
|
||||
assert(vertices && colors && texcoords);
|
||||
|
||||
glEnableVertexAttribArray(0);
|
||||
glEnableVertexAttribArray(1);
|
||||
glEnableVertexAttribArray(2);
|
||||
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, vertices);
|
||||
glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, colors);
|
||||
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, texcoords);
|
||||
|
||||
glDrawArrays(GL_QUADS, 0, vertex_count);
|
||||
|
||||
glDisableVertexAttribArray(0);
|
||||
glDisableVertexAttribArray(1);
|
||||
glDisableVertexAttribArray(2);
|
||||
}
|
||||
|
|
|
@ -31,6 +31,13 @@ ptime_t time_get() {
|
|||
return t;
|
||||
}
|
||||
|
||||
ptime_t time_add_ms(ptime_t t, unsigned int ms) {
|
||||
uint64_t ns = t.tv_nsec + ms * 1000000LL;
|
||||
t.tv_sec += ns / 1000000000LL;
|
||||
t.tv_nsec = ns % 1000000000LL;
|
||||
return t;
|
||||
}
|
||||
|
||||
int32_t time_diff_ms(ptime_t f, ptime_t s) {
|
||||
return (s.tv_sec - f.tv_sec) * 1000 + (s.tv_nsec - f.tv_nsec) / 1000000;
|
||||
}
|
||||
|
@ -54,6 +61,10 @@ ptime_t time_get() {
|
|||
return gettime();
|
||||
}
|
||||
|
||||
ptime_t time_add_ms(ptime_t t, unsigned int ms) {
|
||||
return t + TB_TIMER_CLOCK * ms;
|
||||
}
|
||||
|
||||
int32_t time_diff_ms(ptime_t f, ptime_t s) {
|
||||
return (s - f) / TB_TIMER_CLOCK;
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ typedef struct timespec ptime_t;
|
|||
|
||||
void time_reset(void);
|
||||
ptime_t time_get(void);
|
||||
ptime_t time_add_ms(ptime_t t, unsigned int ms);
|
||||
int32_t time_diff_ms(ptime_t f, ptime_t s);
|
||||
float time_diff_s(ptime_t f, ptime_t s);
|
||||
|
||||
|
|
|
@ -163,6 +163,11 @@ void gfx_setup() {
|
|||
GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGB, GX_RGB8, 0);
|
||||
GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_U8, 8);
|
||||
|
||||
// entities, particles
|
||||
GX_SetVtxAttrFmt(GX_VTXFMT1, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
|
||||
GX_SetVtxAttrFmt(GX_VTXFMT1, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0);
|
||||
GX_SetVtxAttrFmt(GX_VTXFMT1, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0);
|
||||
|
||||
// gui, font drawing
|
||||
GX_SetVtxAttrFmt(GX_VTXFMT2, GX_VA_POS, GX_POS_XYZ, GX_S16, 0);
|
||||
GX_SetVtxAttrFmt(GX_VTXFMT2, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0);
|
||||
|
@ -505,3 +510,20 @@ void gfx_draw_quads(size_t vertex_count, const int16_t* vertices,
|
|||
|
||||
GX_End();
|
||||
}
|
||||
|
||||
void gfx_draw_quads_flt(size_t vertex_count, const float* vertices,
|
||||
const uint8_t* colors, const float* texcoords) {
|
||||
assert(vertices && colors && texcoords);
|
||||
|
||||
GX_Begin(GX_QUADS, GX_VTXFMT1, vertex_count);
|
||||
|
||||
for(size_t k = 0; k < vertex_count; k++) {
|
||||
GX_Position3f32(vertices[k * 3 + 0], vertices[k * 3 + 1],
|
||||
vertices[k * 3 + 2]);
|
||||
GX_Color4u8(colors[k * 4 + 0], colors[k * 4 + 1], colors[k * 4 + 2],
|
||||
colors[k * 4 + 3]);
|
||||
GX_TexCoord2f32(texcoords[k * 2 + 0], texcoords[k * 2 + 1]);
|
||||
}
|
||||
|
||||
GX_End();
|
||||
}
|
||||
|
|
|
@ -24,6 +24,10 @@
|
|||
|
||||
#include "util.h"
|
||||
|
||||
float rand_flt() {
|
||||
return (float)rand() / RAND_MAX;
|
||||
}
|
||||
|
||||
void* file_read(const char* name) {
|
||||
FILE* f = fopen(name, "rb");
|
||||
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
|
||||
#include "platform/time.h"
|
||||
|
||||
float rand_flt(void);
|
||||
|
||||
void* file_read(const char* name);
|
||||
|
||||
uint32_t hash_u32(uint32_t x);
|
||||
|
|
Loading…
Reference in a new issue