point maps (wip)
authorhgn <hgodden00@gmail.com>
Fri, 19 May 2023 21:06:07 +0000 (22:06 +0100)
committerhgn <hgodden00@gmail.com>
Fri, 19 May 2023 21:06:07 +0000 (22:06 +0100)
15 files changed:
blender_export.py
build.c
ent_skateshop.c
entity.h
maps_src/mp_mtzero.mdl
maps_src/mp_spawn.mdl
model.h
pointcloud.h [new file with mode: 0644]
shaders/cloud.fs [new file with mode: 0644]
shaders/cloud.vs [new file with mode: 0644]
shaders/point_map.h [new file with mode: 0644]
skaterift.c
skaterift.h
world_gen.h
world_routes.h

index cc51987624c7c05e1408d6747f0b5a91333b8db0..8c1eaace97da36bdd8f3831d403f8521a9c86e8c 100644 (file)
@@ -355,10 +355,16 @@ class ent_skateshop_boards(Structure):
                ("id_info",c_uint32),
                ("id_rack",c_uint32)]
 #}  
+class ent_skateshop_worlds(Structure):
+#{
+   _fields_ = [("id_display",c_uint32),
+               ("id_info",c_uint32)]
+#}
 class ent_skateshop_anon_union(Union):
 #{
    _fields_ = [("boards",ent_skateshop_boards),
-               ("character",ent_skateshop_characters)]
+               ("character",ent_skateshop_characters),
+               ("worlds",ent_skateshop_worlds)]
 #}
 class ent_skateshop(Structure):
 #{
@@ -697,6 +703,7 @@ def sr_compile_material( mat ):
          if mat.SR_data.skate_surface: flags |= 0x1
          if mat.SR_data.grow_grass: flags |= 0x4
          if mat.SR_data.grind_surface: flags |= 0x8
+         if mat.SR_data.preview_visibile: flags |= 0x40
       #}
       if mat.SR_data.shader == 'invisible': flags |= 0x10
       if mat.SR_data.shader == 'boundary': flags |= (0x10|0x20)
@@ -1694,6 +1701,11 @@ def sr_compile( collection ):
                charshop.id_display = sr_entity_id( obj_data.mark_display )
                charshop.id_info = sr_entity_id( obj_data.mark_info )
             #}
+            elif skateshop.type == 2:#{
+               worldshop = skateshop._anonymous_union.worlds
+               worldshop.id_display = sr_entity_id( obj_data.mark_display )
+               worldshop.id_info = sr_entity_id( obj_data.mark_info )
+            #}
             skateshop.id_camera = sr_entity_id( obj_data.cam )
             compile_obj_transform( obj, skateshop.transform )
             sr_ent_push(skateshop)
@@ -2226,6 +2238,7 @@ class SR_MATERIAL_PANEL(bpy.types.Panel):
             row.prop( active_mat.SR_data, "skate_surface" )
             row.prop( active_mat.SR_data, "grind_surface" )
             row.prop( active_mat.SR_data, "grow_grass" )
+            row.prop( active_mat.SR_data, "preview_visibile" )
          #}
       #}
 
@@ -2818,7 +2831,8 @@ class SR_OBJECT_ENT_SKATESHOP(bpy.types.PropertyGroup):
 #{
    tipo: bpy.props.EnumProperty( name='Type',
                                  items=[('0','boards',''),
-                                        ('1','character','')] )
+                                        ('1','character',''),
+                                        ('2','world','')] )
    mark_rack: bpy.props.PointerProperty( \
            type=bpy.types.Object, name="Board Rack", \
            poll=lambda self,obj: sr_filter_ent_type(obj,['ent_marker']))
@@ -3070,6 +3084,11 @@ class SR_MATERIAL_PROPERTIES(bpy.types.PropertyGroup):
          default=False,\
          description = "Spawn grass sprites on this surface?" \
    )
+   preview_visibile: bpy.props.BoolProperty( \
+         name="Preview visibile", \
+         default=True,\
+         description = "Show this material in preview models?" \
+   )
    blend_offset: bpy.props.FloatVectorProperty( \
          name="Blend Offset", \
          size=2, \
@@ -3942,6 +3961,15 @@ def cv_draw():
                info_cu = Vector((1.2,0.01,0.3))*0.5
                info_co = Vector((0.0,0.0,0.0))*0.5
             #}
+            elif data.tipo == '2':#{
+               rack = None
+               cc1 = (1.0,0.0,0.0)
+               cc2 = (1.0,0.5,0.0)
+               display_cu = Vector((1.0,1.0,0.5))*0.5
+               display_co = Vector((0.0,0.0,0.5))*0.5
+               info_cu = Vector((1.2,0.01,0.3))*0.5
+               info_co = Vector((0.0,0.0,0.0))*0.5
+            #}
 
             if rack:
                cv_draw_ucube( rack.matrix_world, cc, rack_cu, rack_co )
diff --git a/build.c b/build.c
index ae1ff0f9a64cf6e8c2b09a3ebe21320e5062dc2b..d5b09c2cfd6c71ffec7822ee67382c467ef4ea0f 100644 (file)
--- a/build.c
+++ b/build.c
@@ -137,6 +137,9 @@ void build_shaders(void)
    _S( "model_gate",           "model_gate.vs",    "model_gate_lq.fs" );
    _S( "model_font",           "model_font.vs",    "model_font.fs" );
 
+   /* Pointcloud */
+   _S( "point_map", "cloud.vs", "cloud.fs" );
+
    /* 2D */
    _S( "blit",      "blit.vs",      "blit.fs" );
    _S( "blitblur",  "blit.vs",      "blitblur.fs" );
index 9438c00c6c6aa3c72e736843918a9900d827791e..b47dacf9be0780707e9ab3a874b42f263da98a79 100644 (file)
@@ -9,6 +9,7 @@
 #include "player.h"
 #include "gui.h"
 #include "menu.h"
+#include "pointcloud.h"
 
 /*
  * Checks string equality but does a hash check first
@@ -474,7 +475,8 @@ VG_STATIC void global_skateshop_preupdate(void)
    player_vector_angles( localplayer.cam_override_angles, dir, 1.0f, 0.0f );
 
    v3f lookat;
-   if( shop->type == k_skateshop_type_boardshop ){
+   if( shop->type == k_skateshop_type_boardshop ||
+       shop->type == k_skateshop_type_worldshop ){
       ent_marker *display = mdl_arritm( &world->ent_marker,
                                     mdl_entity_id_id(shop->boards.id_display) );
       
@@ -570,6 +572,25 @@ VG_STATIC void global_skateshop_preupdate(void)
          global_skateshop_exit();
       }
    }
+   else if( shop->type == k_skateshop_type_worldshop ){
+      gui_helper_action( axis_display_string( k_sraxis_mbrowse_h ), "browse" );
+
+      v2f input;
+      joystick_state( k_srjoystick_steer, input );
+      pointcloud.control[0] += input[0] * vg.time_delta;
+      pointcloud.control[2] += input[1] * vg.time_delta;
+
+      pointcloud.control[0] = vg_clampf( pointcloud.control[0], -10.0f, 10.0f );
+      pointcloud.control[2] = vg_clampf( pointcloud.control[2], -10.0f, 10.0f );
+
+      if( button_press( k_srbind_trick1 ) ){
+         pointcloud.control[3] += vg.time_delta*0.2f;
+      }
+      if( button_press( k_srbind_trick0 ) ){
+         pointcloud.control[3] -= vg.time_delta*0.2f;
+}
+      pointcloud.control[3] = vg_clampf( pointcloud.control[3], 0.001f, 10.0f );
+   }
    else{
       vg_fatal_error( "Unknown store (%u)\n", shop->type );
    }
@@ -717,6 +738,55 @@ VG_STATIC void skateshop_render_charshop(void)
 {
 }
 
+VG_STATIC void skateshop_render_worldshop(void)
+{
+   world_instance *world = get_active_world();
+
+   m4x3f mmdl;
+   ent_skateshop *shop = global_skateshop.ptr_ent;
+   ent_marker *mark_display = mdl_arritm( &world->ent_marker,
+                                  mdl_entity_id_id(shop->worlds.id_display));
+   mdl_transform_m4x3( &mark_display->transform, mmdl );
+
+   /* TODO? ... */
+   v3f vol;
+   v3_sub( world->scene_geo.bbx[1], world->scene_geo.bbx[0], vol );
+
+   v2f rect = { 1.0f, 1.0f },
+       map  = { vol[0], vol[2] },
+       result;
+
+   f32 rp = rect[0] * map[1],
+       rc = rect[1] * map[0];
+   
+   u32 axis, other;
+   if( rc > rp ) axis = 0;
+   else          axis = 1;
+   other = axis ^ 0x1;
+
+   result[axis] = rect[axis];
+   result[other] = (rect[axis] * map[other]) / map[axis];
+
+   m4x3f mlocal, mx;
+   m4x3_identity( mlocal );
+
+   mlocal[0][0] = result[0];
+   mlocal[2][2] = result[1];
+   mlocal[1][1] = (vol[1]/vol[0]) * mlocal[0][0];
+   mlocal[3][0] = (rect[0]-result[0])*0.5f - rect[0]*0.5f;  /* sea level? */
+   mlocal[3][2] = (rect[1]-result[1])*0.5f - rect[1]*0.5f;
+   m4x3_mul( mmdl, mlocal, mx );
+
+#if 1
+   glEnable(GL_BLEND);
+   glBlendFunc(GL_ONE, GL_ONE);
+   glDisable(GL_DEPTH_TEST);
+#endif
+   pointcloud_render( world, &main_camera, mx );
+   glDisable(GL_BLEND);
+   glEnable(GL_DEPTH_TEST);
+}
+
 /*
  * World: render event
  */
@@ -732,6 +802,9 @@ VG_STATIC void skateshop_render(void)
    else if( shop->type == k_skateshop_type_charshop ){
       skateshop_render_charshop();
    }
+   else if( shop->type == k_skateshop_type_worldshop ){
+      skateshop_render_worldshop();
+   }
    else{
       vg_fatal_error( "Unknown store (%u)\n", shop->type );
    }
index 867c74c8db0cdd0f38287dd1d25152ac74f3b544..998557edfa3de1f84c13f5a9ee9477c768136be2 100644 (file)
--- a/entity.h
+++ b/entity.h
@@ -220,7 +220,8 @@ struct ent_marker{
 
 enum skateshop_type{
    k_skateshop_type_boardshop,
-   k_skateshop_type_charshop
+   k_skateshop_type_charshop,
+   k_skateshop_type_worldshop
 };
 
 struct ent_skateshop{
@@ -240,6 +241,12 @@ struct ent_skateshop{
              id_info;
       }
       character;
+
+      struct{
+         u32 id_display,
+             id_info;
+      }
+      worlds;
    };
 };
 
index 7de53a9627a861514055027a5474668b21986479..ddd7d6df75e5026e8eaf4f999df3841899ba726e 100644 (file)
Binary files a/maps_src/mp_mtzero.mdl and b/maps_src/mp_mtzero.mdl differ
index 8e3042afe83b3ea216e9d3036890f143684753d8..2c015270aa6b4458b1a0330fd82502169d245e37 100644 (file)
Binary files a/maps_src/mp_spawn.mdl and b/maps_src/mp_spawn.mdl differ
diff --git a/model.h b/model.h
index 80ab7cba9f7f6eca7f34ef35a68fea4a274b5080..686a42849b5e6cdf630ac5d448d0a2e247e1b6e4 100644 (file)
--- a/model.h
+++ b/model.h
@@ -36,7 +36,8 @@ enum material_flag
    k_material_flag_grow_grass       = 0x00000004,
    k_material_flag_grindable        = 0x00000008,
    k_material_flag_invisible        = 0x00000010,
-   k_material_flag_boundary         = 0x00000020
+   k_material_flag_boundary         = 0x00000020,
+   k_material_flag_preview_visibile = 0x00000040
 };
 
 #pragma pack(push,1)
diff --git a/pointcloud.h b/pointcloud.h
new file mode 100644 (file)
index 0000000..b303973
--- /dev/null
@@ -0,0 +1,121 @@
+#ifndef POINTCLOUD_H
+#define POINTCLOUD_H
+
+#include "common.h"
+#include "world.h"
+#include "shaders/point_map.h"
+
+#define POINTCLOUD_POINTS 250000
+
+struct pointcloud{
+   GLuint vao, vbo;
+   u32 count;
+
+   v4f control;
+}
+static pointcloud = { .control = {0.0f,0.0f,0.0f,1.0f} };
+
+#pragma pack(push,1)
+struct pointcloud_vert{
+   u16 pos[4];    /* float[  0 -> 1 ] */
+   i8  norm[4];   /* float[ -1 -> 1 ] */
+   u8  colour[4]; /* float[  0 -> 1 ] */
+};
+#pragma pack(pop)
+
+static void async_pointcloud_sub( void *payload, u32 size )
+{
+
+   glBindVertexArray( pointcloud.vao );
+   glBindBuffer( GL_ARRAY_BUFFER, pointcloud.vbo );
+   glBufferSubData( GL_ARRAY_BUFFER, 0, 
+                    sizeof(struct pointcloud_vert)*size, payload );
+   pointcloud.count = size;
+}
+
+static void async_pointcloud_alloc( void *payload, u32 size )
+{
+   glGenVertexArrays( 1, &pointcloud.vao );
+   glGenBuffers( 1, &pointcloud.vbo );
+   glBindVertexArray( pointcloud.vao );
+
+   size_t stride = sizeof( struct pointcloud_vert );
+
+   glBindBuffer( GL_ARRAY_BUFFER, pointcloud.vbo );
+   glBufferData( GL_ARRAY_BUFFER, stride * POINTCLOUD_POINTS, 
+                 payload, GL_DYNAMIC_DRAW );
+
+   /* 0: coordinates */
+   glVertexAttribPointer( 0, 4, GL_UNSIGNED_SHORT, GL_TRUE, stride, (void*)0 );
+   glEnableVertexAttribArray( 0 );
+
+   /* 1: normal */
+   glVertexAttribPointer( 1, 4, GL_BYTE, GL_TRUE, 
+                     stride, (void *)offsetof(struct pointcloud_vert, norm) );
+   glEnableVertexAttribArray( 1 );
+
+   /* 2: colour */
+   glVertexAttribPointer( 2, 4, GL_UNSIGNED_BYTE, GL_TRUE, 
+                     stride, (void *)offsetof(struct pointcloud_vert, colour) );
+   glEnableVertexAttribArray( 2 );
+   VG_CHECK_GL_ERR();
+   pointcloud.count = size;
+}
+
+static void pointcloud_init(void)
+{
+   vg_info( "Generating random test point cloud\n" );
+
+   vg_rand_seed( 2000 );
+   vg_async_item *call = 
+      vg_async_alloc( sizeof(struct pointcloud_vert)*POINTCLOUD_POINTS );
+   struct pointcloud_vert *test_data = call->payload;
+   call->size = POINTCLOUD_POINTS;
+
+   for( u32 i=0; i<POINTCLOUD_POINTS; i++ ){
+      test_data[i].pos[0] = vg_randf64() * 65535.0f;
+      test_data[i].pos[1] = vg_randf64() * 65535.0f;
+      test_data[i].pos[2] = vg_randf64() * 65535.0f;
+
+      v3f norm;
+      vg_rand_dir( norm );
+
+      test_data[i].norm[0] = norm[0] * 127.0f;
+      test_data[i].norm[1] = norm[1] * 127.0f;
+      test_data[i].norm[2] = norm[2] * 127.0f;
+
+      test_data[i].colour[0] = 90;
+      test_data[i].colour[1] = 90;
+      test_data[i].colour[2] = 90;
+      test_data[i].colour[3] = 255;
+   }
+
+   vg_async_dispatch( call, async_pointcloud_alloc );
+   shader_point_map_register();
+}
+
+static void pointcloud_render( world_instance *world, camera *cam, m4x3f model )
+{
+   m4x4f upvmprev;
+   m4x3_expand( model, upvmprev );
+   m4x4_mul( cam->mtx_prev.pv, upvmprev, upvmprev );
+
+   shader_point_map_use();
+   shader_point_map_uPv( cam->mtx.pv );
+   shader_point_map_uPvmPrev( upvmprev );
+   shader_point_map_uMdl( model );
+   shader_point_map_uCamera( cam->pos );
+   shader_point_map_uTime( (v2f){ vg.time, sinf(vg.time) } );
+   shader_point_map_uTransform( pointcloud.control );
+
+   m3x3f mnorm;
+   m3x3_inv( model, mnorm );
+   m3x3_transpose( mnorm, mnorm );
+   shader_point_map_uNormMtx( mnorm );
+
+   glBindVertexArray( pointcloud.vao );
+   glEnable( GL_PROGRAM_POINT_SIZE );
+   glDrawArrays( GL_POINTS, 0, pointcloud.count );
+}
+
+#endif /* POINTCLOUD_H */
diff --git a/shaders/cloud.fs b/shaders/cloud.fs
new file mode 100644 (file)
index 0000000..a7f4802
--- /dev/null
@@ -0,0 +1,24 @@
+out vec4 FragColor;
+
+#include "motion_vectors_fs.glsl"
+
+uniform vec3 uCamera;
+
+in vec4 aColour;
+in vec3 aNorm;
+in vec3 aCo;
+in vec3 aWorldCo;
+
+void main()
+{
+   vec2 ssuv = gl_FragCoord.xy;
+   vec3 vDither = vec3( dot( vec2( 171.0, 231.0 ), ssuv) );
+   float dither = fract( vDither.g / 71.0 ) - 0.5;
+
+   float diff = length(gl_PointCoord.xy-vec2(0.5));
+   if( diff+dither>0.5 )
+      discard;
+
+   compute_motion_vectors();
+   FragColor = aColour;
+}
diff --git a/shaders/cloud.vs b/shaders/cloud.vs
new file mode 100644 (file)
index 0000000..9bac346
--- /dev/null
@@ -0,0 +1,61 @@
+layout (location=0) in vec4 a_co;
+layout (location=1) in vec4 a_norm;
+layout (location=2) in vec4 a_colour;
+
+#include "motion_vectors_vs.glsl"
+
+uniform mat4x3 uMdl;
+uniform mat3 uNormMtx;
+uniform mat4 uPv;
+uniform mat4 uPvmPrev;
+uniform vec2 uTime;
+uniform vec4 uTransform;
+
+out vec4 aColour;
+out vec3 aNorm;
+out vec3 aWorldCo;
+out vec3 aCo;
+
+vec2 rand_hash22( vec2 p )
+{
+   vec3 p3 = fract(vec3(p.xyx) * 213.8976123);
+   p3 += dot(p3, p3.yzx+19.19);
+   return fract(vec2((p3.x + p3.y)*p3.z, (p3.x+p3.z)*p3.y));
+}
+
+vec3 mapP( vec3 p )
+{
+   return p;
+   float t = max(0.0,uTime.y);
+
+   vec3 lco = p * 20.0;
+   vec3 grid = vec3(floor(lco.x),lco.y,floor(lco.z));//fract(p);
+
+   return mix(p,grid * (1.0/20.0), t)*vec3(1.0+t,1.0-t,1.0+t);
+}
+
+void main()
+{
+   vec3 mco = a_co.xyz * uTransform.w + uTransform.xyz;
+
+
+   vec3 center = vec3(0.5);
+   vec3 lco = mapP(mco-center);
+   mco = lco + center;
+
+   vec3 world_pos0 = uMdl     * vec4( mco, 1.0 );
+   vec4 vproj0     = uPv      * vec4( world_pos0, 1.0 );
+   vec4 vproj1     = uPvmPrev * vec4( mco, 1.0 );
+
+   float t = max(0.0,uTime.y);
+   float scaler = smoothstep(0.6,0.58,length(lco.xz*vec2(0.7,1.0)));
+
+   vs_motion_out( vproj0, vproj1 );
+
+   gl_Position = vproj0;
+   gl_PointSize = (8.0*uTransform.w*scaler) / (gl_Position.z + 0.01);
+   aWorldCo = world_pos0;
+   aColour = a_colour*scaler*(0.3+a_co.y)+pow(1.0-a_co.y,16.0);
+   aCo = mco;
+   aNorm = uNormMtx * a_norm.xyz;
+}
diff --git a/shaders/point_map.h b/shaders/point_map.h
new file mode 100644 (file)
index 0000000..533b0dd
--- /dev/null
@@ -0,0 +1,183 @@
+#ifndef SHADER_point_map_H
+#define SHADER_point_map_H
+static void shader_point_map_link(void);
+static void shader_point_map_register(void);
+static struct vg_shader _shader_point_map = {
+   .name = "point_map",
+   .link = shader_point_map_link,
+   .vs = 
+{
+.orig_file = "shaders/cloud.vs",
+.static_src = 
+"layout (location=0) in vec4 a_co;\n"
+"layout (location=1) in vec4 a_norm;\n"
+"layout (location=2) in vec4 a_colour;\n"
+"\n"
+"#line       1        1 \n"
+"const float k_motion_lerp_amount = 0.01;\n"
+"\n"
+"#line      2        0 \n"
+"\n"
+"out vec3 aMotionVec0;\n"
+"out vec3 aMotionVec1;\n"
+"\n"
+"void vs_motion_out( vec4 vproj0, vec4 vproj1 )\n"
+"{\n"
+"   // This magically solves some artifacting errors!\n"
+"   //\n"
+"   vproj1 = vproj0*(1.0-k_motion_lerp_amount) + vproj1*k_motion_lerp_amount;\n"
+"\n"
+"   aMotionVec0 = vec3( vproj0.xy, vproj0.w );\n"
+"   aMotionVec1 = vec3( vproj1.xy, vproj1.w );\n"
+"}\n"
+"\n"
+"#line      6        0 \n"
+"\n"
+"uniform mat4x3 uMdl;\n"
+"uniform mat3 uNormMtx;\n"
+"uniform mat4 uPv;\n"
+"uniform mat4 uPvmPrev;\n"
+"uniform vec2 uTime;\n"
+"uniform vec4 uTransform;\n"
+"\n"
+"out vec4 aColour;\n"
+"out vec3 aNorm;\n"
+"out vec3 aWorldCo;\n"
+"out vec3 aCo;\n"
+"\n"
+"vec2 rand_hash22( vec2 p )\n"
+"{\n"
+"   vec3 p3 = fract(vec3(p.xyx) * 213.8976123);\n"
+"   p3 += dot(p3, p3.yzx+19.19);\n"
+"   return fract(vec2((p3.x + p3.y)*p3.z, (p3.x+p3.z)*p3.y));\n"
+"}\n"
+"\n"
+"vec3 mapP( vec3 p )\n"
+"{\n"
+"   return p;\n"
+"   float t = max(0.0,uTime.y);\n"
+"\n"
+"   vec3 lco = p * 20.0;\n"
+"   vec3 grid = vec3(floor(lco.x),lco.y,floor(lco.z));//fract(p);\n"
+"\n"
+"   return mix(p,grid * (1.0/20.0), t)*vec3(1.0+t,1.0-t,1.0+t);\n"
+"}\n"
+"\n"
+"void main()\n"
+"{\n"
+"   vec3 mco = a_co.xyz * uTransform.w + uTransform.xyz;\n"
+"\n"
+"\n"
+"   vec3 center = vec3(0.5);\n"
+"   vec3 lco = mapP(mco-center);\n"
+"   mco = lco + center;\n"
+"\n"
+"   vec3 world_pos0 = uMdl     * vec4( mco, 1.0 );\n"
+"   vec4 vproj0     = uPv      * vec4( world_pos0, 1.0 );\n"
+"   vec4 vproj1     = uPvmPrev * vec4( mco, 1.0 );\n"
+"\n"
+"   float t = max(0.0,uTime.y);\n"
+"   float scaler = smoothstep(0.6,0.58,length(lco.xz*vec2(0.7,1.0)));\n"
+"\n"
+"   vs_motion_out( vproj0, vproj1 );\n"
+"\n"
+"   gl_Position = vproj0;\n"
+"   gl_PointSize = (8.0*uTransform.w*scaler) / (gl_Position.z + 0.01);\n"
+"   aWorldCo = world_pos0;\n"
+"   aColour = a_colour*scaler*(0.3+a_co.y);\n"
+"   aCo = mco;\n"
+"   aNorm = uNormMtx * a_norm.xyz;\n"
+"}\n"
+""},
+   .fs = 
+{
+.orig_file = "shaders/cloud.fs",
+.static_src = 
+"out vec4 FragColor;\n"
+"\n"
+"#line       1        1 \n"
+"const float k_motion_lerp_amount = 0.01;\n"
+"\n"
+"#line      2        0 \n"
+"\n"
+"layout (location = 1) out vec2 oMotionVec;\n"
+"\n"
+"in vec3 aMotionVec0;\n"
+"in vec3 aMotionVec1;\n"
+"\n"
+"void compute_motion_vectors()\n"
+"{\n"
+"   // Write motion vectors\n"
+"   vec2 vmotion0 = aMotionVec0.xy / aMotionVec0.z;\n"
+"   vec2 vmotion1 = aMotionVec1.xy / aMotionVec1.z;\n"
+"\n"
+"   oMotionVec = (vmotion1-vmotion0) * (1.0/k_motion_lerp_amount);\n"
+"}\n"
+"\n"
+"#line      4        0 \n"
+"\n"
+"uniform vec3 uCamera;\n"
+"\n"
+"in vec4 aColour;\n"
+"in vec3 aNorm;\n"
+"in vec3 aCo;\n"
+"in vec3 aWorldCo;\n"
+"\n"
+"void main()\n"
+"{\n"
+"   vec2 ssuv = gl_FragCoord.xy;\n"
+"   vec3 vDither = vec3( dot( vec2( 171.0, 231.0 ), ssuv) );\n"
+"   float dither = fract( vDither.g / 71.0 ) - 0.5;\n"
+"\n"
+"   float diff = length(gl_PointCoord.xy-vec2(0.5));\n"
+"   if( diff>0.5 )\n"
+"      discard;\n"
+"\n"
+"   compute_motion_vectors();\n"
+"   FragColor = aColour;\n"
+"}\n"
+""},
+};
+
+static GLuint _uniform_point_map_uMdl;
+static GLuint _uniform_point_map_uNormMtx;
+static GLuint _uniform_point_map_uPv;
+static GLuint _uniform_point_map_uPvmPrev;
+static GLuint _uniform_point_map_uTime;
+static GLuint _uniform_point_map_uTransform;
+static GLuint _uniform_point_map_uCamera;
+static void shader_point_map_uMdl(m4x3f m){
+   glUniformMatrix4x3fv(_uniform_point_map_uMdl,1,GL_FALSE,(float*)m);
+}
+static void shader_point_map_uNormMtx(m3x3f m){
+   glUniformMatrix3fv(_uniform_point_map_uNormMtx,1,GL_FALSE,(float*)m);
+}
+static void shader_point_map_uPv(m4x4f m){
+   glUniformMatrix4fv(_uniform_point_map_uPv,1,GL_FALSE,(float*)m);
+}
+static void shader_point_map_uPvmPrev(m4x4f m){
+   glUniformMatrix4fv(_uniform_point_map_uPvmPrev,1,GL_FALSE,(float*)m);
+}
+static void shader_point_map_uTime(v2f v){
+   glUniform2fv(_uniform_point_map_uTime,1,v);
+}
+static void shader_point_map_uTransform(v4f v){
+   glUniform4fv(_uniform_point_map_uTransform,1,v);
+}
+static void shader_point_map_uCamera(v3f v){
+   glUniform3fv(_uniform_point_map_uCamera,1,v);
+}
+static void shader_point_map_register(void){
+   vg_shader_register( &_shader_point_map );
+}
+static void shader_point_map_use(void){ glUseProgram(_shader_point_map.id); }
+static void shader_point_map_link(void){
+   _uniform_point_map_uMdl = glGetUniformLocation( _shader_point_map.id, "uMdl" );
+   _uniform_point_map_uNormMtx = glGetUniformLocation( _shader_point_map.id, "uNormMtx" );
+   _uniform_point_map_uPv = glGetUniformLocation( _shader_point_map.id, "uPv" );
+   _uniform_point_map_uPvmPrev = glGetUniformLocation( _shader_point_map.id, "uPvmPrev" );
+   _uniform_point_map_uTime = glGetUniformLocation( _shader_point_map.id, "uTime" );
+   _uniform_point_map_uTransform = glGetUniformLocation( _shader_point_map.id, "uTransform" );
+   _uniform_point_map_uCamera = glGetUniformLocation( _shader_point_map.id, "uCamera" );
+}
+#endif /* SHADER_point_map_H */
index 2edd7dc5231a84d5fa148270f815b124dbeb2e2b..daac040234cbfd89f99c2c063f26a6b159680ba6 100644 (file)
@@ -31,6 +31,7 @@
 #include "network.h"
 #include "menu.h"
 #include "vehicle.h"
+#include "pointcloud.h"
 
 static struct player_avatar localplayer_avatar;
 static struct player_model  localplayer_models[3];
@@ -106,6 +107,7 @@ VG_STATIC void vg_load(void)
 
    vg_loader_step( render_init, NULL );
    vg_loader_step( menu_init, NULL );
+   vg_loader_step( pointcloud_init, NULL );
    vg_loader_step( world_init, NULL );
    vg_loader_step( vehicle_init, NULL );
    vg_loader_step( font3d_init, NULL );
index b2d208c96ede3378878602445e89cb6d3396ddc3..b76fd1dc69d52b8c085d6ab837223cec1bbf10ae 100644 (file)
@@ -9,6 +9,7 @@ struct{
       k_async_op_clientloading,
       k_async_op_world_preloading,
       k_async_op_world_loading,
+      k_async_op_cloud_loading,
       k_workshop_form_op_loading_model,
       k_workshop_form_op_downloading_submission,
       k_workshop_form_op_publishing_update,
@@ -19,16 +20,10 @@ struct{
 }
 static skaterift = { .async_op = k_async_op_clientloading };
 
-
 /* Skaterift api */
-
 static void skaterift_change_world( const char *world_path );
 static int  skaterift_change_world_command( int argc, const char *argv[] );
 
-
-
-
-
 /*
  * Start a new operation or crash if we are already running one. you can avoid
  * crashing the game by checking the async status yourself before calling.
index 6cae853576ec97cee25c020bc35c29ef848bb3bc..b5b06e54b3783c3212e1e5bdce1dfb8de533de7f 100644 (file)
@@ -104,6 +104,7 @@ VG_STATIC void world_apply_procedural_foliage( world_instance *world,
    float area = volume[0]*volume[2];
    u32 particles = 0.08f * area;
 
+   /* TODO: Quasirandom? */
    vg_info( "Map area: %f. Max particles: %u\n", area, particles );
 
    for( u32 i=0; i<particles; i++ ){
index 9308daa3b6a9e74cc660cbf3afcb97dedab47cae..62fe06913bb1e8da83347c9b00dd325c5c0e3e67 100644 (file)
@@ -9,6 +9,7 @@
 #include "world.h"
 #include "world_gate.h"
 #include "font.h"
+#include "pointcloud.h"
 
 #if 0
 #include "shaders/vblend.h"
@@ -230,7 +231,9 @@ VG_STATIC void world_routes_debug( world_instance *world )
 
 VG_STATIC 
 void world_routes_place_curve( world_instance *world,
-                               v4f h[3], v3f n0, v3f n2, scene_context *scene )
+                               v4f h[3], v3f n0, v3f n2, scene_context *scene,
+                               struct pointcloud_vert *points, 
+                               u32 *point_count, v4f colour )
 {
    float t;
    v3f p, pd;
@@ -290,6 +293,37 @@ void world_routes_place_curve( world_instance *world,
 
       int resa = ray_world( world, sa, down, &ha ),
           resb = ray_world( world, sb, down, &hb );
+      
+      for( u32 j=0; j<10; j++ ){
+      if( *point_count < POINTCLOUD_POINTS ){
+         struct pointcloud_vert *vert = &points[*point_count];
+         *point_count = (*point_count) + 1;
+
+         v3f sample, jitter, pcpoint;
+         vg_rand_sphere( jitter );
+         v3_muladds( ha.pos, jitter, 8.0f, sample );
+
+         if( bh_closest_point( world->geo_bh, sample, pcpoint, 10.0f ) == -1 ){
+            v3_copy( sample, pcpoint );
+         }
+
+         v3f pos, vol;
+         v3_sub( world->scene_geo.bbx[1], world->scene_geo.bbx[0], vol );
+         v3_sub( pcpoint, world->scene_geo.bbx[0], pos );
+         v3_div( pos, vol, pos );
+
+         for( u32 i=0; i<3; i++ ){
+            vert->pos[i] = vg_clampf(pos[i], 0.0f,1.0f) * 65535.0f;
+            vert->norm[i] = ha.normal[i] * 127.0f;
+         }
+
+         float dist = 1.0f-(v3_length(jitter));
+
+         for( u32 i=0; i<4; i++ ){
+            vert->colour[i] = colour[i] * 255.0f * dist*dist;
+         }
+      }
+      }
 
       if( resa && resb ){
          struct world_surface *surfa = ray_hit_surface( world, &ha ),
@@ -346,9 +380,17 @@ void world_routes_place_curve( world_instance *world,
 
 VG_STATIC 
 void world_routes_create_mesh( world_instance *world, u32 route_id, 
-                               scene_context *sc )
+                               scene_context *sc,
+                               struct pointcloud_vert *points, 
+                               u32 *point_count )
 {
    ent_route *route = mdl_arritm( &world->ent_route, route_id );
+   u8 colour[4];
+   colour[0] = route->colour[0] * 255.0f;
+   colour[1] = route->colour[1] * 255.0f;
+   colour[2] = route->colour[2] * 255.0f;
+   colour[3] = route->colour[3] * 255.0f;
+
    u32 last_valid = 0;
 
    for( int i=0; i<route->checkpoints_count; i++ ){
@@ -451,7 +493,8 @@ void world_routes_create_mesh( world_instance *world, u32 route_id,
          v3_normalize( n0 );
          v3_normalize( n2 );
 
-         world_routes_place_curve( world, p, n0, n2, sc );
+         world_routes_place_curve( world, p, n0, n2, sc, points, point_count,
+                                   route->colour );
 
          /* --- */
          v4_copy( p[2], p[0] );
@@ -461,15 +504,25 @@ void world_routes_create_mesh( world_instance *world, u32 route_id,
    scene_copy_slice( sc, &route->sm );
 }
 
+VG_STATIC 
+struct world_surface *world_tri_index_surface( world_instance *world, 
+                                                 u32 index );
 /* 
  * Create the strips of colour that run through the world along course paths
  */
 VG_STATIC void world_routes_generate( world_instance *world )
 {
    vg_info( "Generating route meshes\n" );
+   vg_async_stall();
+
+   vg_rand_seed( 2000 );
    vg_async_item *call = scene_alloc_async( &world->scene_lines, 
                                             &world->mesh_route_lines,
                                             200000, 300000 );
+   vg_async_item *call1 = 
+      vg_async_alloc( sizeof(struct pointcloud_vert)*POINTCLOUD_POINTS );
+   u32 generated_points = 0;
+   struct pointcloud_vert *cloud_data = call1->payload;
 
    for( u32 i=0; i<mdl_arrcount(&world->ent_gate); i++ ){
       ent_gate *gate = mdl_arritm( &world->ent_gate, i );
@@ -510,10 +563,118 @@ VG_STATIC void world_routes_generate( world_instance *world )
       }
    }
 
-   for( u32 i=0; i<mdl_arrcount(&world->ent_route); i++ )
-      world_routes_create_mesh( world, i, &world->scene_lines );
+   for( u32 i=0; i<mdl_arrcount(&world->ent_route); i++ ){
+      world_routes_create_mesh( world, i, &world->scene_lines,
+                                cloud_data, &generated_points );
+   }
+
+
+   {
+   vg_info( "Executing awesome algorithm!\n" );
+
+   f32 accum = 0.0f;
+   
+   v3f vol;
+   v3_sub( world->scene_geo.bbx[1], world->scene_geo.bbx[0], vol );
+   v3_div( (v3f){1.0f,1.0f,1.0f}, vol, vol );
+
+   u8 colour[] = { 80,80,80,255 };
+   v3f light_dir = {0.3f,0.8f,0.1f};
+   v3_normalize( light_dir );
+
+   for( u32 k=1; k<=10; k++ ){
+      f32 rate = 50.0f * (1.0f/(float)k);
+
+      for( u32 i=0; i<world->scene_geo.indice_count/3; i++ ){
+         u32 *tri = &world->scene_geo.arrindices[i*3];
+         struct world_surface *surf = world_tri_index_surface( world, tri[0] );
+
+         if( surf->info.shader == k_shader_boundary ||
+             surf->info.shader == k_shader_invisible ) continue;
+
+         if( !(surf->info.flags & k_material_flag_preview_visibile) ) continue;
+
+         scene_vert *va = &world->scene_geo.arrvertices[tri[0]],
+                    *vb = &world->scene_geo.arrvertices[tri[1]],
+                    *vc = &world->scene_geo.arrvertices[tri[2]];
+
+         v3f v0, v1, vn;
+         v3_sub( vb->co, va->co, v0 );
+         v3_sub( vc->co, va->co, v1 );
+         v3_cross( v0, v1, vn );
+         if( vn[1] < 0.0f ) continue;
+
+         accum += v3_length(vn)*0.5f;
 
+         v3_normalize( vn );
+
+         while( accum > rate ){
+            accum -= rate;
+
+            if( generated_points >= POINTCLOUD_POINTS ){
+               goto too_many_points;
+            }
+
+            v2f co = { vg_randf64(), vg_randf64() };
+            if( v2_length2(co) > 0.5f ){
+               co[0] = 1.0f-co[0];
+               co[1] = 1.0f-co[1];
+            }
+
+            v3f pt;
+            v3_muls( v0, co[0], pt );
+            v3_muladds( pt, v1, co[1], pt );
+            v3_add( va->co, pt, pt );
+
+            if( pt[1] < world->water.height ) continue;
+            struct pointcloud_vert *vert = &cloud_data[generated_points ++];
+
+            v3f pos;
+            v3_sub( pt, world->scene_geo.bbx[0], pos );
+            v3_mul( pos, vol, pos );
+
+            for( u32 j=0; j<3; j++ ){
+               vert->pos[j] = vg_clampf(pos[j],0.0f,1.0f) * 65535.0f;
+               vert->norm[j] = vg_clampf(vn[j],-1.0f,1.0f) * 127.0f;
+            }
+
+            f32 brightness = vg_clampf( v3_dot( vn, light_dir ), 0.0f, 1.0f );
+
+            v4f col = {0.0f,0.0f,0.0f,0.0f};
+            if( surf->info.surface_prop == k_surface_prop_wood ){
+               v4_copy( (v4f){0.66f,0.6f,0.5f}, col );
+            }
+            else if( surf->info.surface_prop == k_surface_prop_grass ){
+               v4_copy( (v4f){0.42f,0.5f,0.33f}, col );
+            }
+            else if( surf->info.surface_prop == k_surface_prop_concrete ){
+               v4_copy( (v4f){0.57f,0.57f,0.55f}, col );
+            }
+            else if( surf->info.surface_prop == k_surface_prop_metal ){
+               v4_copy( (v4f){0.76f,0.76f,0.75f}, col );
+            }
+            else{
+               v4_copy( (v4f){0.2f,0.2f,0.2f}, col );
+            }
+
+            v4_copy( (v4f){0.2f,0.2f,0.26f}, col );
+            v3_muls( col, brightness*0.25f, col );
+
+            for( u32 j=0; j<4; j++ ){
+               vert->colour[j] = col[j] * 255.0f;
+            }
+         }
+      }
+   }
+
+too_many_points:
+   vg_info( "finished awesome algorithm! yipee (%u)!\n", generated_points );
+   }
+
+   call1->size = generated_points;
    vg_async_dispatch( call, async_scene_upload );
+   vg_async_dispatch( call1, async_pointcloud_sub );
+
    world_routes_clear( world );
 }