trail rendering basics
authorhgn <hgodden00@gmail.com>
Sun, 4 Feb 2024 09:49:37 +0000 (09:49 +0000)
committerhgn <hgodden00@gmail.com>
Sun, 4 Feb 2024 09:49:37 +0000 (09:49 +0000)
skaterift.c
skaterift.h
trail.c [new file with mode: 0644]
trail.h [new file with mode: 0644]

index bc0bd3c79f0b5623c5b36169eb5d337280bb0964..82aa54cd4e9f6d31c64be86ee88265be5c49edee 100644 (file)
@@ -59,6 +59,8 @@
 #include "player_effects.c"
 #include "freecam.c"
 #include "testing.c"
+#include "trail.h"
+#include "trail.c"
 
 static int k_tools_mode = 0;
 
@@ -198,6 +200,7 @@ static void skaterift_load_player_content(void){
 
    particle_alloc( &particles_grind, 300 );
    particle_alloc( &particles_env, 200 );
+   trail_alloc( &trails_test, 200 );
 
    player_load_animation_reference( "models/ch_none.mdl" );
    player_model_load( &localplayer.fallback_model, "models/ch_none.mdl" );
@@ -513,6 +516,10 @@ static void render_scene(void){
    particle_system_prerender( &particles_env );
    particle_system_render( &particles_env, &skaterift.cam );
 
+   trail_system_update( &trails_test, vg.time_delta, 
+                        localplayer.rb.co, localplayer.rb.to_world[1], 1.0f );
+   trail_system_debug( &trails_test );
+
    /* 
     * render transition 
     */
index a21e6ab423642b4b86903b8c7490cff9471df3a6..ebab76734b6d909ca475dc5b4b1dce67b16f9379 100644 (file)
@@ -11,6 +11,7 @@
 #include "vg/vg.h"
 #include "world.h"
 #include "addon.h"
+#include "trail.h"
 
 enum skaterift_rt {
    k_skaterift_rt_workshop_preview,
@@ -69,10 +70,15 @@ struct{
 
    audio_channel *aud_air;
    const char *hub_world;
+
+   struct trail_system test_trail;
 }
 static skaterift = { 
    .op = k_async_op_clientloading, .time_rate = 1.0f, .demo_mode = 1,
-   .hub_world = "maps/dev_hub"
+   .hub_world = "maps/dev_hub",
+   .test_trail = {
+      .max = 80
+   }
 };
 
 /* Skaterift api */
diff --git a/trail.c b/trail.c
new file mode 100644 (file)
index 0000000..bf23b1c
--- /dev/null
+++ b/trail.c
@@ -0,0 +1,159 @@
+#pragma once
+#include "trail.h"
+
+static void trail_system_update( trail_system *sys, f32 dt,
+                                 v3f co, v3f normal, f32 alpha ){
+   /* update existing points and clip dead ones */
+   bool clip_allowed = 1;
+   for( i32 i=0; i<sys->count; i ++ ){
+      i32 i0 = sys->head - sys->count + i;
+      if( i0 < 0 ) i0 += sys->max;
+
+      trail_point *p0 = &sys->array[i0];
+      p0->alpha -= dt/sys->lifetime;
+
+      if( clip_allowed ){
+         if( p0->alpha <= 0.0f )
+            sys->count --;
+         else
+            clip_allowed = 0;
+      }
+   }
+
+   bool add_point = 1;
+   i32 index_current = sys->head;
+   if( sys->count >= 2 ) index_current = sys->head -1;
+
+   i32 index_prev = index_current -1;
+
+   if( index_current < 0 ) index_current += sys->max;
+   if( index_prev    < 0 ) index_prev    += sys->max;
+
+   /* always enforced non-zero distance */
+   if( sys->count >= 1 ){
+      if( v3_dist2( sys->array[index_prev].co, co ) < 0.001f*0.001f )
+         return;
+   }
+
+   /* copy new info in */
+   trail_point *p_current = &sys->array[index_current];
+   v3_copy( co, p_current->co );
+   v3_copy( normal, p_current->normal );
+   p_current->alpha = alpha;
+
+   /* update direction */
+   if( sys->count >= 2 ){
+      trail_point *p_prev = &sys->array[index_prev];
+
+      v3f dir;
+      v3_sub( co, p_prev->co, dir );
+      v3_normalize( dir );
+      v3_cross( dir, normal, p_current->right );
+      v3_copy( p_current->right, p_prev->right );
+
+      /* decide if to prevent split based on user min-distance */
+      if( v3_dist2( p_prev->co, co ) < sys->min_dist*sys->min_dist )
+         add_point = 0;
+   }
+   else 
+      v3_zero( p_current->right );
+
+   if( add_point ){
+      sys->head ++;
+
+      if( sys->head == sys->max )
+         sys->head = 0;
+
+      /* undesirable effect: will remove active points if out of space! */
+      if( sys->count < sys->max )
+         sys->count ++;
+
+      index_current = sys->head;
+   }
+
+   p_current = &sys->array[index_current];
+   v3_copy( co, p_current->co );
+   v3_copy( normal, p_current->normal );
+   p_current->alpha = alpha;
+   v3_zero( p_current->right );
+}
+
+static void trail_system_debug( trail_system *sys ){
+   for( i32 i=0; i<sys->count; i ++ ){
+      i32 i0 = sys->head - sys->count + i;
+      if( i0 < 0 ) i0 += sys->max;
+
+      trail_point *p0 = &sys->array[i0];
+      vg_line_point( p0->co, 0.04f, 0xff000000 | (u32)(p0->alpha*255.0f) );
+      vg_line_arrow( p0->co, p0->right, 0.3f, VG__GREEN );
+
+      if( i == sys->count-1 ) break;
+
+      i32 i1 = i0+1;
+      if( i1 == sys->max ) i1 = 0;
+
+      trail_point *p1 = &sys->array[i1];
+      vg_line( p0->co, p1->co, VG__RED );
+   }
+}
+
+struct trail_init_args {
+   trail_system *sys;
+};
+
+static void async_trail_init( void *payload, u32 size ){
+   struct trail_init_args *args = payload;
+   trail_system *sys = args->sys;
+
+   glGenVertexArrays( 1, &sys->vao );
+   glGenBuffers( 1, &sys->vbo );
+   glBindVertexArray( sys->vao );
+
+   size_t stride = sizeof(trail_vert);
+
+   glBindBuffer( GL_ARRAY_BUFFER, sys->vbo );
+   glBufferData( GL_ARRAY_BUFFER, sys->max*stride*2, NULL, GL_DYNAMIC_DRAW );
+
+   /* 0: coordinates */
+   glVertexAttribPointer( 0, 4, GL_FLOAT, GL_FALSE, stride, (void*)0 );
+   glEnableVertexAttribArray( 0 );
+
+   VG_CHECK_GL_ERR();
+}
+
+static void trail_alloc( trail_system *sys, u32 max ){
+   size_t stride = sizeof(trail_vert);
+   sys->max = max;
+   sys->array = vg_linear_alloc( vg_mem.rtmemory, max*sizeof(trail_point) );
+   sys->vertices = vg_linear_alloc( vg_mem.rtmemory, max*stride*2 );
+
+   vg_async_item *call = vg_async_alloc( sizeof(struct trail_init_args) );
+
+   struct trail_init_args *init = call->payload;
+   init->sys = sys;
+   vg_async_dispatch( call, async_trail_init );
+}
+
+static void trail_system_prerender( trail_system *sys ){
+#if 0
+   glBindVertexArray( sys->vao );
+
+   size_t stride = sizeof(trail_vert);
+   glBindBuffer( GL_ARRAY_BUFFER, sys->vbo );
+   glBufferSubData( GL_ARRAY_BUFFER, 0, sys->alive*stride*4, sys->vertices );
+#endif
+}
+
+static void trail_system_render( trail_system *sys, camera *cam ){
+#if 0
+   glDisable( GL_CULL_FACE );
+   glEnable( GL_DEPTH_TEST );
+
+   shader_trail_use();
+   shader_trail_uPv( cam->mtx.pv );
+   shader_trail_uPvPrev( cam->mtx_prev.pv );
+
+       glBindVertexArray( sys->vao );
+       glDrawElements( GL_TRIANGLES, sys->alive*6, GL_UNSIGNED_SHORT, NULL );
+#endif
+}
diff --git a/trail.h b/trail.h
new file mode 100644 (file)
index 0000000..dc90fc9
--- /dev/null
+++ b/trail.h
@@ -0,0 +1,43 @@
+#ifndef TRAIL_H
+#define TRAIL_H
+
+#include "skaterift.h"
+
+typedef struct trail_system trail_system;
+typedef struct trail_point trail_point;
+typedef struct trail_vert trail_vert;
+
+struct trail_system {
+   struct trail_point {
+      v3f co, normal, right;
+      f32 alpha;
+   }
+   *array;
+
+#pragma pack(push,1)
+   struct trail_vert {
+      v4f co; /* xyz: position, w: alpha */
+   }
+   *vertices;
+#pragma pack(pop)
+
+   i32 head, count, max;
+   GLuint vao, vbo;
+
+   /* render settings */
+   f32 width, lifetime, min_dist;
+}
+static trails_test = {
+   .width = 0.25f,
+   .lifetime = 5.0f,
+   .min_dist = 0.5f
+};
+
+static void trail_alloc( trail_system *sys, u32 max );
+static void trail_system_update( trail_system *sys, f32 dt, 
+                                 v3f co, v3f normal, f32 alpha );
+static void trail_system_debug( trail_system *sys );
+static void trail_system_prerender( trail_system *sys );
+static void trail_system_render( trail_system *sys, camera *cam );
+
+#endif /* TRAIL_H */