class classtype_gate(Structure):
_pack_ = 1
_fields_ = [("target",c_uint32),
- ("target1",c_uint32)]
+ ("dims",c_float*3)]
class classtype_block(Structure):
_pack_ = 1
_pack_ = 1
_fields_ = [("pstr_file",c_uint32)]
+class classtype_capsule(Structure):
+ _pack_ = 1
+ _fields_ = [("height",c_float),
+ ("radius",c_float)]
+
+class classtype_route_node(Structure):
+ _pack_ = 1
+ _fields_ = [("target",c_uint32),
+ ("target1",c_uint32)]
+
+class classtype_route(Structure):
+ _pack_ = 1
+ _fields_ = [("pstr_name",c_uint32),
+ ("id_start",c_uint32)]
+
# Exporter
# ==============================================================================
if obj.cv_data.target != None:
gate.target = obj.cv_data.target.cv_data.uid
+ if obj.type == 'MESH':
+ gate.dims[0] = obj.data.cv_data.v0[0]
+ gate.dims[1] = obj.data.cv_data.v0[1]
+ gate.dims[2] = obj.data.cv_data.v0[2]
+ else:
+ gate.dims[0] = obj.cv_data.v0[0]
+ gate.dims[1] = obj.cv_data.v0[1]
+ gate.dims[2] = obj.cv_data.v0[2]
+
entdata_buffer += [gate]
elif classtype == 'k_classtype_block':
inst = classtype_instance()
inst.pstr_file = emplace_string( F"models/{target.name}.mdl" )
entdata_buffer += [inst]
+ elif classtype == 'k_classtype_capsule':
+ node.classtype = 7
+ elif classtype == 'k_classtype_route_node':
+ node.classtype = 8
+ entdata_length += sizeof( classtype_route_node )
+
+ rn = classtype_route_node()
+ if obj.cv_data.target != None:
+ rn.target = obj.cv_data.target.cv_data.uid
+ if obj.cv_data.target1 != None:
+ rn.target1 = obj.cv_data.target1.cv_data.uid
+
+ entdata_buffer += [rn]
+ elif classtype == 'k_classtype_route':
+ node.classtype = 9
+ entdata_length += sizeof( classtype_route )
+ r = classtype_route()
+ r.pstr_name = emplace_string("not-implemented")
+ if obj.cv_data.target != None:
+ r.target = obj.cv_data.target.cv_data.uid
+
+ entdata_buffer += [r]
# classtype == 'k_classtype_none':
else:
if obj.type == 'MESH':
default_mat = c_uint32(69)
default_mat.name = ""
-
- if obj.data.name in mesh_cache:
+
+ # Dont use the cache if we have modifiers that affect the normals
+ #
+ use_cache = True
+ for mod in obj.modifiers:
+ if mod.type == 'DATA_TRANSFER':
+ use_cache = False
+
+ if use_cache and obj.data.name in mesh_cache:
ref = mesh_cache[obj.data.name]
node.submesh_start = ref.submesh_start
node.submesh_count = ref.submesh_count
gpu.state.depth_mask_set(False)
gpu.state.line_width_set(2.0)
gpu.state.face_culling_set('BACK')
- gpu.state.depth_test_set('NONE')
+ gpu.state.depth_test_set('LESS')
gpu.state.blend_set('NONE')
verts = []
colours = []
- def drawbezier(p0,h0,p1,h1,c0,c1):
+ #def drawbezier(p0,h0,p1,h1,c0,c1):
+ # nonlocal verts, colours
+
+ # verts += [p0]
+ # verts += [h0]
+ # colours += [(0.5,0.5,0.5,1.0),(0.5,0.5,0.5,1)]
+ # verts += [p1]
+ # verts += [h1]
+ # colours += [(1.0,1.0,1,1),(1,1,1,1)]
+ #
+ # last = p0
+ # for i in range(10):
+ # t = (i+1)/10
+ # a0 = 1-t
+
+ # tt = t*t
+ # ttt = tt*t
+ # p=ttt*p1+(3*tt-3*ttt)*h1+(3*ttt-6*tt+3*t)*h0+(3*tt-ttt-3*t+1)*p0
+ # verts += [(last[0],last[1],last[2])]
+ # verts += [(p[0],p[1],p[2])]
+ # colours += [c0*a0+c1*(1-a0),c0*a0+c1*(1-a0)]
+ # last = p
+
+ course_count = 0
+
+ def drawbhandle(obj, direction, colour):
nonlocal verts, colours
-
+ p0 = obj.location
+ h0 = obj.matrix_world @ Vector((0,direction,0))
verts += [p0]
verts += [h0]
- colours += [(0.5,0.5,0.5,1.0),(0.5,0.5,0.5,1)]
- verts += [p1]
- verts += [h1]
- colours += [(1.0,1.0,1,1),(1,1,1,1)]
-
+ colours += [colour,colour]
+
+ def drawbezier(p0,h0,p1,h1,c0,c1):
+ nonlocal verts, colours
+
last = p0
for i in range(10):
t = (i+1)/10
colours += [c0*a0+c1*(1-a0),c0*a0+c1*(1-a0)]
last = p
+ def drawsbpath(o0,o1,c0,c1,s0,s1):
+ nonlocal course_count
+
+ offs = ((course_count % 2)*2-1) * course_count * 0.02
+
+ p0 = o0.matrix_world @ Vector((offs, 0,0))
+ h0 = o0.matrix_world @ Vector((offs, s0,0))
+ p1 = o1.matrix_world @ Vector((offs, 0,0))
+ h1 = o1.matrix_world @ Vector((offs,-s1,0))
+ drawbezier(p0,h0,p1,h1,c0,c1)
+
+ def drawbpath(o0,o1,c0,c1):
+ drawsbpath(o0,o1,c0,c1,1.0,1.0)
+
+ def drawbline(o0,o1,c0,c1):
+ nonlocal verts, colours
+ verts += [o0.location]
+ verts += [o1.location]
+ colours += [c0,c1]
+
for obj in bpy.context.collection.objects:
- if obj.cv_data.classtype == 'k_classtype_gate':
+ if obj.cv_data.classtype == 'k_classtype_gate' and False:
if obj.cv_data.target != None:
p0 = obj.location
p1 = obj.cv_data.target.location
- verts += [(p0[0],p0[1],p0[2])]
- verts += [(p1[0],p1[1],p1[2])]
- colours += [(0,1,0,1.0),(1,0,0,1.0)]
+
+ for i in range(20):
+ t = i/20.0
+ t1 = (i+0.5)/20.0
+
+ pa = p0*t+p1*(1.0-t)
+ pb = p0*t1+p1*(1.0-t1)
+
+ verts += [(pa[0],pa[1],pa[2])]
+ verts += [(pb[0],pb[1],pb[2])]
+ colours += [(0,1,0,1.0),(1,0,0,1.0)]
+
+ if obj.type == 'MESH':
+ dims = obj.data.cv_data.v0
+ else:
+ dims = obj.cv_data.v0
+
+ vs = [None]*9
+ c = Vector((0,0,dims[2]))
+
+ vs[0] = obj.matrix_world @ Vector((-dims[0],0.0,-dims[1]+dims[2]))
+ vs[1] = obj.matrix_world @ Vector((-dims[0],0.0, dims[1]+dims[2]))
+ vs[2] = obj.matrix_world @ Vector(( dims[0],0.0, dims[1]+dims[2]))
+ vs[3] = obj.matrix_world @ Vector(( dims[0],0.0,-dims[1]+dims[2]))
+ vs[4] = obj.matrix_world @ (c+Vector((-1,0,-2)))
+ vs[5] = obj.matrix_world @ (c+Vector((-1,0, 2)))
+ vs[6] = obj.matrix_world @ (c+Vector(( 1,0, 2)))
+ vs[7] = obj.matrix_world @ (c+Vector((-1,0, 0)))
+ vs[8] = obj.matrix_world @ (c+Vector(( 1,0, 0)))
+
+ indices = [(0,1),(1,2),(2,3),(3,0),(4,5),(5,6),(7,8)]
+
+ for l in indices:
+ v0 = vs[l[0]]
+ v1 = vs[l[1]]
+ verts += [(v0[0],v0[1],v0[2])]
+ verts += [(v1[0],v1[1],v1[2])]
+ colours += [(1,1,0,1),(1,1,0,1)]
+
elif obj.cv_data.classtype == 'k_classtype_block':
a = obj.data.cv_data.v0
b = obj.data.cv_data.v1
verts += [(v1[0],v1[1],v1[2])]
colours += [(1,1,0,1),(1,1,0,1)]
+ elif obj.cv_data.classtype == 'k_classtype_capsule':
+ h = obj.data.cv_data.v0[0]
+ r = obj.data.cv_data.v0[1]
+
+ vs = [None]*10
+ vs[0] = obj.matrix_world @ Vector((0.0,0.0, h*0.5 ))
+ vs[1] = obj.matrix_world @ Vector((0.0,0.0,-h*0.5 ))
+ vs[2] = obj.matrix_world @ Vector(( r,0.0, h*0.5-r))
+ vs[3] = obj.matrix_world @ Vector(( -r,0.0, h*0.5-r))
+ vs[4] = obj.matrix_world @ Vector(( r,0.0,-h*0.5+r))
+ vs[5] = obj.matrix_world @ Vector(( -r,0.0,-h*0.5+r))
+ vs[6] = obj.matrix_world @ Vector((0.0, r , h*0.5-r))
+ vs[7] = obj.matrix_world @ Vector((0.0,-r , h*0.5-r))
+ vs[8] = obj.matrix_world @ Vector((0.0, r ,-h*0.5+r))
+ vs[9] = obj.matrix_world @ Vector((0.0,-r ,-h*0.5+r))
+
+ indices = [(0,1),(2,3),(4,5),(6,7),(8,9)]
+
+ for l in indices:
+ v0 = vs[l[0]]
+ v1 = vs[l[1]]
+ verts += [(v0[0],v0[1],v0[2])]
+ verts += [(v1[0],v1[1],v1[2])]
+ colours += [(0.5,1,0,1),(0.5,1,0,1)]
+
elif obj.cv_data.classtype == 'k_classtype_spawn':
vs = [None]*4
vs[0] = obj.matrix_world @ Vector((0,0,0))
verts += [(v1[0],v1[1],v1[2])]
colours += [(0,1,1,1),(0,1,1,1)]
- elif obj.cv_data.classtype == 'k_classtype_car_path':
- p0 = obj.location
- h0 = obj.matrix_world @ Vector((1,0,0))
+ elif obj.cv_data.classtype == 'k_classtype_route':
+ vs = [None]*2
+ vs[0] = obj.location
+ vs[1] = obj.cv_data.target.location
+ indices = [(0,1)]
+ for l in indices:
+ v0 = vs[l[0]]
+ v1 = vs[l[1]]
+ verts += [(v0[0],v0[1],v0[2])]
+ verts += [(v1[0],v1[1],v1[2])]
+ colours += [(0,1,1,1),(0,1,1,1)]
+
+ stack = [None]*64
+ stack_i = [0]*64
+ stack[0] = obj.cv_data.target
+ si = 1
+ loop_complete = False
+
+ while si > 0:
+ node = stack[si-1]
+
+ targets = [None,None]
+ targets[0] = node.cv_data.target
+
+ if node.cv_data.classtype == 'k_classtype_route_node':
+ targets[1] = node.cv_data.target1
+
+ nextnode = targets[stack_i[si-1]]
+ stack_i[si-1] += 1
+
+ if nextnode != None: # branch
+ if nextnode == stack[0]: # Loop completed
+ loop_complete = True
+ break
+
+ valid=True
+ for sj in range(si):
+ if stack[sj] == nextnode: # invalidated path
+ valid=False
+ break
+
+ if valid:
+ stack_i[si] = 0
+ stack[si] = nextnode
+ si += 1
+ continue
+
+ if stack_i[si-1] == 2:
+ si -= 1
+
+ if si == 0: # Loop failed to complete
+ break
- v0 = obj.matrix_world.to_quaternion() @ Vector((1,0,0))
+ if loop_complete:
+ course_colours = [Vector((0,0.8,0.2,1.0)), \
+ Vector((0,0.3,0.9,1.0)), \
+ Vector((0.4,0.0,0.8,1.0)),\
+ Vector((0.5,0.8,0.0,1.0)),\
+ Vector((0.0,0.7,0.6,1.0)),\
+ Vector((0.2,0.9,0.5,1.0)) ]
+
+ cc = course_colours[ course_count % len(course_colours) ]
+
+ for sj in range(si):
+ sk = (sj+1)%si
+
+ if stack[sj].cv_data.classtype == 'k_classtype_gate' and \
+ stack[sk].cv_data.classtype == 'k_classtype_gate':
+ dist = (stack[sj].location-stack[sk].location).magnitude
+ drawsbpath( stack[sj], stack[sk], cc*0.4, cc, dist, dist )
+
+ else:
+ drawbpath( stack[sj], stack[sk], cc, cc )
+
+ course_count += 1
+
+ elif obj.cv_data.classtype == 'k_classtype_car_path':
+ v0 = obj.matrix_world.to_quaternion() @ Vector((0,1,0))
c0 = Vector((v0.x*0.5+0.5, v0.y*0.5+0.5, 0.0, 1.0))
+ drawbhandle( obj, 1.0, (0.9,0.9,0.9,1.0) )
if obj.cv_data.target != None:
- p1 = obj.cv_data.target.location
- h1 = obj.cv_data.target.matrix_world @ Vector((-1,0,0))
-
- v1 = obj.cv_data.target.matrix_world.to_quaternion()@Vector((1,0,0))
+ v1 = obj.cv_data.target.matrix_world.to_quaternion()@Vector((0,1,0))
c1 = Vector((v1.x*0.5+0.5, v1.y*0.5+0.5, 0.0, 1.0))
- drawbezier( p0, h0, p1, h1, c0, c1 )
+ drawbhandle( obj.cv_data.target, -1.0, (0.5,0.5,0.5,1.0) )
+ drawbpath( obj, obj.cv_data.target, c0, c1 )
if obj.cv_data.target1 != None:
- p1 = obj.cv_data.target1.location
- h1 = obj.cv_data.target1.matrix_world @ Vector((-1,0,0))
-
- v1 = obj.cv_data.target1.matrix_world.to_quaternion()@Vector((1,0,0))
+ v1 = obj.cv_data.target1.matrix_world.to_quaternion()@Vector((0,1,0))
c1 = Vector((v1.x*0.5+0.5, v1.y*0.5+0.5, 0.0, 1.0))
- drawbezier( p0, h0, p1, h1, c0, c1 )
+ drawbhandle( obj.cv_data.target1, -1.0, (0.5,0.5,0.5,1.0) )
+ drawbpath( obj, obj.cv_data.target1, c0, c1 )
lines = batch_for_shader(\
cv_view_shader, 'LINES', \
('k_classtype_block', "k_classtype_block", "", 2),
('k_classtype_spawn', "k_classtype_spawn", "", 3),
('k_classtype_water', "k_classtype_water", "", 4),
- ('k_classtype_car_path', "k_classtype_car_path", "", 5)
+ ('k_classtype_car_path', "k_classtype_car_path", "", 5),
+ ('k_classtype_capsule', "k_classtype_capsule", "", 7 ),
+ ('k_classtype_route_node', "k_classtype_route_node", "", 8 ),
+ ('k_classtype_route', "k_classtype_route", "", 9 )
])
class CV_OBJ_PANEL(bpy.types.Panel):
if active_object.cv_data.classtype == 'k_classtype_gate':
_.layout.prop( active_object.cv_data, "target" )
- elif active_object.cv_data.classtype == 'k_classtype_car_path':
+
+ mesh = active_object.data
+ _.layout.label( text=F"(i) Data is stored in {mesh.name}" )
+ _.layout.prop( mesh.cv_data, "v0" )
+
+ elif active_object.cv_data.classtype == 'k_classtype_car_path' or \
+ active_object.cv_data.classtype == 'k_classtype_route_node':
_.layout.prop( active_object.cv_data, "target" )
_.layout.prop( active_object.cv_data, "target1" )
+
+ elif active_object.cv_data.classtype == 'k_classtype_route':
+ _.layout.prop( active_object.cv_data, "target" )
+
elif active_object.cv_data.classtype == 'k_classtype_block':
mesh = active_object.data
_.layout.prop( mesh.cv_data, "v1" )
_.layout.prop( mesh.cv_data, "v2" )
_.layout.prop( mesh.cv_data, "v3" )
+ elif active_object.cv_data.classtype == 'k_classtype_capsule':
+ mesh = active_object.data
+ _.layout.label( text=F"(i) Data is stored in {mesh.name}" )
+ _.layout.prop( mesh.cv_data, "v0" )
class CV_INTERFACE(bpy.types.Panel):
bl_idname = "VIEW3D_PT_carve"
static void character_ragdoll_iter( struct character *ch )
{
- /* TODO: Lots of the RB functions unimplemented here currently */
-
- return;
rb_solver_reset();
for( int i=0; i<PART_COUNT; i++ )
shoe_vel[i] = v3_length( ch->ragdoll[i].v );
/* This used to be 20 iterations */
- for( int i=0; i<5; i++ )
+ for( int i=0; i<10; i++ )
{
float const k_springfactor = 1.0f/20.0f;
k_classtype_spawn = 3,
k_classtype_water = 4,
k_classtype_car_path = 5,
- k_classtype_instance = 6
+ k_classtype_instance = 6,
+ k_classtype_capsule = 7,
+ k_classtype_route_node = 8,
+ k_classtype_route = 9
};
/* TODO: he needs a home somewhere */
{
m4x4_projection( vg_pv, gpipeline.fov,
(float)vg_window_x / (float)vg_window_y,
- 0.01f, 100.0f );
+ 0.04f, 600.0f );
m4x4_mul( vg_pv, world_4x4, vg_pv );
}
draw_player();
struct classtype_gate
{
u32 target;
+ v3f dims;
};
struct classtype_spawn
u32 pstr_file;
};
+struct classtype_capsule
+{
+ float height, radius;
+};
+
+struct classtype_route_node
+{
+ u32 target, target1;
+};
+
+struct classtype_route
+{
+ u32 pstr_name;
+ u32 id_start;
+};
+
#pragma pack(pop)
/*
.is_world = 1
};
+rigidbody marko =
+{
+ .type = k_rb_shape_box,
+ .bbx = {{-0.5f,-0.5f,-0.5f},{0.5f,0.5f,0.5f}},
+ .co = {-36.0f,8.0f,-36.0f},
+ .q = {0.0f,0.0f,0.0f,1.0f},
+ .is_world = 0
+};
+
+scene epic_scene;
+
+rigidbody epic_scene_rb =
+{
+ .type = k_rb_shape_scene,
+ .co = {0.0f,0.0f,0.0f},
+ .q = {0.0f,0.0f,0.0f,1.0f},
+ .is_world = 1,
+ .inf.scene = { .pscene = &epic_scene }
+};
+
rigidbody funnel[4] = {
{
.type = k_rb_shape_box,
rb_init( &ball1 );
rb_init( &jeff1 );
rb_init( &blocky );
+
+ scene_init( &epic_scene );
+
+ mdl_header *mdl = mdl_load( "models/epic_scene.mdl" );
+
+ m4x3f transform;
+ m4x3_identity( transform );
+
+ for( int i=0; i<mdl->node_count; i++ )
+ {
+ mdl_node *pnode = mdl_node_from_id( mdl, i );
+
+ for( int j=0; j<pnode->submesh_count; j++ )
+ {
+ mdl_submesh *sm = mdl_node_submesh( mdl, pnode, j );
+ scene_add_submesh( &epic_scene, mdl, sm, transform );
+ }
+ }
+
+ free( mdl );
+ scene_bh_create( &epic_scene );
+
+ rb_init( &epic_scene_rb );
+ rb_init( &marko );
}
static void physics_test_update(void)
player_freecam();
player_camera_update();
-
for( int i=0; i<4; i++ )
rb_debug( &funnel[i], 0xff0060e0 );
rb_debug( &ground, 0xff00ff00 );
rb_debug( &blocky, 0xffcccccc );
rb_debug( &jeff1, 0xff00ffff );
- for( int i=0; i<vg_list_size(jeffs); i++ )
- {
- rb_debug( &jeffs[i], (u32[]){ 0xff0000ff, 0xff00ff00, 0xff00ffff,
- 0xffff0000, 0xffff00ff, 0xffffff00,
- }[i%6] );
- rb_iter( jeffs+i );
- }
+ rb_debug( &epic_scene_rb, 0xffcccccc );
+ rb_debug( &marko, 0xffffcc00 );
{
- rb_iter( &ball );
- rb_iter( &ball1 );
- rb_iter( &jeff1 );
-
rb_solver_reset();
for( int i=0; i<4; i++ )
rb_collide( &ball, &ground );
rb_collide( &ball1, &ground );
rb_collide( &ball1, &ball );
+ rb_collide( &marko, &epic_scene_rb );
rb_presolve_contacts( rb_contact_buffer, rb_contact_count );
for( int i=0; i<8; i++ )
rb_solve_contacts( rb_contact_buffer, rb_contact_count );
+
+ /* ITERATE */
+ {
for( int i=0; i<vg_list_size(jeffs); i++ )
{
- rb_update_transform(jeffs+i);
+ rb_debug( &jeffs[i], (u32[]){ 0xff0000ff, 0xff00ff00, 0xff00ffff,
+ 0xffff0000, 0xffff00ff, 0xffffff00,
+ }[i%6] );
+ rb_iter( jeffs+i );
}
- rb_update_transform( &ball );
- rb_update_transform( &ball1 );
- rb_update_transform( &jeff1 );
-
+ rb_iter( &ball );
+ rb_iter( &ball1 );
+ rb_iter( &jeff1 );
+ rb_iter( &marko );
}
-
+
+ /* POSITION OVERRIDE */
+ {
if(glfwGetKey( vg_window, GLFW_KEY_L ))
{
- m4x3_mulv( player.camera, (v3f){0.0f,0.0f,-5.0f}, jeff1.co );
- v3_zero( jeff1.v );
- v3_zero( jeff1.w );
+ m4x3_mulv( player.camera, (v3f){0.0f,0.0f,-5.0f}, marko.co );
+ v3_zero( marko.v );
+ v3_zero( marko.w );
}
if(glfwGetKey( vg_window, GLFW_KEY_K ))
{
{
reorg_jeffs();
}
+ }
+
+ /* UPDATE TRANSFORMS */
+ for( int i=0; i<vg_list_size(jeffs); i++ )
+ {
+ rb_update_transform(jeffs+i);
+ }
+
+ rb_update_transform( &ball );
+ rb_update_transform( &ball1 );
+ rb_update_transform( &jeff1 );
+ rb_update_transform( &marko );
+
+ }
}
static void physics_test_render(void)
len += rb_sphere_vs_scene( rbf, &world.rb_geo, manifold+len );
len += rb_sphere_vs_scene( rbb, &world.rb_geo, manifold+len );
-#if 0
- for( int i=0; i<len; i++ )
- {
- u32 *ptri = &world.geo.indices[ geo[i]*3 ];
-
- for( int j=0; j<3; j++ )
- v3_copy( world.geo.verts[ptri[j]].co, tri[j] );
-
- vg_line(tri[0],tri[1],0xff00ff00 );
- vg_line(tri[1],tri[2],0xff00ff00 );
- vg_line(tri[2],tri[0],0xff00ff00 );
-
- v3f temp;
- v3_copy( player.rb.co, temp );
-
- for( int j=0; j<2; j++ )
- {
- if(manifold_count >= vg_list_size(manifold))
- {
- vg_error("Manifold overflow!\n");
- break;
- }
-
- rb_ct *ct = &manifold[manifold_count];
- v3_copy( poles[j], player.rb.co );
-
- manifold_count += rb_sphere_vs_triangle( &player.rb, tri, ct );
- }
-
- v3_copy( temp, player.rb.co );
- }
-#endif
-
rb_presolve_contacts( manifold, len );
v3f surface_avg = {0.0f, 0.0f, 0.0f};
else
{
for( int i=0; i<len; i++ )
+ {
v3_add( manifold[i].n, surface_avg, surface_avg );
+ if( manifold[i].element_id <= world.sm_geo_std_oob.vertex_count )
+ {
+ player.is_dead = 1;
+ character_ragdoll_copypose( &player.mdl, player.rb.v );
+ return;
+ }
+ }
+
v3_normalize( surface_avg );
if( v3_dot( player.rb.v, surface_avg ) > 0.5f )
v3f co, n;
v3f t[2];
float mass_total, p, bias, norm_impulse, tangent_impulse[2];
+ u32 element_id;
}
rb_contact_buffer[256];
static int rb_contact_count = 0;
}
else
{
- rb->inv_mass = 1.0f/(8.0f*volume);
+ rb->inv_mass = 1.0f/(8.0f*volume); /* TODO: Things get weird when mass
+ passes a certain point??? */
}
v3_zero( rb->v );
v3_muladds( dest, ac, w, dest );
}
+/* TODO */
+static void closest_on_triangle_1( v3f p, v3f tri[3], v3f dest )
+{
+ v3f ab, ac, ap;
+ float d1, d2;
+
+ /* Region outside A */
+ v3_sub( tri[1], tri[0], ab );
+ v3_sub( tri[2], tri[0], ac );
+ v3_sub( p, tri[0], ap );
+
+ d1 = v3_dot(ab,ap);
+ d2 = v3_dot(ac,ap);
+ if( d1 <= 0.0f && d2 <= 0.0f )
+ {
+ v3_copy( tri[0], dest );
+ return;
+ }
+
+ /* Region outside B */
+ v3f bp;
+ float d3, d4;
+
+ v3_sub( p, tri[1], bp );
+ d3 = v3_dot( ab, bp );
+ d4 = v3_dot( ac, bp );
+
+ if( d3 >= 0.0f && d4 <= d3 )
+ {
+ v3_copy( tri[1], dest );
+ return;
+ }
+
+ /* Edge region of AB */
+ float vc = d1*d4 - d3*d2;
+ if( vc <= 0.0f && d1 >= 0.0f && d3 <= 0.0f )
+ {
+ float v = d1 / (d1-d3);
+ v3_muladds( tri[0], ab, v, dest );
+ return;
+ }
+
+ /* Region outside C */
+ v3f cp;
+ float d5, d6;
+ v3_sub( p, tri[2], cp );
+ d5 = v3_dot(ab, cp);
+ d6 = v3_dot(ac, cp);
+
+ if( d6 >= 0.0f && d5 <= d6 )
+ {
+ v3_copy( tri[2], dest );
+ return;
+ }
+
+ /* Region of AC */
+ float vb = d5*d2 - d1*d6;
+ if( vb <= 0.0f && d2 >= 0.0f && d6 <= 0.0f )
+ {
+ float w = d2 / (d2-d6);
+ v3_muladds( tri[0], ac, w, dest );
+ return;
+ }
+
+ /* Region of BC */
+ float va = d3*d6 - d5*d4;
+ if( va <= 0.0f && (d4-d3) >= 0.0f && (d5-d6) >= 0.0f )
+ {
+ float w = (d4-d3) / ((d4-d3) + (d5-d6));
+ v3f bc;
+ v3_sub( tri[2], tri[1], bc );
+ v3_muladds( tri[1], bc, w, dest );
+ return;
+ }
+
+ /* P inside region, Q via barycentric coordinates uvw */
+ float d = 1.0f/(va+vb+vc),
+ v = vb*d,
+ w = vc*d;
+
+ v3_muladds( tri[0], ab, v, dest );
+ v3_muladds( dest, ac, w, dest );
+}
+
+static int rb_intersect_planes( v4f p0, v4f p1, v4f p2, v3f p )
+{
+ v3f u;
+ v3_cross( p1, p2, u );
+ float d = v3_dot( p0, u );
+
+ if( fabsf(d) < 0.0001f )
+ return 0;
+
+ v3_muls( u, p0[3], p );
+
+ v3f v0, v1;
+ v3_muls( p1, p2[3], v0 );
+ v3_muladds( v0, p2, -p1[3], v0 );
+ v3_cross( p0, v0, v1 );
+ v3_add( v1, p, p );
+ v3_muls( p, 1.0f/d, p );
+
+ return 1;
+}
+
+int rb_intersect_planes_1( v4f a, v4f b, v4f c, v3f p )
+{
+ float const epsilon = 0.001;
+
+ v3f x, bc, ca, ab;
+ float d;
+
+ v3_cross( a, b, x );
+ d = v3_dot( x, c );
+
+ if( d < epsilon && d > -epsilon ) return 0;
+
+ v3_cross(b,c,bc);
+ v3_cross(c,a,ca);
+ v3_cross(a,b,ab);
+
+ v3_muls( bc, -a[3], p );
+ v3_muladds( p, ca, -b[3], p );
+ v3_muladds( p, ab, -c[3], p );
+
+ v3_negate( p, p );
+ v3_divs( p, d, p );
+
+ return 1;
+}
/*
* Contact generators
*
vg_line(tri[0],tri[1],0xff00ff00 );
vg_line(tri[1],tri[2],0xff00ff00 );
vg_line(tri[2],tri[0],0xff00ff00 );
-
+
+ buf[count].element_id = ptri[0];
count += rb_sphere_vs_triangle( rba, rbb, tri, buf+count );
if( count == 12 )
return count;
}
+static float rb_box_plane_interval( rigidbody *rba, v4f p )
+{
+ /* TODO: Make boxes COG aligned as is every other shape.
+ * or create COG vector.
+ * TODO: Make forward actually point in the right fucking direction. */
+ v3f e,c;
+ v3_sub( rba->bbx[1], rba->bbx[0], e );
+ v3_muls( e, 0.5f, e );
+ v3_add( rba->bbx[0], e, c );
+ m4x3_mulv( rba->to_world, c, c );
+
+ float r =
+ e[0]*fabsf( v3_dot(p, rba->right)) +
+ e[1]*fabsf( v3_dot(p, rba->up)) +
+ e[2]*fabsf(-v3_dot(p, rba->forward)),
+ s = v3_dot( p, c ) - p[3];
+
+ return r-s;
+}
+
+static int rb_box_vs_scene( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
+{
+#if 1
+ scene *sc = rbb->inf.scene.pscene;
+
+ u32 geo[128];
+ v3f tri[3];
+ int len = bh_select( &sc->bhtris, rba->bbx_world, geo, 128 );
+
+ vg_info( "%d\n", len );
+
+ int count = 0;
+
+ for( int i=0; i<len; i++ )
+ {
+ u32 *ptri = &sc->indices[ geo[i]*3 ];
+
+ for( int j=0; j<3; j++ )
+ v3_copy( sc->verts[ptri[j]].co, tri[j] );
+
+ vg_line(tri[0],tri[1],0xff00ff00 );
+ vg_line(tri[1],tri[2],0xff00ff00 );
+ vg_line(tri[2],tri[0],0xff00ff00 );
+
+ //count += rb_sphere_vs_triangle( rba, rbb, tri, buf+count );
+ //
+
+ /* TODO: SAT test first */
+
+ /*
+ * each pair of faces on the box vs triangle normal
+ */
+
+ v3f v0, v1;
+ v4f tn;
+
+ v3_sub( tri[1],tri[0], v0 );
+ v3_sub( tri[2],tri[0], v1 );
+ v3_cross( v0, v1, tn );
+ v3_normalize( tn );
+
+ tn[3] = v3_dot( tn, tri[0] );
+
+ v4f pa, pb, pc, pd, pe, pf;
+ v3_copy( rba->right, pa );
+ v3_muls( rba->right, -1.0f, pb );
+ v3_copy( rba->up, pc );
+ v3_muls( rba->up, -1.0f, pd );
+ v3_copy( rba->forward, pf );
+ v3_muls( rba->forward, -1.0f, pe );
+
+ float dx = v3_dot( rba->co, rba->right ),
+ dy = v3_dot( rba->co, rba->up ),
+ dz = -v3_dot( rba->co, rba->forward );
+
+ pa[3] = dx + rba->bbx[1][0];
+ pb[3] = -dx - rba->bbx[0][0];
+ pc[3] = dy + rba->bbx[1][1];
+ pd[3] = -dy - rba->bbx[0][1];
+ pe[3] = dz + rba->bbx[1][2];
+ pf[3] = -dz - rba->bbx[0][2];
+
+ float *pairs[][2] = { {pc, pa}, {pc,pe}, {pc,pb}, {pc,pf},
+ {pd, pa}, {pd,pe}, {pd,pb}, {pd,pf},
+ {pf, pa}, {pa,pe}, {pe,pb}, {pb,pf}};
+ for( int j=0; j<vg_list_size(pairs); j++ )
+ {
+ v3f p;
+
+ if( rb_intersect_planes_1( pairs[j][0], pairs[j][1], tn, p ))
+ {
+ v3f p_tri, p_box;
+ closest_point_obb( p, rba, p_box );
+ closest_on_triangle_1( p, tri, p_tri );
+
+ //vg_line_pt3( p, 0.1f, 0xffeeaaff );
+
+ if( v3_dist( p_tri, p ) < 0.001f && v3_dist( p_box, p ) < 0.001f )
+ {
+ if( count == 12 )
+ {
+ vg_warn( "Exceeding box_vs_scene capacity."
+ "Geometry too dense!\n" );
+ return count;
+ }
+
+ rb_ct *ct = buf+count;
+
+ v3_copy( tn, ct->n );
+ v3_copy( p_box, ct->co );
+
+ ct->p = rb_box_plane_interval( rba, tn );
+ ct->rba = rba;
+ ct->rbb = rbb;
+ count ++;
+ }
+ }
+ }
+ }
+#else
+
+ v3f pts[8];
+ float *p000 = pts[0], *p001 = pts[1], *p010 = pts[2], *p011 = pts[3],
+ *p100 = pts[4], *p101 = pts[5], *p110 = pts[6], *p111 = pts[7];
+
+ p000[0]=rba->bbx[0][0];p000[1]=rba->bbx[0][1];p000[2]=rba->bbx[0][2];
+ p001[0]=rba->bbx[0][0];p001[1]=rba->bbx[0][1];p001[2]=rba->bbx[1][2];
+ p010[0]=rba->bbx[0][0];p010[1]=rba->bbx[1][1];p010[2]=rba->bbx[0][2];
+ p011[0]=rba->bbx[0][0];p011[1]=rba->bbx[1][1];p011[2]=rba->bbx[1][2];
+ p100[0]=rba->bbx[1][0];p100[1]=rba->bbx[0][1];p100[2]=rba->bbx[0][2];
+ p101[0]=rba->bbx[1][0];p101[1]=rba->bbx[0][1];p101[2]=rba->bbx[1][2];
+ p110[0]=rba->bbx[1][0];p110[1]=rba->bbx[1][1];p110[2]=rba->bbx[0][2];
+ p111[0]=rba->bbx[1][0];p111[1]=rba->bbx[1][1];p111[2]=rba->bbx[1][2];
+
+ int count = 0;
+ for( int i=0; i<8; i++ )
+ {
+ m4x3_mulv( rba->to_world, pts[i], pts[i] );
+
+ vg_line_pt3( pts[i], 0.1f, 0xffff00ff );
+
+ if( pts[i][1] < 0.0f )
+ {
+ rb_ct *ct = buf+count;
+
+ v3_copy( (v3f){0.0f,1.0f,0.0f}, ct->n );
+ v3_copy( pts[i], ct->co );
+
+ ct->p = 0.0f-pts[i][1];
+ ct->rba = rba;
+ ct->rbb = rbb;
+ count ++;
+ }
+ }
+
+#endif
+
+ return count;
+}
+
static int RB_MATRIX_ERROR( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
{
vg_error( "Collision type is unimplemented between types %d and %d\n",
return rb_sphere_vs_box( rbb, rba, buf );
}
+static int rb_scene_vs_box( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
+{
+ return rb_box_vs_scene( rbb, rba, buf );
+}
+
static int (*rb_jump_table[4][4])( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
= {
- /* box */ /* Sphere */ /* Capsule */
-/*box */ { RB_MATRIX_ERROR, rb_box_vs_sphere, rb_box_vs_capsule, RB_MATRIX_ERROR },
+ /* box */ /* Sphere */ /* Capsule */ /* Mesh */
+/*box */ { RB_MATRIX_ERROR, rb_box_vs_sphere, rb_box_vs_capsule, rb_box_vs_scene },
/*sphere */ { rb_sphere_vs_box, rb_sphere_vs_sphere, rb_sphere_vs_capsule, rb_sphere_vs_scene },
/*capsule*/ { rb_capsule_vs_box,rb_capsule_vs_sphere,rb_capsule_vs_capsule,RB_MATRIX_ERROR },
-/*mesh */ { RB_MATRIX_ERROR, RB_MATRIX_ERROR, RB_MATRIX_ERROR, RB_MATRIX_ERROR }
+/*mesh */ { rb_scene_vs_box, RB_MATRIX_ERROR, RB_MATRIX_ERROR, RB_MATRIX_ERROR }
};
static int rb_collide( rigidbody *rba, rigidbody *rbb )
*/
static void rb_solve_contacts( rb_ct *buf, int len )
{
- float k_friction = 0.1f;
+ float k_friction = 0.5f;
/* Friction Impulse */
for( int i=0; i<len; i++ )
&pscene->vertex_cap, sm->vertex_count, sizeof(mdl_vert) );
pscene->indices = buffer_reserve( pscene->indices, pscene->indice_count,
&pscene->indice_cap, sm->indice_count, sizeof(u32) );
+
+ m3x3f normal_matrix;
+ m3x3_copy( transform, normal_matrix );
+ v3_normalize( normal_matrix[0] );
+ v3_normalize( normal_matrix[1] );
+ v3_normalize( normal_matrix[2] );
/* Transform and place vertices */
mdl_vert *src_verts = mdl_submesh_vertices( mdl, sm );
*src = &src_verts[ i ];
m4x3_mulv( transform, src->co, pvert->co );
- m3x3_mulv( transform, src->norm, pvert->norm );
+ m3x3_mulv( normal_matrix, src->norm, pvert->norm );
v4_copy( src->colour, pvert->colour );
v2_copy( src->uv, pvert->uv );
--- /dev/null
+#ifndef SHADER_alphatest_H
+#define SHADER_alphatest_H
+static void shader_alphatest_link(void);
+static void shader_alphatest_register(void);
+static struct vg_shader _shader_alphatest = {
+ .name = "alphatest",
+ .link = shader_alphatest_link,
+ .vs =
+{
+.orig_file = "../shaders/standard.vs",
+.static_src =
+"layout (location=0) in vec3 a_co;\n"
+"layout (location=1) in vec3 a_norm;\n"
+"layout (location=2) in vec4 a_colour;\n"
+"layout (location=3) in vec2 a_uv;\n"
+"\n"
+"#line 2 0 \n"
+"\n"
+"uniform mat4 uPv;\n"
+"uniform mat4x3 uMdl;\n"
+"\n"
+"out vec4 aColour;\n"
+"out vec2 aUv;\n"
+"out vec3 aNorm;\n"
+"out vec3 aCo;\n"
+"out vec3 aWorldCo;\n"
+"\n"
+"void main()\n"
+"{\n"
+" vec3 world_pos = uMdl * vec4(a_co,1.0);\n"
+" gl_Position = uPv * vec4( world_pos, 1.0 );\n"
+" aColour = a_colour;\n"
+" aUv = a_uv;\n"
+" aNorm = mat3(uMdl) * a_norm;\n"
+" aCo = a_co;\n"
+" aWorldCo = world_pos;\n"
+"}\n"
+""},
+ .fs =
+{
+.orig_file = "../shaders/std_alphatest.fs",
+.static_src =
+"out vec4 FragColor;\n"
+"\n"
+"uniform sampler2D uTexGarbage;\n"
+"uniform sampler2D uTexMain;\n"
+"uniform vec3 uCamera;\n"
+"uniform vec4 uPlane;\n"
+"\n"
+"in vec4 aColour;\n"
+"in vec2 aUv;\n"
+"in vec3 aNorm;\n"
+"in vec3 aCo;\n"
+"in vec3 aWorldCo;\n"
+"\n"
+"#line 1 1 \n"
+"layout (std140) uniform ub_world_lighting\n"
+"{\n"
+" vec4 g_light_colours[3];\n"
+" vec4 g_light_directions[3];\n"
+" vec4 g_ambient_colour;\n"
+"\n"
+" vec4 g_water_plane;\n"
+" vec4 g_depth_bounds;\n"
+" float g_water_fog;\n"
+" int g_light_count;\n"
+" int g_light_preview;\n"
+"};\n"
+"\n"
+"uniform sampler2D g_world_depth;\n"
+"\n"
+"// Standard diffuse + spec models\n"
+"// ==============================\n"
+"\n"
+"vec3 do_light_diffuse( vec3 vfrag, vec3 wnormal )\n"
+"{\n"
+" vec3 vtotal = g_ambient_colour.rgb;\n"
+"\n"
+" for( int i=0; i<g_light_count; i++ )\n"
+" {\n"
+" vec3 vcolour = g_light_colours[i].rgb;\n"
+" vec3 vdir = g_light_directions[i].xyz;\n"
+"\n"
+" float flight = max(dot( vdir, wnormal )*0.75+0.25,0.0);\n"
+" vtotal += vcolour*flight;\n"
+" }\n"
+"\n"
+" return vfrag * vtotal;\n"
+"}\n"
+"\n"
+"vec3 do_light_spec( vec3 vfrag, vec3 wnormal, vec3 halfview, float fintensity )\n"
+"{\n"
+" vec3 vcolour = g_light_colours[0].rgb;\n"
+" vec3 vdir = g_light_directions[0].xyz;\n"
+"\n"
+" vec3 specdir = reflect( -vdir, wnormal );\n"
+" float spec = pow(max(dot( halfview, specdir ), 0.0), 10.0);\n"
+" return vfrag + vcolour*spec*fintensity;\n"
+"}\n"
+"\n"
+"float world_depth_sample( vec3 pos )\n"
+"{\n"
+" vec2 depth_coord = (pos.xz - g_depth_bounds.xy) * g_depth_bounds.zw; \n"
+" return texture( g_world_depth, depth_coord ).r;\n"
+"}\n"
+"\n"
+"float shadow_sample( vec3 vdir )\n"
+"{\n"
+" vec3 sample_pos = aWorldCo + vdir;\n"
+" float height_sample = world_depth_sample( sample_pos );\n"
+"\n"
+" float fdelta = height_sample - sample_pos.y;\n"
+" return clamp( fdelta, 0.1, 0.2 )-0.1;\n"
+"}\n"
+"\n"
+"vec3 do_light_shadowing_old( vec3 vfrag )\n"
+"{\n"
+" float faccum = 0.0;\n"
+" faccum += shadow_sample( vec3( 0.0, 0.5, 0.0 ));\n"
+" faccum += shadow_sample( vec3( 2.0, 0.3, 0.0 ));\n"
+" faccum += shadow_sample( vec3( 3.0, 1.0, 0.0 ));\n"
+" faccum += shadow_sample( vec3( 5.0, 1.0, 0.0 ));\n"
+" faccum += shadow_sample( vec3( 0.0, 0.5, 0.0 )*1.5);\n"
+" faccum += shadow_sample( vec3( 2.0, 0.3, 0.0 )*1.5);\n"
+" faccum += shadow_sample( vec3( 3.0, 1.0, 0.0 )*1.5);\n"
+" faccum += shadow_sample( vec3( 5.0, 1.0, 0.0 )*1.5);\n"
+" return mix( vfrag, g_ambient_colour.rgb, faccum );\n"
+"}\n"
+"\n"
+"vec3 do_light_shadowing( vec3 vfrag )\n"
+"{\n"
+" float fspread = g_light_colours[0].w;\n"
+" vec3 vdir = g_light_directions[0].xyz;\n"
+" float flength = g_light_directions[0].w;\n"
+"\n"
+" float famt = 0.0;\n"
+" famt+=shadow_sample((vdir+vec3(-0.563, 0.550, 0.307)*fspread)*flength*0.1);\n"
+" famt+=shadow_sample((vdir+vec3( 0.808, 0.686, 0.346)*fspread)*flength*0.2);\n"
+" famt+=shadow_sample((vdir+vec3( 0.787, 0.074,-0.065)*fspread)*flength*0.3);\n"
+" famt+=shadow_sample((vdir+vec3(-0.593, 0.071,-0.425)*fspread)*flength*0.4);\n"
+" famt+=shadow_sample((vdir+vec3(-0.790,-0.933,-0.875)*fspread)*flength*0.5);\n"
+" famt+=shadow_sample((vdir+vec3( 0.807,-0.690, 0.472)*fspread)*flength*0.6);\n"
+" famt+=shadow_sample((vdir+vec3( 0.522,-0.379, 0.350)*fspread)*flength*0.7);\n"
+" famt+=shadow_sample((vdir+vec3( 0.483, 0.201, 0.306)*fspread)*flength*0.8);\n"
+" return mix( vfrag, g_ambient_colour.rgb, famt );\n"
+"}\n"
+"\n"
+"vec3 apply_fog( vec3 vfrag, float fdist )\n"
+"{\n"
+" float dist = pow(fdist*0.0008,1.2);\n"
+" return mix( vfrag, vec3(0.55,0.76,1.0), min( 1.0, dist ) );\n"
+"}\n"
+"\n"
+"#line 15 0 \n"
+"\n"
+"void main()\n"
+"{\n"
+" vec3 vfrag = vec3(0.5,0.5,0.5);\n"
+" vec4 vsamplemain = texture( uTexMain, aUv );\n"
+" vec3 qnorm = normalize(aNorm);\n"
+"\n"
+" if( vsamplemain.a < 0.15 )\n"
+" discard;\n"
+"\n"
+" vfrag = vsamplemain.rgb;\n"
+"\n"
+" if( g_light_preview == 1 )\n"
+" {\n"
+" vfrag = vec3(0.5);\n"
+" }\n"
+"\n"
+" // Lighting\n"
+" vec3 halfview = uCamera - aWorldCo;\n"
+" float fdist = length( halfview );\n"
+" halfview /= fdist;\n"
+"\n"
+" vfrag = do_light_diffuse( vfrag, qnorm );\n"
+" vfrag = do_light_spec( vfrag, qnorm, halfview, 0.1 );\n"
+" vfrag = do_light_shadowing( vfrag );\n"
+" vfrag = apply_fog( vfrag, fdist );\n"
+"\n"
+" FragColor = vec4(vfrag, 1.0);\n"
+"}\n"
+""},
+};
+
+static GLuint _uniform_alphatest_uPv;
+static GLuint _uniform_alphatest_uMdl;
+static GLuint _uniform_alphatest_uTexGarbage;
+static GLuint _uniform_alphatest_uTexMain;
+static GLuint _uniform_alphatest_uCamera;
+static GLuint _uniform_alphatest_uPlane;
+static GLuint _uniform_alphatest_g_world_depth;
+static void shader_alphatest_uPv(m4x4f m){
+ glUniformMatrix4fv( _uniform_alphatest_uPv, 1, GL_FALSE, (float *)m );
+}
+static void shader_alphatest_uMdl(m4x3f m){
+ glUniformMatrix4x3fv( _uniform_alphatest_uMdl, 1, GL_FALSE, (float *)m );
+}
+static void shader_alphatest_uTexGarbage(int i){
+ glUniform1i( _uniform_alphatest_uTexGarbage, i );
+}
+static void shader_alphatest_uTexMain(int i){
+ glUniform1i( _uniform_alphatest_uTexMain, i );
+}
+static void shader_alphatest_uCamera(v3f v){
+ glUniform3fv( _uniform_alphatest_uCamera, 1, v );
+}
+static void shader_alphatest_uPlane(v4f v){
+ glUniform4fv( _uniform_alphatest_uPlane, 1, v );
+}
+static void shader_alphatest_g_world_depth(int i){
+ glUniform1i( _uniform_alphatest_g_world_depth, i );
+}
+static void shader_alphatest_register(void){
+ vg_shader_register( &_shader_alphatest );
+}
+static void shader_alphatest_use(void){ glUseProgram(_shader_alphatest.id); }
+static void shader_alphatest_link(void){
+ _uniform_alphatest_uPv = glGetUniformLocation( _shader_alphatest.id, "uPv" );
+ _uniform_alphatest_uMdl = glGetUniformLocation( _shader_alphatest.id, "uMdl" );
+ _uniform_alphatest_uTexGarbage = glGetUniformLocation( _shader_alphatest.id, "uTexGarbage" );
+ _uniform_alphatest_uTexMain = glGetUniformLocation( _shader_alphatest.id, "uTexMain" );
+ _uniform_alphatest_uCamera = glGetUniformLocation( _shader_alphatest.id, "uCamera" );
+ _uniform_alphatest_uPlane = glGetUniformLocation( _shader_alphatest.id, "uPlane" );
+ _uniform_alphatest_g_world_depth = glGetUniformLocation( _shader_alphatest.id, "g_world_depth" );
+}
+#endif /* SHADER_alphatest_H */
--- /dev/null
+out vec4 FragColor;
+
+uniform sampler2D uTexGarbage;
+uniform sampler2D uTexMain;
+uniform vec3 uCamera;
+uniform vec4 uPlane;
+
+in vec4 aColour;
+in vec2 aUv;
+in vec3 aNorm;
+in vec3 aCo;
+in vec3 aWorldCo;
+
+#include "common_world.glsl"
+
+void main()
+{
+ vec3 vfrag = vec3(0.5,0.5,0.5);
+ vec4 vsamplemain = texture( uTexMain, aUv );
+ vec3 qnorm = normalize(aNorm);
+
+ if( vsamplemain.a < 0.15 )
+ discard;
+
+ vfrag = vsamplemain.rgb;
+
+ if( g_light_preview == 1 )
+ {
+ vfrag = vec3(0.5);
+ }
+
+ // Lighting
+ vec3 halfview = uCamera - aWorldCo;
+ float fdist = length( halfview );
+ halfview /= fdist;
+
+ vfrag = do_light_diffuse( vfrag, qnorm );
+ vfrag = do_light_spec( vfrag, qnorm, halfview, 0.1 );
+ vfrag = do_light_shadowing( vfrag );
+ vfrag = apply_fog( vfrag, fdist );
+
+ FragColor = vec4(vfrag, 1.0);
+}
uniform sampler2D uTexGarbage;
uniform sampler2D uTexGradients;
uniform vec3 uCamera;
-uniform vec4 uPlane;
in vec4 aColour;
in vec2 aUv;
"uniform sampler2D uTexGarbage;\n"
"uniform sampler2D uTexGradients;\n"
"uniform vec3 uCamera;\n"
-"uniform vec4 uPlane;\n"
"\n"
"in vec4 aColour;\n"
"in vec2 aUv;\n"
" return mix( vfrag, vec3(0.55,0.76,1.0), min( 1.0, dist ) );\n"
"}\n"
"\n"
-"#line 15 0 \n"
+"#line 14 0 \n"
"\n"
"void main()\n"
"{\n"
static GLuint _uniform_vblend_uTexGarbage;
static GLuint _uniform_vblend_uTexGradients;
static GLuint _uniform_vblend_uCamera;
-static GLuint _uniform_vblend_uPlane;
static GLuint _uniform_vblend_g_world_depth;
static void shader_vblend_uPv(m4x4f m){
glUniformMatrix4fv( _uniform_vblend_uPv, 1, GL_FALSE, (float *)m );
static void shader_vblend_uCamera(v3f v){
glUniform3fv( _uniform_vblend_uCamera, 1, v );
}
-static void shader_vblend_uPlane(v4f v){
- glUniform4fv( _uniform_vblend_uPlane, 1, v );
-}
static void shader_vblend_g_world_depth(int i){
glUniform1i( _uniform_vblend_g_world_depth, i );
}
_uniform_vblend_uTexGarbage = glGetUniformLocation( _shader_vblend.id, "uTexGarbage" );
_uniform_vblend_uTexGradients = glGetUniformLocation( _shader_vblend.id, "uTexGradients" );
_uniform_vblend_uCamera = glGetUniformLocation( _shader_vblend.id, "uCamera" );
- _uniform_vblend_uPlane = glGetUniformLocation( _shader_vblend.id, "uPlane" );
_uniform_vblend_g_world_depth = glGetUniformLocation( _shader_vblend.id, "g_world_depth" );
}
#endif /* SHADER_vblend_H */
shader fscolour blit.vs colour.fs
shader terrain standard.vs terrain.fs
shader vblend standard.vs vblend.fs
+shader alphatest standard.vs std_alphatest.fs
shader standard standard.vs standard.fs
shader unlit standard.vs unlit.fs
shader character character.vs character.fs
#include "bvh.h"
#include "lighting.h"
#include "model.h"
-#include "traffic.h"
+
+#include "traffic.h" /*TODO: -> world_traffic.h */
+#include "world_routes.h"
#include "shaders/terrain.h"
#include "shaders/sky.h"
#include "shaders/vblend.h"
#include "shaders/gpos.h"
#include "shaders/fscolour.h"
+#include "shaders/alphatest.h"
static struct gworld
{
spawns[32];
u32 spawn_count;
+ struct subworld_routes routes;
+
+ /* ...
+ struct subworld_spawns system_spawns;
+ struct subworld_physics system_physics;
+ */
+
teleport_gate gates[64];
u32 gate_count;
traffic_node traffic[128];
u32 traffic_count;
+#if 0
traffic_driver van_man[6];
+#endif
/* Physics */
- rigidbody temp_rbs[128];
- u32 rb_count;
/* Rendering & geometry */
scene geo, foliage;
rigidbody rb_geo;
- mdl_submesh sm_geo_std_oob, sm_geo_std, sm_geo_vb;
+ mdl_submesh sm_geo_std_oob, sm_geo_std, sm_geo_vb,
+ sm_foliage_main, sm_foliage_alphatest;
glmesh skybox, skydome;
mdl_submesh dome_upper, dome_lower;
}
world;
+static struct subworld_routes *subworld_routes(void) { return &world.routes; }
+
+
vg_tex2d tex_terrain_colours = { .path = "textures/gradients.qoi",
.flags = VG_TEXTURE_CLAMP|VG_TEXTURE_NEAREST };
vg_tex2d tex_terrain_noise = { .path = "textures/garbage.qoi",
.flags = VG_TEXTURE_NEAREST };
+vg_tex2d tex_alphatest = { .path = "textures/alphatest.qoi",
+ .flags = VG_TEXTURE_NEAREST };
+
static void ray_world_get_tri( ray_hit *hit, v3f tri[3] )
{
for( int i=0; i<3; i++ )
shader_planeinf_register();
shader_gpos_register();
shader_fscolour_register();
+ shader_alphatest_register();
}
static void world_free(void)
}
}
-static void world_apply_foliage(void)
+static void world_apply_procedural_foliage(void)
{
- scene_init( &world.foliage );
mdl_header *mfoliage = mdl_load("models/rs_foliage.mdl");
v3f volume;
}
}
}
-
- scene_upload( &world.foliage );
free( mfoliage );
}
world.spawn_count = 0;
world.gate_count = 0;
- world.rb_count = 0;
world.traffic_count = 0;
world.instance_cache = NULL;
if( pnode->classtype == k_classtype_none )
{}
+#if 0
else if( pnode->classtype == k_classtype_gate )
{
struct classtype_gate *entgate = mdl_get_entdata( mworld, pnode );
gate_transform_update( gate );
}
}
- else if( pnode->classtype == k_classtype_block )
- {
- struct classtype_block *block = mdl_get_entdata( mworld, pnode );
-
- m4x3f transform;
- mdl_node_transform( pnode, transform );
-
- rigidbody *rb = &world.temp_rbs[ world.rb_count ++ ];
-
- box_copy( block->bbx, rb->bbx ); /* TODO: apply scale */
- v3_copy( pnode->co, rb->co );
- rb_init( rb );
- v4_copy( pnode->q, rb->q );
- rb_update_transform( rb );
- }
+#endif
else if( pnode->classtype == k_classtype_spawn )
{
struct respawn_point *rp = &world.spawns[ world.spawn_count ++ ];
}
}
}
-
+
world.instance_cache = buffer_fix( world.instance_cache,
world.instance_cache_count,
&world.instance_cache_cap,
sizeof( struct instance_cache ) );
+#if 0
traffic_finalize( world.traffic, world.traffic_count );
for( int i=0; i<vg_list_size(world.van_man); i++ )
world.van_man[i].current =&world.traffic[vg_randint(world.traffic_count)];
+#endif
/*
* Compile meshes into the world scenes
u32 mat_surf = 0,
mat_surf_oob = 0,
- mat_vertex_blend = 0;
+ mat_vertex_blend = 0,
+ mat_alphatest = 0;
for( int i=1; i<mworld->material_count; i++ )
{
mat_surf_oob = i;
else if( !strcmp( "vertex_blend", mat_name ))
mat_vertex_blend = i;
+ else if( !strcmp( "alphatest", mat_name ))
+ mat_alphatest = i;
}
- vg_info( "surf %d\noob %d\nvert_blend %d\n", mat_surf, mat_surf_oob,
- mat_vertex_blend );
-
m4x3f midentity;
m4x3_identity( midentity );
scene_upload( &world.geo );
scene_bh_create( &world.geo );
- world_apply_foliage();
+
+ /* Foliage /nocollide layer.
+ * TODO: Probably should have material traits for this
+ */
+ scene_init( &world.foliage );
+
+ world_apply_procedural_foliage();
+ scene_copy_slice( &world.foliage, &world.sm_foliage_main );
+
+ add_all_if_material( midentity, &world.foliage, mworld, mat_alphatest );
+ scene_copy_slice( &world.foliage, &world.sm_foliage_alphatest );
+
+ scene_upload( &world.foliage );
+ world_routes_init( mworld );
+
+ for( int i=0; i<world.instance_cache_count; i++ )
+ free( world.instance_cache[i].mdl );
+
free( world.instance_cache );
free( mworld );
q_identity(world.mr_ball.q);
rb_init( &world.mr_ball );
+
+ /*
+ * Setup scene collider
+ */
+ v3_zero( world.rb_geo.co );
+ q_identity( world.rb_geo.q );
+
+ world.rb_geo.type = k_rb_shape_scene;
+ world.rb_geo.inf.scene.pscene = &world.geo;
+ world.rb_geo.is_world = 1;
+ rb_init( &world.rb_geo );
}
static void world_init(void)
{
vg_tex2d_init( (vg_tex2d *[]){ &tex_terrain_colours,
- &tex_terrain_noise }, 2 );
+ &tex_terrain_noise,
+ &tex_alphatest }, 3 );
mdl_header *mcars = mdl_load( "models/rs_cars.mdl" );
mdl_unpack_glmesh( mcars, &world.cars );
world.dome_lower = *mdl_node_submesh( msky, nlower, 0 );
world.dome_upper = *mdl_node_submesh( msky, nupper, 0 );
free(msky);
-
- /*
- * Setup scene collider
- */
- v3_zero( world.rb_geo.co );
- q_identity( world.rb_geo.q );
-
- world.rb_geo.type = k_rb_shape_scene;
- world.rb_geo.inf.scene.pscene = &world.geo;
- world.rb_geo.is_world = 1;
- rb_init( &world.rb_geo );
}
static void world_update(void)
{
+ world_routes_debug();
+
#if 0
rb_solver_reset();
rb_build_manifold_terrain_sphere( &world.mr_ball );
rb_iter( &world.mr_ball );
rb_update_transform( &world.mr_ball );
rb_debug( &world.mr_ball, 0 );
-#endif
for( int i=0; i<vg_list_size(world.van_man); i++ )
{
traffic_drive( &world.van_man[i] );
traffic_visualize_car( &world.van_man[i] );
}
+#endif
}
/*
mesh_bind( &world.cars );
+#if 0
for( int i=0; i<vg_list_size(world.van_man); i++ )
{
shader_vblend_uMdl( world.van_man[i].transform );
mdl_draw_submesh( &world.car_holden );
}
+#endif
+}
+
+static void render_world_alphatest( m4x4f projection, v3f camera )
+{
+ m4x3f identity_matrix;
+ m4x3_identity( identity_matrix );
+
+ shader_alphatest_use();
+ shader_alphatest_uTexGarbage(0);
+ shader_alphatest_uTexMain(1);
+ shader_link_standard_ub( _shader_alphatest.id, 2 );
+
+ vg_tex2d_bind( &tex_terrain_noise, 0 );
+ vg_tex2d_bind( &tex_alphatest, 1 );
+
+ shader_alphatest_uPv( projection );
+ shader_alphatest_uMdl( identity_matrix );
+ shader_alphatest_uCamera( camera );
+
+ glDisable(GL_CULL_FACE);
+ scene_bind( &world.foliage );
+ mdl_draw_submesh( &world.sm_foliage_alphatest );
+ glEnable(GL_CULL_FACE);
}
static void render_terrain( m4x4f projection, v3f camera )
mdl_draw_submesh( &world.sm_geo_std_oob );
mdl_draw_submesh( &world.sm_geo_std );
+ /* TODO: Dont draw in reflection */
glDisable(GL_CULL_FACE);
scene_bind( &world.foliage );
- scene_draw( &world.foliage );
+ mdl_draw_submesh( &world.sm_foliage_main );
glEnable(GL_CULL_FACE);
}
{
render_sky( camera );
render_world_vb( projection, camera[3] );
+ render_world_alphatest( projection, camera[3] );
render_terrain( projection, camera[3] );
}
--- /dev/null
+#ifndef ROUTES_H
+#define ROUTES_H
+
+#include "common.h"
+#include "model.h"
+#include "gate.h"
+
+struct subworld_routes
+{
+ struct route_node
+ {
+ v3f co, right, h;
+ u32 next[2];
+
+ u32 is_gate, gate_id;
+ }
+ *nodes;
+
+ u32 node_count,
+ node_cap;
+
+ struct route
+ {
+ const char *name;
+ v4f colour;
+
+ u32 start;
+ }
+ *routes;
+
+ u32 route_count,
+ route_cap;
+
+ struct route_gate
+ {
+ teleport_gate gate;
+
+ u32 route_ids[4]; /* Gates can be linked into up to four routes */
+ u32 route_count,
+ node_id;
+ }
+ *gates;
+
+ u32 gate_count,
+ gate_cap;
+};
+
+static struct subworld_routes *subworld_routes(void);
+
+/*
+ * TODO list:
+ * when a gate is passed through it needs to trigger into an active state
+ */
+
+static void world_routes_debug(void)
+{
+ struct subworld_routes *r = subworld_routes();
+
+ for( int i=0; i<r->node_count; i++ )
+ {
+ struct route_node *rn = &r->nodes[i];
+ vg_line_pt3( rn->co, 1.0f, rn->is_gate? 0xffffff00: 0xff00b2ff );
+ }
+}
+
+static void world_routes_free(void)
+{
+ struct subworld_routes *r = subworld_routes();
+
+ free( r->nodes );
+ free( r->routes );
+ free( r->gates );
+}
+
+static void world_id_fixup( u32 *uid, mdl_header *mdl )
+{
+ if( *uid )
+ *uid = mdl_node_from_id( mdl, *uid )->sub_uid;
+}
+
+static void world_routes_init( mdl_header *mdl )
+{
+ struct subworld_routes *r = subworld_routes();
+ r->nodes = NULL;
+ r->node_count = 0;
+ r->node_cap = 0;
+ r->routes = NULL;
+ r->route_count = 0;
+ r->route_cap = 0;
+ r->gates = NULL;
+ r->gate_count = 0;
+ r->gate_cap = 0;
+
+ for( int i=0; i<mdl->node_count; i++ )
+ {
+ mdl_node *pnode = mdl_node_from_id(mdl,i);
+ m4x3f transform;
+
+ if( pnode->classtype == k_classtype_route_node ||
+ pnode->classtype == k_classtype_gate )
+ {
+ mdl_node_transform( pnode, transform );
+ pnode->sub_uid = r->node_count;
+
+ r->nodes = buffer_reserve( r->nodes, r->node_count, &r->node_cap, 1,
+ sizeof( struct route_node ) );
+
+ struct route_node *rn = &r->nodes[r->node_count];
+
+ v3_copy( transform[0], rn->right );
+ v3_normalize( rn->right );
+ v3_copy( transform[2], rn->h );
+ v3_copy( transform[3], rn->co );
+
+ if( pnode->classtype == k_classtype_gate )
+ {
+ r->gates = buffer_reserve( r->gates, r->gate_count, &r->gate_cap,
+ 1, sizeof( struct route_gate ) );
+
+ struct classtype_gate *inf = mdl_get_entdata( mdl, pnode );
+
+ /* H is later scaled based on link distance */
+ v3_normalize( rn->h );
+ rn->next[0] = inf->target;
+ rn->next[1] = 0;
+ rn->gate_id = r->gate_count;
+ rn->is_gate = 1;
+
+ struct route_gate *rg = &r->gates[r->gate_count];
+ rg->node_id = r->node_count;
+
+ /* TODO */
+
+ r->gate_count ++;
+ }
+ else
+ {
+ struct classtype_route_node *inf = mdl_get_entdata( mdl, pnode );
+ rn->next[0] = inf->target;
+ rn->next[1] = inf->target1;
+ rn->is_gate = 0;
+ }
+
+ r->node_count ++;
+ }
+ else if( pnode->classtype == k_classtype_route )
+ {
+ struct classtype_route *inf = mdl_get_entdata( mdl, pnode );
+ r->routes = buffer_reserve( r->routes, r->route_count, &r->route_cap,
+ 1, sizeof( struct route ) );
+
+ struct route *route = &r->routes[r->route_count];
+
+ v4_zero( route->colour );
+ route->name = NULL;
+ route->start = inf->id_start;
+
+ r->route_count ++;
+ }
+ }
+
+ /*
+ * Apply correct system-local ids
+ */
+ for( int i=0; i<r->node_count; i++ )
+ {
+ struct route_node *rn = &r->nodes[i];
+
+ for( int j=0; j<2; j++ )
+ world_id_fixup( &rn->next[j], mdl );
+
+ if( rn->is_gate )
+ world_id_fixup( &rn->gate_id, mdl );
+ }
+
+ for( int i=0; i<r->gate_count; i++ )
+ {
+ struct route_gate *rg = &r->gates[i];
+ world_id_fixup( &rg->node_id, mdl );
+ }
+
+ for( int i=0; i<r->route_count; i++ )
+ {
+ struct route *route = &r->routes[i];
+ world_id_fixup( &route->start, mdl );
+ }
+}
+
+#endif /* ROUTES_H */