From: hgn Date: Sat, 30 Jul 2022 10:14:12 +0000 (+0100) Subject: routes X-Git-Url: https://harrygodden.com/git/?a=commitdiff_plain;h=d57b7661518800479c00300ce57407378696eec9;hp=1c97cb161f885ad24d3356d92c8f4fd0e252bc61;p=carveJwlIkooP6JGAAIwe30JlM.git routes --- diff --git a/blender_export.py b/blender_export.py index 8424753..e52757b 100644 --- a/blender_export.py +++ b/blender_export.py @@ -77,7 +77,7 @@ class mdl_header(Structure): class classtype_gate(Structure): _pack_ = 1 _fields_ = [("target",c_uint32), - ("target1",c_uint32)] + ("dims",c_float*3)] class classtype_block(Structure): _pack_ = 1 @@ -100,6 +100,21 @@ class classtype_instance(Structure): _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 # ============================================================================== @@ -223,6 +238,15 @@ def write_model(name): 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': @@ -269,6 +293,28 @@ def write_model(name): 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: @@ -283,8 +329,15 @@ def write_model(name): 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 @@ -452,22 +505,48 @@ def cv_draw(): 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 @@ -481,14 +560,70 @@ def cv_draw(): 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 @@ -513,6 +648,31 @@ def cv_draw(): 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)) @@ -527,30 +687,100 @@ def cv_draw(): 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', \ @@ -587,7 +817,10 @@ class CV_OBJ_SETTINGS(bpy.types.PropertyGroup): ('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): @@ -604,9 +837,19 @@ 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 @@ -615,6 +858,10 @@ class CV_OBJ_PANEL(bpy.types.Panel): _.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" diff --git a/character.h b/character.h index 3858f24..df05295 100644 --- a/character.h +++ b/character.h @@ -913,9 +913,6 @@ static void character_debug_ragdoll( struct character *ch ) 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; iragdoll[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; diff --git a/common.h b/common.h index c22fd45..952b51d 100644 --- a/common.h +++ b/common.h @@ -17,7 +17,10 @@ enum classtype 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 */ diff --git a/main.c b/main.c index d8a2ceb..e053c42 100644 --- a/main.c +++ b/main.c @@ -276,7 +276,7 @@ static void render_main_game(void) { 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(); diff --git a/model.h b/model.h index 4fdd860..f8b09b8 100644 --- a/model.h +++ b/model.h @@ -83,6 +83,7 @@ struct classtype_block struct classtype_gate { u32 target; + v3f dims; }; struct classtype_spawn @@ -105,6 +106,22 @@ struct classtype_instance 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) /* diff --git a/models/ch_default.mdl b/models/ch_default.mdl index 4257a58..f425d65 100644 Binary files a/models/ch_default.mdl and b/models/ch_default.mdl differ diff --git a/models/cubeh.mdl b/models/cubeh.mdl index 66380cb..9f0a845 100644 Binary files a/models/cubeh.mdl and b/models/cubeh.mdl differ diff --git a/models/epic_scene.mdl b/models/epic_scene.mdl new file mode 100644 index 0000000..7b868e2 Binary files /dev/null and b/models/epic_scene.mdl differ diff --git a/models/mp_dev.mdl b/models/mp_dev.mdl index 65cfcf4..6e1b704 100644 Binary files a/models/mp_dev.mdl and b/models/mp_dev.mdl differ diff --git a/models/rs_vig.mdl b/models/rs_vig.mdl index 37bde7b..1a31cd9 100644 Binary files a/models/rs_vig.mdl and b/models/rs_vig.mdl differ diff --git a/physics_test.h b/physics_test.h index d3b9f06..33a6b6b 100644 --- a/physics_test.h +++ b/physics_test.h @@ -19,6 +19,26 @@ rigidbody blocky = .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, @@ -100,6 +120,30 @@ static void physics_test_start(void) 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; inode_count; i++ ) + { + mdl_node *pnode = mdl_node_from_id( mdl, i ); + + for( int j=0; jsubmesh_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) @@ -107,7 +151,6 @@ 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 ); @@ -117,20 +160,11 @@ static void physics_test_update(void) rb_debug( &blocky, 0xffcccccc ); rb_debug( &jeff1, 0xff00ffff ); - for( int i=0; i= 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}; @@ -493,8 +460,17 @@ static void player_physics(void) else { for( int i=0; i 0.5f ) diff --git a/rigidbody.h b/rigidbody.h index 14bc060..2714c43 100644 --- a/rigidbody.h +++ b/rigidbody.h @@ -93,6 +93,7 @@ static struct contact 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; @@ -163,7 +164,8 @@ static void rb_init( rigidbody *rb ) } 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 ); @@ -424,6 +426,136 @@ static void closest_on_triangle( v3f p, v3f tri[3], v3f dest ) 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 * @@ -911,7 +1043,8 @@ static int rb_sphere_vs_scene( rigidbody *rba, rigidbody *rbb, rb_ct *buf ) 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 ) @@ -924,6 +1057,166 @@ static int rb_sphere_vs_scene( rigidbody *rba, rigidbody *rbb, rb_ct *buf ) 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; iindices[ 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; jn ); + 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", @@ -947,13 +1240,18 @@ static int rb_box_vs_sphere( rigidbody *rba, rigidbody *rbb, rb_ct *buf ) 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 ) @@ -1279,7 +1577,7 @@ static void rb_standard_impulse( rb_ct *ct, v3f da, v3f db, v3f impulse ) */ 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; ivertex_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 ); @@ -130,7 +136,7 @@ static void scene_add_submesh( scene *pscene, mdl_header *mdl, *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 ); diff --git a/shaders/alphatest.h b/shaders/alphatest.h new file mode 100644 index 0000000..3039b48 --- /dev/null +++ b/shaders/alphatest.h @@ -0,0 +1,228 @@ +#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 world_traffic.h */ +#include "world_routes.h" #include "shaders/terrain.h" #include "shaders/sky.h" @@ -23,6 +25,7 @@ static int ray_world( v3f pos, v3f dir, ray_hit *hit ); #include "shaders/vblend.h" #include "shaders/gpos.h" #include "shaders/fscolour.h" +#include "shaders/alphatest.h" static struct gworld { @@ -36,6 +39,13 @@ 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; @@ -43,17 +53,18 @@ static struct gworld 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; @@ -76,12 +87,18 @@ static struct gworld } 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++ ) @@ -105,6 +122,7 @@ static void world_register(void) shader_planeinf_register(); shader_gpos_register(); shader_fscolour_register(); + shader_alphatest_register(); } static void world_free(void) @@ -153,9 +171,8 @@ static void add_all_if_material( m4x3f transform, scene *pscene, } } -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; @@ -197,8 +214,6 @@ static void world_apply_foliage(void) } } } - - scene_upload( &world.foliage ); free( mfoliage ); } @@ -208,7 +223,6 @@ static void world_load(void) world.spawn_count = 0; world.gate_count = 0; - world.rb_count = 0; world.traffic_count = 0; world.instance_cache = NULL; @@ -221,6 +235,7 @@ static void world_load(void) if( pnode->classtype == k_classtype_none ) {} +#if 0 else if( pnode->classtype == k_classtype_gate ) { struct classtype_gate *entgate = mdl_get_entdata( mworld, pnode ); @@ -240,21 +255,7 @@ static void world_load(void) 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 ++ ]; @@ -345,15 +346,17 @@ static void world_load(void) } } } - + 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; imaterial_count; i++ ) { @@ -375,11 +379,10 @@ static void world_load(void) 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 ); @@ -400,7 +403,24 @@ static void world_load(void) 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; inode_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; inode_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; inode_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; igate_count; i++ ) + { + struct route_gate *rg = &r->gates[i]; + world_id_fixup( &rg->node_id, mdl ); + } + + for( int i=0; iroute_count; i++ ) + { + struct route *route = &r->routes[i]; + world_id_fixup( &route->start, mdl ); + } +} + +#endif /* ROUTES_H */