From: hgn Date: Fri, 28 Oct 2022 02:15:02 +0000 (+0100) Subject: refactor model things X-Git-Url: https://harrygodden.com/git/?a=commitdiff_plain;ds=sidebyside;h=be6707a307bfeec1b45cca8b3fb647e81262be87;p=carveJwlIkooP6JGAAIwe30JlM.git refactor model things --- diff --git a/audio.h b/audio.h index 34ebb3a..26c1a35 100644 --- a/audio.h +++ b/audio.h @@ -9,10 +9,10 @@ #include "world.h" -static float audio_occlusion_current = 0.0f, +VG_STATIC float audio_occlusion_current = 0.0f, k_audio_occlusion_rate = 1.0f; -static int k_audio_debug_soundscape = 0; +VG_STATIC int k_audio_debug_soundscape = 0; audio_clip audio_board[] = { @@ -141,7 +141,7 @@ audio_player audio_player_gate = .name = "Gate" }; -static void audio_init(void) +VG_STATIC void audio_init(void) { audio_player_init( &audio_player0 ); audio_player_init( &audio_player1 ); @@ -156,19 +156,19 @@ static void audio_init(void) audio_player_init( &audio_player_extra ); audio_player_init( &audio_rewind_player ); - audio_clip_loadn( audio_board, vg_list_size(audio_board) ); - audio_clip_loadn( audio_ambience, vg_list_size(audio_ambience) ); - audio_clip_loadn( &audio_splash, 1 ); - audio_clip_loadn( &audio_gate_pass, 1 ); - audio_clip_loadn( &audio_gate_lap, 1 ); - audio_clip_loadn( &audio_gate_ambient, 1 ); - audio_clip_loadn( audio_jumps, vg_list_size(audio_jumps) ); - audio_clip_loadn( audio_lands, vg_list_size(audio_lands) ); - audio_clip_loadn( audio_water, vg_list_size(audio_water) ); - audio_clip_loadn( audio_grass, vg_list_size(audio_grass) ); - audio_clip_loadn( audio_footsteps, vg_list_size(audio_footsteps) ); - audio_clip_loadn( audio_rewind, vg_list_size(audio_rewind) ); - audio_clip_loadn( audio_ui, vg_list_size(audio_ui) ); + audio_clip_loadn( audio_board, vg_list_size(audio_board), NULL ); + audio_clip_loadn( audio_ambience, vg_list_size(audio_ambience), NULL ); + audio_clip_loadn( &audio_splash, 1, NULL ); + audio_clip_loadn( &audio_gate_pass, 1, NULL ); + audio_clip_loadn( &audio_gate_lap, 1, NULL ); + audio_clip_loadn( &audio_gate_ambient, 1, NULL ); + audio_clip_loadn( audio_jumps, vg_list_size(audio_jumps), NULL ); + audio_clip_loadn( audio_lands, vg_list_size(audio_lands), NULL ); + audio_clip_loadn( audio_water, vg_list_size(audio_water), NULL ); + audio_clip_loadn( audio_grass, vg_list_size(audio_grass), NULL ); + audio_clip_loadn( audio_footsteps, vg_list_size(audio_footsteps), NULL ); + audio_clip_loadn( audio_rewind, vg_list_size(audio_rewind), NULL ); + audio_clip_loadn( audio_ui, vg_list_size(audio_ui), NULL ); audio_lock(); u32 flags = AUDIO_FLAG_LOOP|AUDIO_FLAG_SPACIAL_3D; @@ -215,13 +215,13 @@ static void audio_init(void) }); } -static void audio_free(void*_) +VG_STATIC void audio_free(void*_) { /* TODO! */ vg_warn( "UNIMPLEMENTED: audio_free()\n" ); } -static void audio_sample_occlusion( v3f origin ) +VG_STATIC void audio_sample_occlusion( v3f origin ) { float d = 0.0f, sample_dist = 880.0f; @@ -280,7 +280,7 @@ enum audio_sprite_type /* * Trace out a random point, near the player to try and determine water areas */ -static enum audio_sprite_type audio_sample_sprite_random( v3f origin, +VG_STATIC enum audio_sprite_type audio_sample_sprite_random( v3f origin, v3f output ) { v3f chance = { (vg_randf()-0.5f) * 30.0f, @@ -314,7 +314,7 @@ static enum audio_sprite_type audio_sample_sprite_random( v3f origin, return k_audio_sprite_type_water; } -static void audio_debug_soundscapes(void) +VG_STATIC void audio_debug_soundscapes(void) { if( !k_audio_debug_soundscape ) return; diff --git a/blender_export.py b/blender_export.py index a7e714c..ce4e826 100644 --- a/blender_export.py +++ b/blender_export.py @@ -1,5 +1,20 @@ +# +# ============================================================================= +# +# Copyright . . . -----, ,----- ,---. .---. +# 2021-2022 |\ /| | / | | | | /| +# | \ / | +-- / +----- +---' | / | +# | \ / | | / | | \ | / | +# | \/ | | / | | \ | / | +# ' ' '--' [] '----- '----- ' ' '---' SOFTWARE +# +# ============================================================================= +# +# Python exporter for Blender, compiles .mdl format for Skate Rift. # -# Copyright (C) 2021-2022 Mt.ZERO Software, Harry Godden - All Rights Reserved +# Its really slow, sorry, I don't know how to speed it up. +# Also not sure why you need to put # before {} in code blocks, there is errors +# otherwise # import bpy, math, gpu @@ -116,17 +131,29 @@ class mdl_keyframe(Structure): ("s",c_float*3)] #} -# Entity types -# ========================================== +# ---------------------------------------------------------------------------- # +# # +# Entity definitions # +# # +# ---------------------------------------------------------------------------- # # # ctypes _fields_ defines the data which is filled in by: # def encode_obj( _, node, node_def ): # # gizmos get drawn into the viewport via: # @staticmethod -# def editor_interface( object ): +# def draw_scene_helpers( obj ): +# +# editor enterface, simiraliy: +# @staticmethod +# def editor_interface( layout, obj ): # +# Classtype 1 +# +# Purpose: A rift. must target another gate, the target gate can not have more +# than one target nodes of its own. +# class classtype_gate(Structure): #{ _pack_ = 1 @@ -155,8 +182,62 @@ class classtype_gate(Structure): _.dims[2] = obj.cv_data.v0[2] #} #} + + @staticmethod + def draw_scene_helpers( obj ): + #{ + global cv_view_verts, cv_view_colours + + 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]] + cv_view_verts += [(v0[0],v0[1],v0[2])] + cv_view_verts += [(v1[0],v1[1],v1[2])] + cv_view_colours += [(1,1,0,1),(1,1,0,1)] + + sw = (0.4,0.4,0.4,0.2) + if obj.cv_data.target != None: + cv_draw_arrow( obj.location, obj.cv_data.target.location, sw ) + #} + + @staticmethod + def editor_interface( layout, obj ): + #{ + layout.prop( obj.cv_data, "target" ) + + mesh = obj.data + layout.label( text=F"(i) Data is stored in {mesh.name}" ) + layout.prop( mesh.cv_data, "v0", text="Gate dimensions" ) + #} #} +# Classtype 3 +# +# Purpose: player can reset here, its a safe place +# spawns can share the same name, the closest one will be picked +# +# when the world loads it will pick the one named 'start' first. +# class classtype_spawn(Structure): #{ _pack_ = 1 @@ -167,8 +248,41 @@ class classtype_spawn(Structure): node.classtype = 3 _.pstr_alias = encoder_process_pstr( node_def['obj'].cv_data.strp ) #} + + @staticmethod + def draw_scene_helpers( obj ): + #{ + global cv_view_verts, cv_view_colours + + vs = [None]*4 + vs[0] = obj.matrix_world @ Vector((0,0,0)) + vs[1] = obj.matrix_world @ Vector((0,2,0)) + vs[2] = obj.matrix_world @ Vector((0.5,1,0)) + vs[3] = obj.matrix_world @ Vector((-0.5,1,0)) + indices = [(0,1),(1,2),(1,3)] + + for l in indices: + #{ + v0 = vs[l[0]] + v1 = vs[l[1]] + + cv_view_verts += [(v0[0],v0[1],v0[2])] + cv_view_verts += [(v1[0],v1[1],v1[2])] + cv_view_colours += [(0,1,1,1),(0,1,1,1)] + #} + #} + + @staticmethod + def editor_interface( layout, obj ): + #{ + layout.prop( obj.cv_data, "strp", text="Alias" ) + #} #} +# Classtype 4 +# +# Purpose: Tells the game to draw water HERE, at this entity. +# class classtype_water(Structure): #{ _pack_ = 1 @@ -181,6 +295,10 @@ class classtype_water(Structure): #} #} +# Classtype 8 +# +# Purpose: Defines a route node and links to up to two more nodes +# class classtype_route_node(Structure): #{ _pack_ = 1 @@ -197,12 +315,44 @@ class classtype_route_node(Structure): if obj.cv_data.target1 != None: _.target1 = obj.cv_data.target1.cv_data.uid #} + + @staticmethod + def draw_scene_helpers( obj ): + #{ + global cv_view_verts, cv_view_colours + + sw = Vector((0.4,0.4,0.4,0.2)) + sw2 = Vector((1.5,0.2,0.2,0.0)) + if obj.cv_data.target != None: + cv_draw_bpath( obj, obj.cv_data.target, sw, sw ) + if obj.cv_data.target1 != None: + cv_draw_bpath( obj, obj.cv_data.target1, sw, sw ) + + cv_draw_bhandle( obj, 1.0, (0.8,0.8,0.8,1.0) ) + cv_draw_bhandle( obj, -1.0, (0.4,0.4,0.4,1.0) ) + + p1 = obj.location+ \ + obj.matrix_world.to_quaternion() @ Vector((0,0,-6+1.5)) + cv_draw_arrow( obj.location, p1, sw ) + #} + + @staticmethod + def editor_interface( layout, obj ): + #{ + layout.prop( obj.cv_data, "target", text="Left" ) + layout.prop( obj.cv_data, "target1", text="Right" ) + #} #} +# Classtype 9 +# +# Purpose: Defines a route, its 'starting' point, and the colour to use for it +# class classtype_route(Structure): #{ _pack_ = 1 _fields_ = [("id_start",c_uint32), + ("pstr_name",c_uint32), ("colour",c_float*3)] def encode_obj(_, node,node_def): @@ -213,12 +363,118 @@ class classtype_route(Structure): _.colour[0] = obj.cv_data.colour[0] _.colour[1] = obj.cv_data.colour[1] _.colour[2] = obj.cv_data.colour[2] + _.pstr_name = encoder_process_pstr( obj.cv_data.strp ) if obj.cv_data.target != None: _.id_start = obj.cv_data.target.cv_data.uid #} + + @staticmethod + def draw_scene_helpers( obj ): + #{ + global cv_view_verts, cv_view_colours, cv_view_course_i + + if obj.cv_data.target: + cv_draw_arrow( obj.location, obj.cv_data.target.location, [1,1,1,1] ) + + # Tries to simulate how we do it in the game + # + stack = [None]*64 + stack_i = [0]*64 + stack[0] = obj.cv_data.target + si = 1 + loop_complete = False + + while si > 0: + #{ + if stack_i[si-1] == 2: + #{ + si -= 1 + continue + + if si == 0: # Loop failed to complete + break + #} + + node = stack[si-1] + + targets = [None,None] + targets[0] = node.cv_data.target + + if node.cv_data.classtype == '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 loop_complete: + #{ + cc = Vector((obj.cv_data.colour[0],\ + obj.cv_data.colour[1],\ + obj.cv_data.colour[2],\ + 1.0)) + + for sj in range(si): + #{ + sk = (sj+1)%si + + if stack[sj].cv_data.classtype == 'classtype_gate' and \ + stack[sk].cv_data.classtype == 'classtype_gate': + #{ + dist = (stack[sj].location-stack[sk].location).magnitude + cv_draw_sbpath( stack[sj], stack[sk], cc*0.4, cc, dist, dist ) + #} + else: + cv_draw_bpath( stack[sj], stack[sk], cc, cc ) + #} + + cv_view_course_i += 1 + #} + #} + + @staticmethod + def editor_interface( layout, obj ): + #{ + layout.prop( obj.cv_data, "target", text="'Start' from" ) + layout.prop( obj.cv_data, "colour" ) + layout.prop( obj.cv_data, "strp", text="Name" ) + #} #} +# Classtype 12 +# +# Purpose: links an mesh node to a type 11 +# class classtype_skin(Structure): #{ _pack_ = 1 @@ -233,6 +489,10 @@ class classtype_skin(Structure): #} #} +# Classtype 11 +# +# Purpose: defines the allocation requirements for a skeleton +# class classtype_skeleton(Structure): #{ _pack_ = 1 @@ -254,6 +514,11 @@ class classtype_skeleton(Structure): #} #} + +# Classtype 10 +# +# Purpose: intrinsic bone type, stores collision information and limits too +# class classtype_bone(Structure): #{ _pack_ = 1 @@ -306,21 +571,127 @@ class classtype_bone(Structure): #} #} +# Classtype 100 +# +# Purpose: sends a signal to another entity +# +class classtype_trigger(Structure): +#{ + _pack_ = 1 + _fields_ = [("target",c_uint32)] + + def encode_obj(_, node,node_def ): + #{ + node.classtype = 100 + if node_def['obj'].cv_data.target: + _.target = node_def['obj'].cv_data.target.cv_data.uid + #} + + @staticmethod + def draw_scene_helpers( obj ): + #{ + global cv_view_verts, cv_view_colours + cv_draw_ucube( obj.matrix_world, [0,1,0,1] ) + + if obj.cv_data.target: + cv_draw_arrow( obj.location, obj.cv_data.target.location, [1,1,1,1] ) + #} + + @staticmethod + def editor_interface( layout, obj ): + #{ + layout.prop( obj.cv_data, "target", text="Triggers" ) + #} +#} -# TO BE REPLACED +# Classtype 101 +# +# Purpose: Gives the player an achievement. +# No cheating! You shouldn't use this entity anyway, since only ME can +# add achievements to the steam ;) # -class classtype_achievement_box(Structure): +class classtype_logic_achievement(Structure): #{ _pack_ = 1 - _fields_ = [("pstr_name",c_uint32), - ("trigger",c_uint32)] + _fields_ = [("pstr_name",c_uint32)] def encode_obj(_, node,node_def ): #{ - node.classtype = 0 + node.classtype = 101 + _.pstr_name = encoder_process_pstr( node_def['obj'].cv_data.strp ) + #} + + @staticmethod + def editor_interface( layout, obj ): + #{ + layout.prop( obj.cv_data, "strp", text="Achievement ID" ) #} #} +# Classtype 102 +# +# Purpose: sends a signal to another entity +# +class classtype_logic_relay(Structure): +#{ + _pack_ = 1 + _fields_ = [("targets",c_uint32*4)] + + def encode_obj(_, node,node_def ): + #{ + node.classtype = 102 + obj = node_def['obj'] + if obj.cv_data.target: + _.targets[0] = obj.cv_data.target.cv_data.uid + if obj.cv_data.target1: + _.targets[1] = obj.cv_data.target1.cv_data.uid + if obj.cv_data.target2: + _.targets[2] = obj.cv_data.target2.cv_data.uid + if obj.cv_data.target3: + _.targets[3] = obj.cv_data.target3.cv_data.uid + #} + + @staticmethod + def draw_scene_helpers( obj ): + #{ + global cv_view_verts, cv_view_colours + + if obj.cv_data.target: + cv_draw_arrow( obj.location, obj.cv_data.target.location, [1,1,1,1] ) + if obj.cv_data.target1: + cv_draw_arrow( obj.location, obj.cv_data.target1.location, [1,1,1,1] ) + if obj.cv_data.target2: + cv_draw_arrow( obj.location, obj.cv_data.target2.location, [1,1,1,1] ) + if obj.cv_data.target3: + cv_draw_arrow( obj.location, obj.cv_data.target3.location, [1,1,1,1] ) + #} + + @staticmethod + def editor_interface( layout, obj ): + #{ + layout.prop( obj.cv_data, "target", text="Triggers" ) + layout.prop( obj.cv_data, "target1", text="Triggers" ) + layout.prop( obj.cv_data, "target2", text="Triggers" ) + layout.prop( obj.cv_data, "target3", text="Triggers" ) + #} +#} + +# Classtype 14 +# +# Purpose: Plays some audio (44100hz .ogg vorbis only) +# NOTE: There is a 32mb limit on the audio buffer, world audio is +# decompressed and stored in signed 16 bit integers (2 bytes) +# per sample. +# +# volume: not used if has 3D flag +# flags: +# AUDIO_FLAG_LOOP 0x1 +# AUDIO_FLAG_ONESHOT 0x2 (DONT USE THIS, it breaks semaphores) +# AUDIO_FLAG_SPACIAL_3D 0x4 (Probably what you want) +# AUDIO_FLAG_AUTO_START 0x8 (Play when the world starts) +# ...... +# the rest are just internal flags, only use the above 3. +# class classtype_audio(Structure): #{ _pack_ = 1 @@ -335,29 +706,45 @@ class classtype_audio(Structure): obj = node_def['obj'] _.pstr_file = encoder_process_pstr( obj.cv_data.strp ) - _.flags = obj.cv_data.intp + + flags = 0x00 + if obj.cv_data.bp0: flags |= 0x1 + if obj.cv_data.bp1: flags |= 0x4 + if obj.cv_data.bp2: flags |= 0x8 + + _.flags = flags _.volume = obj.cv_data.fltp #} @staticmethod - def editor_interface(yada): + def editor_interface( layout, obj ): #{ - pass + layout.prop( obj.cv_data, "strp" ) + + layout.prop( obj.cv_data, "bp0", text = "Looping" ) + layout.prop( obj.cv_data, "bp1", text = "3D Audio" ) + layout.prop( obj.cv_data, "bp2", text = "Auto Start" ) #} @staticmethod - def draw_scene_helpers(yada): + def draw_scene_helpers( obj ): #{ - pass + global cv_view_verts, cv_view_colours + + cv_draw_sphere( obj.location, obj.scale[0], [1,1,0,1] ) #} #} +# ---------------------------------------------------------------------------- # +# # +# Compiler section # +# # +# ---------------------------------------------------------------------------- # # Current encoder state # g_encoder = None - # Reset encoder # def encoder_init(): @@ -585,7 +972,6 @@ def encoder_build_scene_graph( collection ): for b in n.data.bones: if not b.parent: _extendb( tree, b, d+1 ) - #} #} # Recurse into children of this object @@ -1279,459 +1665,439 @@ def write_model(collection_name): print( F"Completed {collection_name}.mdl" ) #} - -# Clicky clicky GUI -# ------------------------------------------------------------------------------ +# ---------------------------------------------------------------------------- # +# # +# GUI section # +# # +# ---------------------------------------------------------------------------- # cv_view_draw_handler = None cv_view_shader = gpu.shader.from_builtin('3D_SMOOTH_COLOR') +cv_view_verts = [] +cv_view_colours = [] +cv_view_course_i = 0 -def cv_draw(): - global cv_view_shader - cv_view_shader.bind() - gpu.state.depth_mask_set(False) - gpu.state.line_width_set(2.0) - gpu.state.face_culling_set('BACK') - gpu.state.depth_test_set('LESS') - gpu.state.blend_set('NONE') - - verts = [] - colours = [] - - #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 += [colour,colour] - - def drawbezier(p0,h0,p1,h1,c0,c1): - nonlocal verts, colours - - 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 - - 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) +# Draw axis alligned sphere at position with radius +# +def cv_draw_sphere( pos, radius, colour ): +#{ + global cv_view_verts, cv_view_colours + + ly = pos + Vector((0,0,radius)) + lx = pos + Vector((0,radius,0)) + lz = pos + Vector((0,0,radius)) + + pi = 3.14159265358979323846264 - def drawbline(p0,p1,c0,c1): - nonlocal verts, colours - verts += [p0,p1] - colours += [c0,c1] + for i in range(16): + #{ + t = ((i+1.0) * 1.0/16.0) * pi * 2.0 + s = math.sin(t) + c = math.cos(t) - for obj in bpy.context.collection.objects: - if obj.type == 'ARMATURE': - for bone in obj.data.bones: - if bone.cv_data.collider and obj.data.pose_position == 'REST': - c = bone.head_local - a = bone.cv_data.v0 - b = bone.cv_data.v1 - - vs = [None]*8 - vs[0]=obj.matrix_world@Vector((c[0]+a[0],c[1]+a[1],c[2]+a[2])) - vs[1]=obj.matrix_world@Vector((c[0]+a[0],c[1]+b[1],c[2]+a[2])) - vs[2]=obj.matrix_world@Vector((c[0]+b[0],c[1]+b[1],c[2]+a[2])) - vs[3]=obj.matrix_world@Vector((c[0]+b[0],c[1]+a[1],c[2]+a[2])) - vs[4]=obj.matrix_world@Vector((c[0]+a[0],c[1]+a[1],c[2]+b[2])) - vs[5]=obj.matrix_world@Vector((c[0]+a[0],c[1]+b[1],c[2]+b[2])) - vs[6]=obj.matrix_world@Vector((c[0]+b[0],c[1]+b[1],c[2]+b[2])) - vs[7]=obj.matrix_world@Vector((c[0]+b[0],c[1]+a[1],c[2]+b[2])) - - indices = [(0,1),(1,2),(2,3),(3,0),(4,5),(5,6),(6,7),(7,4),\ - (0,4),(1,5),(2,6),(3,7)] - - 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,0.5,0.5,0.5),(0.5,0.5,0.5,0.5)] - - center=obj.matrix_world@c - - def _angle_lim( major, minor, amin, amax, colour ): - nonlocal verts, colours - f = 0.05 - ay = major*f - ax = minor*f - - for x in range(16): - t0 = x/16 - t1 = (x+1)/16 - a0 = amin*(1.0-t0)+amax*t0 - a1 = amin*(1.0-t1)+amax*t1 - - p0 = c + major*f*math.cos(a0) + minor*f*math.sin(a0) - p1 = c + major*f*math.cos(a1) + minor*f*math.sin(a1) - - p0=obj.matrix_world @ p0 - p1=obj.matrix_world @ p1 - verts += [p0,p1] - colours += [colour,colour] - - if x == 0: - verts += [p0,c] - colours += [colour,colour] - if x == 15: - verts += [p1,c] - colours += [colour,colour] - - verts += [c+major*1.2*f,c+major*f*0.8] - colours += [colour,colour] - - if bone.cv_data.con0: - _angle_lim( Vector((0,1,0)),Vector((0,0,1)), \ - bone.cv_data.mins[0], bone.cv_data.maxs[0], \ - (1,0,0,1)) - _angle_lim( Vector((0,0,1)),Vector((1,0,0)), \ - bone.cv_data.mins[1], bone.cv_data.maxs[1], \ - (0,1,0,1)) - _angle_lim( Vector((1,0,0)),Vector((0,1,0)), \ - bone.cv_data.mins[2], bone.cv_data.maxs[2], \ - (0,0,1,1)) - + py = pos + Vector((s*radius,0.0,c*radius)) + px = pos + Vector((s*radius,c*radius,0.0)) + pz = pos + Vector((0.0,s*radius,c*radius)) - if obj.cv_data.classtype == 'classtype_gate': - if obj.type == 'MESH': - dims = obj.data.cv_data.v0 - else: - dims = obj.cv_data.v0 + cv_view_verts += [ px, lx ] + cv_view_verts += [ py, ly ] + cv_view_verts += [ pz, lz ] - vs = [None]*9 - c = Vector((0,0,dims[2])) + cv_view_colours += [ colour, colour, colour, colour, colour, colour ] - 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))) + ly = py + lx = px + lz = pz + #} + cv_draw_lines() +#} - indices = [(0,1),(1,2),(2,3),(3,0),(4,5),(5,6),(7,8)] +# Draw transformed -1 -> 1 cube +# +def cv_draw_ucube( transform, colour ): +#{ + global cv_view_verts, cv_view_colours - 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)] - - sw = (0.4,0.4,0.4,0.2) - if obj.cv_data.target != None: - drawbline( obj.location, obj.cv_data.target.location, sw,sw ) - - elif obj.cv_data.classtype == 'classtype_route_node': - sw = Vector((0.4,0.4,0.4,0.2)) - sw2 = Vector((1.5,0.2,0.2,0.0)) - if obj.cv_data.target != None: - drawbpath( obj, obj.cv_data.target, sw, sw ) - if obj.cv_data.target1 != None: - drawbpath( obj, obj.cv_data.target1, sw, sw ) - - drawbhandle( obj, 1.0, (0.8,0.8,0.8,1.0) ) - drawbhandle( obj, -1.0, (0.4,0.4,0.4,1.0) ) - - p1 = obj.location+ \ - obj.matrix_world.to_quaternion() @ Vector((0,0,-6+1.5)) - drawbline( obj.location, p1, sw,sw2 ) - - elif obj.cv_data.classtype == 'classtype_achievement_box': - a = Vector((-1,-1,-1)) - b = Vector((1,1,1)) - - vs = [None]*8 - vs[0] = obj.matrix_world @ Vector((a[0], a[1], a[2])) - vs[1] = obj.matrix_world @ Vector((a[0], b[1], a[2])) - vs[2] = obj.matrix_world @ Vector((b[0], b[1], a[2])) - vs[3] = obj.matrix_world @ Vector((b[0], a[1], a[2])) - vs[4] = obj.matrix_world @ Vector((a[0], a[1], b[2])) - vs[5] = obj.matrix_world @ Vector((a[0], b[1], b[2])) - vs[6] = obj.matrix_world @ Vector((b[0], b[1], b[2])) - vs[7] = obj.matrix_world @ Vector((b[0], a[1], b[2])) + a = Vector((-1,-1,-1)) + b = Vector((1,1,1)) + + vs = [None]*8 + vs[0] = transform @ Vector((a[0], a[1], a[2])) + vs[1] = transform @ Vector((a[0], b[1], a[2])) + vs[2] = transform @ Vector((b[0], b[1], a[2])) + vs[3] = transform @ Vector((b[0], a[1], a[2])) + vs[4] = transform @ Vector((a[0], a[1], b[2])) + vs[5] = transform @ Vector((a[0], b[1], b[2])) + vs[6] = transform @ Vector((b[0], b[1], b[2])) + vs[7] = transform @ Vector((b[0], a[1], b[2])) + + indices = [(0,1),(1,2),(2,3),(3,0),(4,5),(5,6),(6,7),(7,4),\ + (0,4),(1,5),(2,6),(3,7)] + + for l in indices: + #{ + v0 = vs[l[0]] + v1 = vs[l[1]] + cv_view_verts += [(v0[0],v0[1],v0[2])] + cv_view_verts += [(v1[0],v1[1],v1[2])] + cv_view_colours += [(0,1,0,1),(0,1,0,1)] + #} + cv_draw_lines() +#} - indices = [(0,1),(1,2),(2,3),(3,0),(4,5),(5,6),(6,7),(7,4),\ - (0,4),(1,5),(2,6),(3,7)] +# Draw line with colour +# +def cv_draw_line( p0, p1, colour ): +#{ + global cv_view_verts, cv_view_colours - 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,0,1),(0,1,0,1)] - - if obj.cv_data.target != None: - 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)] - - - elif obj.cv_data.classtype == 'classtype_block': - a = obj.data.cv_data.v0 - b = obj.data.cv_data.v1 - - vs = [None]*8 - vs[0] = obj.matrix_world @ Vector((a[0], a[1], a[2])) - vs[1] = obj.matrix_world @ Vector((a[0], b[1], a[2])) - vs[2] = obj.matrix_world @ Vector((b[0], b[1], a[2])) - vs[3] = obj.matrix_world @ Vector((b[0], a[1], a[2])) - vs[4] = obj.matrix_world @ Vector((a[0], a[1], b[2])) - vs[5] = obj.matrix_world @ Vector((a[0], b[1], b[2])) - vs[6] = obj.matrix_world @ Vector((b[0], b[1], b[2])) - vs[7] = obj.matrix_world @ Vector((b[0], a[1], b[2])) + cv_view_verts += [p0,p1] + cv_view_colours += [colour, colour] + cv_draw_lines() +#} - indices = [(0,1),(1,2),(2,3),(3,0),(4,5),(5,6),(6,7),(7,4),\ - (0,4),(1,5),(2,6),(3,7)] +# Draw line with colour(s) +# +def cv_draw_line2( p0, p1, c0, c1 ): +#{ + global cv_view_verts, cv_view_colours - 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 == '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)] + cv_view_verts += [p0,p1] + cv_view_colours += [c0,c1] + cv_draw_lines() +#} - 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 == 'classtype_spawn': - vs = [None]*4 - vs[0] = obj.matrix_world @ Vector((0,0,0)) - vs[1] = obj.matrix_world @ Vector((0,2,0)) - vs[2] = obj.matrix_world @ Vector((0.5,1,0)) - vs[3] = obj.matrix_world @ Vector((-0.5,1,0)) - indices = [(0,1),(1,2),(1,3)] - 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)] - - elif obj.cv_data.classtype == '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: - if stack_i[si-1] == 2: - si -= 1 - continue +# Just the tx because we dont really need ty for this app +# +def cv_tangent_basis_tx( n, tx ): +#{ + if abs( n[0] ) >= 0.57735027: + #{ + tx[0] = n[1] + tx[1] = -n[0] + tx[2] = 0.0 + #} + else: + #{ + tx[0] = 0.0 + tx[1] = n[2] + tx[2] = -n[1] + #} - if si == 0: # Loop failed to complete - break + tx.normalize() +#} - node = stack[si-1] +# Draw coloured arrow +# +def cv_draw_arrow( p0, p1, c0 ): +#{ + global cv_view_verts, cv_view_colours - targets = [None,None] - targets[0] = node.cv_data.target + n = p1-p0 + midpt = p0 + n*0.5 + n.normalize() - if node.cv_data.classtype == 'classtype_route_node': - targets[1] = node.cv_data.target1 - - nextnode = targets[stack_i[si-1]] - stack_i[si-1] += 1 + tx = Vector((1,0,0)) + cv_tangent_basis_tx( n, tx ) + + cv_view_verts += [p0,p1, midpt+(tx-n)*0.15,midpt, midpt+(-tx-n)*0.15,midpt ] + cv_view_colours += [c0,c0,c0,c0,c0,c0] + cv_draw_lines() +#} - if nextnode != None: # branch - if nextnode == stack[0]: # Loop completed - loop_complete = True - break +# Drawhandles of a bezier control point +# +def cv_draw_bhandle( obj, direction, colour ): +#{ + global cv_view_verts, cv_view_colours - valid=True - for sj in range(si): - if stack[sj] == nextnode: # invalidated path - valid=False - break + p0 = obj.location + h0 = obj.matrix_world @ Vector((0,direction,0)) - if valid: - stack_i[si] = 0 - stack[si] = nextnode - si += 1 - continue + cv_view_verts += [p0] + cv_view_verts += [h0] + cv_view_colours += [colour,colour] + cv_draw_lines() +#} - if loop_complete: - cc = Vector((obj.cv_data.colour[0],\ - obj.cv_data.colour[1],\ - obj.cv_data.colour[2],\ - 1.0)) +# Draw a bezier curve (at fixed resolution 10) +# +def cv_draw_bezier( p0,h0,p1,h1,c0,c1 ): +#{ + global cv_view_verts, cv_view_colours - for sj in range(si): - sk = (sj+1)%si + last = p0 + for i in range(10): + #{ + t = (i+1)/10 + a0 = 1-t - if stack[sj].cv_data.classtype == 'classtype_gate' and \ - stack[sk].cv_data.classtype == 'classtype_gate': - dist = (stack[sj].location-stack[sk].location).magnitude - drawsbpath( stack[sj], stack[sk], cc*0.4, cc, dist, dist ) + 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 - else: - drawbpath( stack[sj], stack[sk], cc, cc ) + cv_view_verts += [(last[0],last[1],last[2])] + cv_view_verts += [(p[0],p[1],p[2])] + cv_view_colours += [c0*a0+c1*(1-a0),c0*a0+c1*(1-a0)] - course_count += 1 + last = p + #} + cv_draw_lines() +#} - elif obj.cv_data.classtype == '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) ) +# I think this one extends the handles of the bezier otwards...... +# +def cv_draw_sbpath( o0,o1,c0,c1,s0,s1 ): +#{ + global cv_view_course_i + + offs = ((cv_view_course_i % 2)*2-1) * cv_view_course_i * 0.02 - if obj.cv_data.target != None: - 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)) + 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)) - drawbhandle( obj.cv_data.target, -1.0, (0.5,0.5,0.5,1.0) ) - drawbpath( obj, obj.cv_data.target, c0, c1 ) + cv_draw_bezier( p0,h0,p1,h1,c0,c1 ) + cv_draw_lines() +#} - if obj.cv_data.target1 != None: - 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)) +# Flush the lines buffers. This is called often because god help you if you want +# to do fixed, fast buffers in this catastrophic programming language. +# +def cv_draw_lines(): +#{ + global cv_view_shader, cv_view_verts, cv_view_colours - drawbhandle( obj.cv_data.target1, -1.0, (0.5,0.5,0.5,1.0) ) - drawbpath( obj, obj.cv_data.target1, c0, c1 ) + if len(cv_view_verts) < 2: + return lines = batch_for_shader(\ cv_view_shader, 'LINES', \ - { "pos":verts, "color":colours }) + { "pos":cv_view_verts, "color":cv_view_colours }) lines.draw( cv_view_shader ) + cv_view_verts = [] + cv_view_colours = [] +#} + +# I dont remember what this does exactly +# +def cv_draw_bpath( o0,o1,c0,c1 ): +#{ + cv_draw_sbpath( o0,o1,c0,c1,1.0,1.0 ) +#} + +# Semi circle to show the limit. and some lines +# +def draw_limit( obj, center, major, minor, amin, amax, colour ): +#{ + global cv_view_verts, cv_view_colours + f = 0.05 + ay = major*f + ax = minor*f + + for x in range(16): + #{ + t0 = x/16 + t1 = (x+1)/16 + a0 = amin*(1.0-t0)+amax*t0 + a1 = amin*(1.0-t1)+amax*t1 + + p0 = center + major*f*math.cos(a0) + minor*f*math.sin(a0) + p1 = center + major*f*math.cos(a1) + minor*f*math.sin(a1) + + p0=obj.matrix_world @ p0 + p1=obj.matrix_world @ p1 + cv_view_verts += [p0,p1] + cv_view_colours += [colour,colour] + + if x == 0: + #{ + cv_view_verts += [p0,center] + cv_view_colours += [colour,colour] + #} + if x == 15: + #{ + cv_view_verts += [p1,center] + cv_view_colours += [colour,colour] + #} + #} + + cv_view_verts += [center+major*1.2*f,center+major*f*0.8] + cv_view_colours += [colour,colour] + + cv_draw_lines() +#} + +# Draws constraints and stuff for the skeleton. This isnt documented and wont be +# +def draw_skeleton_helpers( obj ): +#{ + global cv_view_verts, cv_view_colours + + for bone in obj.data.bones: + #{ + if bone.cv_data.collider and (obj.data.pose_position == 'REST'): + #{ + c = bone.head_local + a = bone.cv_data.v0 + b = bone.cv_data.v1 + + vs = [None]*8 + vs[0]=obj.matrix_world@Vector((c[0]+a[0],c[1]+a[1],c[2]+a[2])) + vs[1]=obj.matrix_world@Vector((c[0]+a[0],c[1]+b[1],c[2]+a[2])) + vs[2]=obj.matrix_world@Vector((c[0]+b[0],c[1]+b[1],c[2]+a[2])) + vs[3]=obj.matrix_world@Vector((c[0]+b[0],c[1]+a[1],c[2]+a[2])) + vs[4]=obj.matrix_world@Vector((c[0]+a[0],c[1]+a[1],c[2]+b[2])) + vs[5]=obj.matrix_world@Vector((c[0]+a[0],c[1]+b[1],c[2]+b[2])) + vs[6]=obj.matrix_world@Vector((c[0]+b[0],c[1]+b[1],c[2]+b[2])) + vs[7]=obj.matrix_world@Vector((c[0]+b[0],c[1]+a[1],c[2]+b[2])) + + indices = [(0,1),(1,2),(2,3),(3,0),(4,5),(5,6),(6,7),(7,4),\ + (0,4),(1,5),(2,6),(3,7)] + + for l in indices: + #{ + v0 = vs[l[0]] + v1 = vs[l[1]] + + cv_view_verts += [(v0[0],v0[1],v0[2])] + cv_view_verts += [(v1[0],v1[1],v1[2])] + cv_view_colours += [(0.5,0.5,0.5,0.5),(0.5,0.5,0.5,0.5)] + #} + + center = obj.matrix_world @ c + if bone.cv_data.con0: + #{ + draw_limit( obj, c, Vector((0,1,0)),Vector((0,0,1)), \ + bone.cv_data.mins[0], bone.cv_data.maxs[0], \ + (1,0,0,1)) + draw_limit( obj, c, Vector((0,0,1)),Vector((1,0,0)), \ + bone.cv_data.mins[1], bone.cv_data.maxs[1], \ + (0,1,0,1)) + draw_limit( obj, c, Vector((1,0,0)),Vector((0,1,0)), \ + bone.cv_data.mins[2], bone.cv_data.maxs[2], \ + (0,0,1,1)) + #} + #} + #} +#} + +def cv_draw(): +#{ + global cv_view_shader + global cv_view_verts + global cv_view_colours + global cv_view_course_i + + cv_view_course_i = 0 + cv_view_verts = [] + cv_view_colours = [] + + cv_view_shader.bind() + gpu.state.depth_mask_set(False) + gpu.state.line_width_set(2.0) + gpu.state.face_culling_set('BACK') + gpu.state.depth_test_set('LESS') + gpu.state.blend_set('NONE') + + for obj in bpy.context.collection.objects: + #{ + if obj.type == 'ARMATURE': + #{ + if obj.data.pose_position == 'REST': + draw_skeleton_helpers( obj ) + #} + else: + #{ + classtype = obj.cv_data.classtype + if (classtype != 'classtype_none') and (classtype in globals()): + #{ + cl = globals()[ classtype ] + + if getattr( cl, "draw_scene_helpers", None ): + #{ + cl.draw_scene_helpers( obj ) + #} + #} + #} + #} + + cv_draw_lines() + return +#} + + +# ---------------------------------------------------------------------------- # +# # +# Blender # +# # +# ---------------------------------------------------------------------------- # + +# Checks whether this object has a classtype assigned. we can only target other +# classes def cv_poll_target(scene, obj): +#{ if obj == bpy.context.active_object: return False if obj.cv_data.classtype == 'classtype_none': return False + return True +#} class CV_MESH_SETTINGS(bpy.types.PropertyGroup): +#{ v0: bpy.props.FloatVectorProperty(name="v0",size=3) v1: bpy.props.FloatVectorProperty(name="v1",size=3) v2: bpy.props.FloatVectorProperty(name="v2",size=3) v3: bpy.props.FloatVectorProperty(name="v3",size=3) +#} class CV_OBJ_SETTINGS(bpy.types.PropertyGroup): +#{ uid: bpy.props.IntProperty( name="" ) strp: bpy.props.StringProperty( name="strp" ) intp: bpy.props.IntProperty( name="intp" ) fltp: bpy.props.FloatProperty( name="fltp" ) + bp0: bpy.props.BoolProperty( name="bp0" ) + bp1: bpy.props.BoolProperty( name="bp1" ) + bp2: bpy.props.BoolProperty( name="bp2" ) + bp3: bpy.props.BoolProperty( name="bp3" ) target: bpy.props.PointerProperty( type=bpy.types.Object, name="target", \ poll=cv_poll_target ) target1: bpy.props.PointerProperty( type=bpy.types.Object, name="target1", \ poll=cv_poll_target ) + target2: bpy.props.PointerProperty( type=bpy.types.Object, name="target2", \ + poll=cv_poll_target ) + target3: bpy.props.PointerProperty( type=bpy.types.Object, name="target3", \ + poll=cv_poll_target ) - colour: bpy.props.FloatVectorProperty(name="colour",subtype='COLOR',\ - min=0.0,max=1.0) + colour: bpy.props.FloatVectorProperty( name="colour",subtype='COLOR',\ + min=0.0,max=1.0) classtype: bpy.props.EnumProperty( name="Format", items = [ ('classtype_none', "classtype_none", "", 0), ('classtype_gate', "classtype_gate", "", 1), - ('classtype_block', "classtype_block", "", 2), ('classtype_spawn', "classtype_spawn", "", 3), ('classtype_water', "classtype_water", "", 4), - ('classtype_car_path', "classtype_car_path", "", 5), - ('classtype_INSTANCE', "","", 6 ), - ('classtype_capsule', "classtype_capsule", "", 7 ), ('classtype_route_node', "classtype_route_node", "", 8 ), ('classtype_route', "classtype_route", "", 9 ), - ('classtype_bone',"classtype_bone","",10), - ('classtype_SKELETON', "","", 11 ), - ('classtype_SKIN',"","",12), - ('classtype_achievement_box',"classtype_achievement_box","",13), ('classtype_audio',"classtype_audio","",14), + ('classtype_trigger',"classtype_trigger","",100), + ('classtype_logic_achievement',"classtype_logic_achievement","",101), + ('classtype_logic_relay',"classtype_logic_relay","",102), ]) +#} class CV_BONE_SETTINGS(bpy.types.PropertyGroup): +#{ collider: bpy.props.BoolProperty(name="Collider",default=False) v0: bpy.props.FloatVectorProperty(name="v0",size=3) v1: bpy.props.FloatVectorProperty(name="v1",size=3) @@ -1739,8 +2105,10 @@ class CV_BONE_SETTINGS(bpy.types.PropertyGroup): con0: bpy.props.BoolProperty(name="Constriant 0",default=False) mins: bpy.props.FloatVectorProperty(name="mins",size=3) maxs: bpy.props.FloatVectorProperty(name="maxs",size=3) +#} class CV_BONE_PANEL(bpy.types.Panel): +#{ bl_label="Bone Config" bl_idname="SCENE_PT_cv_bone" bl_space_type='PROPERTIES' @@ -1748,6 +2116,7 @@ class CV_BONE_PANEL(bpy.types.Panel): bl_context='bone' def draw(_,context): + #{ active_object = context.active_object if active_object == None: return @@ -1762,11 +2131,16 @@ class CV_BONE_PANEL(bpy.types.Panel): _.layout.prop( bone.cv_data, "con0" ) _.layout.prop( bone.cv_data, "mins" ) _.layout.prop( bone.cv_data, "maxs" ) + #} +#} class CV_SCENE_SETTINGS(bpy.types.PropertyGroup): +#{ use_hidden: bpy.props.BoolProperty( name="use hidden", default=False ) +#} class CV_OBJ_PANEL(bpy.types.Panel): +#{ bl_label="Entity Config" bl_idname="SCENE_PT_cv_entity" bl_space_type='PROPERTIES' @@ -1774,6 +2148,7 @@ class CV_OBJ_PANEL(bpy.types.Panel): bl_context="object" def draw(_,context): + #{ active_object = bpy.context.active_object if active_object == None: return if active_object.type == 'ARMATURE': @@ -1786,43 +2161,22 @@ class CV_OBJ_PANEL(bpy.types.Panel): _.layout.prop( active_object.cv_data, "classtype" ) - if active_object.cv_data.classtype == 'classtype_gate': - _.layout.prop( active_object.cv_data, "target" ) - - 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 == 'classtype_car_path' or \ - active_object.cv_data.classtype == 'classtype_route_node': - _.layout.prop( active_object.cv_data, "target" ) - _.layout.prop( active_object.cv_data, "target1" ) - - elif active_object.cv_data.classtype == 'classtype_route': - _.layout.prop( active_object.cv_data, "target" ) - _.layout.prop( active_object.cv_data, "colour" ) - - elif active_object.cv_data.classtype == 'classtype_block': - mesh = active_object.data - - _.layout.label( text=F"(i) Data is stored in {mesh.name}" ) - _.layout.prop( mesh.cv_data, "v0" ) - _.layout.prop( mesh.cv_data, "v1" ) - _.layout.prop( mesh.cv_data, "v2" ) - _.layout.prop( mesh.cv_data, "v3" ) - elif active_object.cv_data.classtype == 'classtype_capsule': - 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 == 'classtype_achievement_box': - _.layout.prop( active_object.cv_data, "strp" ) - _.layout.prop( active_object.cv_data, "target" ) - elif active_object.cv_data.classtype == 'classtype_audio': - _.layout.prop( active_object.cv_data, "strp" ) - _.layout.prop( active_object.cv_data, "intp" ) - _.layout.prop( active_object.cv_data, "fltp" ) + classtype = active_object.cv_data.classtype + + if (classtype != 'classtype_none') and (classtype in globals()): + #{ + cl = globals()[ classtype ] + + if getattr( cl, "editor_interface", None ): + #{ + cl.editor_interface( _.layout, active_object ) + #} + #} + #} +#} class CV_INTERFACE(bpy.types.Panel): +#{ bl_idname = "VIEW3D_PT_carve" bl_label = "Carve" bl_space_type = 'VIEW_3D' @@ -1830,33 +2184,43 @@ class CV_INTERFACE(bpy.types.Panel): bl_category = "Carve" def draw(_, context): + #{ layout = _.layout layout.prop( context.scene.cv_data, "use_hidden") layout.operator( "carve.compile_all" ) + #} +#} def test_compile(): +#{ view_layer = bpy.context.view_layer for col in view_layer.layer_collection.children["export"].children: if not col.hide_viewport or bpy.context.scene.cv_data.use_hidden: write_model( col.name ) +#} class CV_COMPILE(bpy.types.Operator): +#{ bl_idname="carve.compile_all" bl_label="Compile All" def execute(_,context): + #{ test_compile() #cProfile.runctx("test_compile()",globals(),locals(),sort=1) #for col in bpy.data.collections["export"].children: # write_model( col.name ) return {'FINISHED'} + #} +#} classes = [CV_OBJ_SETTINGS,CV_OBJ_PANEL,CV_COMPILE,CV_INTERFACE,\ CV_MESH_SETTINGS, CV_SCENE_SETTINGS, CV_BONE_SETTINGS,\ CV_BONE_PANEL] def register(): +#{ global cv_view_draw_handler for c in classes: @@ -1869,11 +2233,14 @@ def register(): cv_view_draw_handler = bpy.types.SpaceView3D.draw_handler_add(\ cv_draw,(),'WINDOW','POST_VIEW') +#} def unregister(): +#{ global cv_view_draw_handler for c in classes: bpy.utils.unregister_class(c) bpy.types.SpaceView3D.draw_handler_remove(cv_view_draw_handler,'WINDOW') +#} diff --git a/build.sh b/build.sh index 0228534..eb741bf 100755 --- a/build.sh +++ b/build.sh @@ -29,7 +29,7 @@ _options_release="-O3 -DVG_RELEASE" # Compiler lines # ============================================================================== -_warnings="-Wall -Wno-unused-function -Wno-unused-variable" +_warnings="-Wall -Wno-unused-function -Wno-unused-variable -Wno-unused-command-line-argument -Wno-unused-but-set-variable" _include="-I. -I./vg/dep -I./vg/src" _library="-L. -L./vg/dep/glfw -L./vg/dep/steam" _epilogue="-Wl,-rpath=./" diff --git a/main.c b/main.c index 119be9e..0e5a2fc 100644 --- a/main.c +++ b/main.c @@ -40,26 +40,8 @@ static int cl_ui = 1; int main( int argc, char *argv[] ) { - vg_mem.use_libc_malloc = 1; -#if 0 - vg_prealloc_quota( 128*1024*1024 ); - void *test_allocator = vg_create_linear_allocator( NULL, 2048 ); - - for( int i=0; i<8; i++ ) - { - u64 *items = vg_linear_alloc( test_allocator, sizeof(u64) ); - items = vg_linear_extend( test_allocator, items, sizeof(u64)); - items[0] = 43; - items[1] = 12445; - - vg_info( "%lu %lu\n", items[0], items[1] ); - } - - vg_linear_clear( test_allocator ); - return 0; -#endif - - vg_prealloc_quota( 128*1024*1024 ); + vg_mem.use_libc_malloc = 0; + vg_set_mem_quota( 128*1024*1024 ); vg_enter( argc, argv, "Voyager Game Engine" ); } @@ -109,6 +91,7 @@ VG_STATIC void vg_load(void) vg_bake_shaders(); vg_loader_highwater( audio_init, audio_free, NULL ); + world_audio_init(); /* 'systems' are completely loaded now */ strcpy( world.world_name, "models/mp_test.mdl" ); diff --git a/model.h b/model.h index 957001c..fb33e0b 100644 --- a/model.h +++ b/model.h @@ -37,12 +37,12 @@ enum classtype k_classtype_bone = 10, k_classtype_skeleton = 11, k_classtype_skin = 12, - k_classtype_achievement_box = 13, k_classtype_audio = 14, - k_classtype_trigger = 15 + k_classtype_trigger = 100, + k_classtype_logic_achievement = 101, + k_classtype_logic_relay = 102 }; - #pragma pack(push,1) struct mdl_vert @@ -149,6 +149,7 @@ struct classtype_route_node struct classtype_route { u32 id_start; + u32 pstr_name; v3f colour; }; @@ -178,10 +179,19 @@ struct classtype_skin u32 skeleton; }; -struct classtype_achievement_box +struct classtype_trigger { - u32 pstr_name, - trigger; + u32 target; +}; + +struct classtype_logic_relay +{ + u32 targets[4]; +}; + +struct classtype_logic_achievement +{ + u32 pstr_name; }; struct classtype_audio diff --git a/models_src/mp_dev.mdl b/models_src/mp_dev.mdl index e2ffeb5..00eb7e8 100644 Binary files a/models_src/mp_dev.mdl and b/models_src/mp_dev.mdl differ diff --git a/player.h b/player.h index 0b6db88..e119ffc 100644 --- a/player.h +++ b/player.h @@ -472,17 +472,6 @@ VG_STATIC void player_update_post(void) budget -= advt; } -#if 0 - if( player.dist_accum >= 5.0f ) - { - audio_lock(); - audio_player_playclip( &audio_rewind_player, &audio_rewind[4] ); - audio_unlock(); - - player.dist_accum -= 5.0f; - } -#endif - player.rewind_time = vg_maxf( 0.0f, player.rewind_time ); float current_time = vg.time - player.diag_rewind_start, diff --git a/server.c b/server.c index dfe8be8..4b088c1 100644 --- a/server.c +++ b/server.c @@ -337,7 +337,9 @@ int main( int argc, char *argv[] ) /* TODO: Options to override, ammend, remove etc */ - vg_prealloc_quota( 80*1024*1024 ); + vg_set_mem_quota( 80*1024*1024 ); + vg_alloc_quota(); + highscores_init( 250000, 10000 ); if( !highscores_read() ) diff --git a/world.h b/world.h index 7b265cd..8b650a5 100644 --- a/world.h +++ b/world.h @@ -110,6 +110,7 @@ VG_STATIC struct gworld v3f render_gate_pos; int active_route_board; + int in_trigger; /* This is a small flag we use to changelevel. * It will not be cleared until all sounds stop playing @@ -126,7 +127,8 @@ VG_STATIC struct gworld * (world_gen.h) * -------------------------------------------------------------------------- */ - void *dynamic_vgl; + void *dynamic_vgl, + *audio_vgl; /* sub buffer of the audio buffer */ /* * Main world .mdl @@ -161,42 +163,46 @@ VG_STATIC struct gworld u32 audio_things_count; /* - * Relays, random, etc + * Relays */ - struct logic_entity + struct logic_relay { v3f pos; - enum logic_type logic_type; - int enabled; - /* indexes the action array */ - u32 action_start, action_count; + struct relay_target + { + u32 sub_id; + enum classtype classtype; + } + targets[4]; + u32 target_count; } - * logic_entities; - u32 logic_entity_count; + * logic_relays; + u32 relay_count; /* - * Action array + * Box trigger entities */ - struct logic_action + struct trigger_zone { - u32 event, /* on trigger, on enable, etc (TODO: Enum) */ - target_id; /* thing to target, 0: self */ + m4x3f transform, inv_transform; + struct relay_target target; } - * logic_actions; - u32 logic_action_count; + * triggers; + u32 trigger_count; /* - * Box trigger entities + * Achievements */ - struct trigger_zone + struct logic_achievement { - m4x3f transform, inv_transform; - u32 trigger_entity; + v3f pos; + const char *achievement_id; + u32 achieved; } - * triggers; - u32 trigger_count; + * logic_achievements; + u32 achievement_count; /* @@ -431,6 +437,77 @@ VG_STATIC void world_init(void) VG_MEMORY_SYSTEM ); } +VG_STATIC void world_audio_init(void) +{ + u32 size = vg_linear_remaining( vg_audio.audio_pool ) + - sizeof(vg_linear_allocator); + + world.audio_vgl = vg_create_linear_allocator( vg_audio.audio_pool, + size, VG_MEMORY_SYSTEM ); +} + +VG_STATIC void world_trigger_achievement( u32 uid ) +{ + struct logic_achievement *ach = &world.logic_achievements[ uid ]; + + if( ach->achieved ) + return; + + steam_set_achievement( ach->achievement_id ); + steam_store_achievements(); + + ach->achieved = 1; +} + +VG_STATIC void world_run_relay( struct relay_target *rt ); +VG_STATIC void world_trigger_relay( u32 uid ) +{ + struct logic_relay *relay = &world.logic_relays[ uid ]; + + for( int i=0; itarget_count; i++ ) + { + world_run_relay( &relay->targets[i] ); + } +} + +VG_STATIC void world_trigger_audio( u32 uid ) +{ + struct world_audio_thing *wat = &world.audio_things[ uid ]; + + audio_lock(); + audio_player_playclip( &wat->player, + &wat->temp_embedded_clip ); + audio_unlock(); +} + +VG_STATIC void world_run_relay( struct relay_target *rt ) +{ + struct entity_instruction + { + enum classtype classtype; + void (*p_trigger)( u32 uid ); + } + entity_instructions[] = + { + { k_classtype_logic_achievement, world_trigger_achievement }, + { k_classtype_logic_relay, world_trigger_relay }, + { k_classtype_audio, world_trigger_audio } + }; + + for( int i=0; iclasstype == rt->classtype ) + { + instr->p_trigger( rt->sub_id ); + return; + } + } + + vg_error( "Don't know how to trigger classtype %d\n", rt->classtype ); +} + VG_STATIC void world_update( v3f pos ) { if( world.switching_to_new_world ) @@ -502,14 +579,10 @@ VG_STATIC void world_update( v3f pos ) } } -#if 0 - VG_STATIC int in_zone = 0; - - int in_zone_this_time = 0; - - for( int i=0; iinv_transform, pos, local ); @@ -518,23 +591,12 @@ VG_STATIC void world_update( v3f pos ) (fabsf(local[1]) <= 1.0f) && (fabsf(local[2]) <= 1.0f) ) { - in_zone_this_time = 1; - - if( !in_zone && zone->ptarget ) - { - audio_lock(); - audio_player_playclip( &zone->ptarget->player, - &zone->ptarget->temp_embedded_clip ); - audio_unlock(); - } + in_trigger = 1; - if( !zone->triggered ) + if( !world.in_trigger ) { - steam_set_achievement( zone->name ); - steam_store_achievements(); + world_run_relay( &zone->target ); } - - zone->triggered = 1; } vg_line_boxf_transformed( zone->transform, (boxf){{-1.0f,-1.0f,-1.0f}, @@ -542,9 +604,7 @@ VG_STATIC void world_update( v3f pos ) 0xff00ff00 ); } - in_zone = in_zone_this_time; -#endif - + world.in_trigger = in_trigger; sfd_update(); } diff --git a/world_gen.h b/world_gen.h index 4605adf..16d64fd 100644 --- a/world_gen.h +++ b/world_gen.h @@ -115,6 +115,16 @@ VG_STATIC void world_ents_allocate(void) k_classtype_trigger, (void*)&world.triggers, sizeof(struct trigger_zone) + }, + { + k_classtype_logic_relay, + (void*)&world.logic_relays, + sizeof(struct logic_relay) + }, + { + k_classtype_logic_achievement, + (void*)&world.logic_achievements, + sizeof(struct logic_achievement) } }; @@ -129,6 +139,7 @@ VG_STATIC void world_ents_allocate(void) { if( pnode->classtype == entity_counts[j].ct ) { + pnode->sub_uid = entity_counts[j].count; entity_counts[j].count ++; break; } @@ -199,7 +210,7 @@ VG_STATIC void world_pct_audio( mdl_node *pnode ) thing->temp_embedded_clip.path = mdl_pstr( world.meta, aud->pstr_file ); thing->temp_embedded_clip.source_mode = k_audio_source_mono; - audio_clip_load( &thing->temp_embedded_clip ); + audio_clip_load( &thing->temp_embedded_clip, world.audio_vgl ); thing->player.name = mdl_pstr( world.meta, pnode->pstr_name ); thing->player.enqued = 0; @@ -207,6 +218,71 @@ VG_STATIC void world_pct_audio( mdl_node *pnode ) world.audio_things_count ++; } + +VG_STATIC void world_pct_trigger( mdl_node *pnode ) +{ + struct trigger_zone *trigger = &world.triggers[ world.trigger_count ]; + struct classtype_trigger *inf = mdl_get_entdata( world.meta, pnode ); + + if( inf->target ) + { + mdl_node *target_node = mdl_node_from_id( world.meta, inf->target ); + + trigger->target.sub_id = target_node->sub_uid; + trigger->target.classtype = target_node->classtype; + } + else + { + vg_warn( "Trigger with no target...\n" ); + return; + } + + mdl_node_transform( pnode, trigger->transform ); + m4x3_invert_full( trigger->transform, trigger->inv_transform ); + + world.trigger_count ++; +} + + +VG_STATIC void world_pct_relay( mdl_node *pnode ) +{ + struct logic_relay *relay = &world.logic_relays[ world.relay_count ]; + struct classtype_logic_relay *inf = mdl_get_entdata( world.meta, pnode ); + + relay->target_count = 0; + + for( int i=0; itargets); i++ ) + { + if( inf->targets[i] ) + { + struct relay_target *target = &relay->targets[relay->target_count ++]; + mdl_node *other = mdl_node_from_id( world.meta, inf->targets[i] ); + + target->classtype = other->classtype; + target->sub_id = other->sub_uid; + } + } + + v3_copy( pnode->co, relay->pos ); + world.relay_count ++; +} + + +VG_STATIC void world_pct_achievement( mdl_node *pnode ) +{ + struct logic_achievement *ach = + &world.logic_achievements[ world.achievement_count ]; + struct classtype_logic_achievement *inf = + mdl_get_entdata( world.meta, pnode ); + + v3_copy( pnode->co, ach->pos ); + ach->achievement_id = mdl_pstr( world.meta, inf->pstr_name ); + ach->achieved = 0; + + world.achievement_count ++; +} + + VG_STATIC void world_entities_process(void) { struct entity_instruction @@ -219,6 +295,9 @@ VG_STATIC void world_entities_process(void) { k_classtype_spawn, world_pct_spawn }, { k_classtype_water, world_pct_water }, { k_classtype_audio, world_pct_audio }, + { k_classtype_trigger, world_pct_trigger }, + { k_classtype_logic_relay, world_pct_relay }, + { k_classtype_logic_achievement, world_pct_achievement } }; for( int i=0; iinfo.node_count; i++ ) @@ -235,50 +314,7 @@ VG_STATIC void world_entities_process(void) break; } } - -#if 0 - else if( pnode->classtype == k_classtype_achievement_box ) - { - world.achievement_zones = - buffer_reserve( world.achievement_zones, - world.achievement_zones_count, - &world.achievement_zones_cap, 1, - sizeof(struct achievement_zone) ); - - struct achievement_zone *zone = &world.achievement_zones[ - world.achievement_zones_count ++ ]; - - - struct classtype_achievement_box *box = mdl_get_entdata(mworld,pnode); - - mdl_node_transform( pnode, zone->transform ); - m4x3_invert_full( zone->transform, zone->inv_transform ); - vg_strncpy( mdl_pstr(mworld, box->pstr_name), zone->name, 31 ); - zone->name[31] = 0x00; - zone->triggered = 0; - - if( box->trigger ) - zone->ptarget_delegated = mdl_node_from_id( mworld, box->trigger ); - else - zone->ptarget_delegated = NULL; - } -#endif } - -#if 0 - /* fixup links */ - for( int i=0; iptarget_delegated ) - { - u32 id = ach->ptarget_delegated->sub_uid; - ach->ptarget = &world.audio_things[ id ]; - } - else - ach->ptarget = NULL; - } -#endif } VG_STATIC void world_generate(void) @@ -413,6 +449,7 @@ VG_STATIC void world_generate(void) world.scene_no_collide = NULL; } +VG_STATIC int reset_player( int argc, char const *argv[] ); VG_STATIC void world_post_process(void) { /* initialize audio if need be */ @@ -505,6 +542,8 @@ VG_STATIC void world_post_process(void) /* * Setup scene collider */ + + reset_player( 1, (const char *[]){"start"} ); } @@ -538,6 +577,7 @@ VG_STATIC void world_unload(void) /* delete the entire block of memory */ vg_linear_clear( world.dynamic_vgl ); + vg_linear_clear( world.audio_vgl ); /* clean dangling pointers */ world.meta = NULL; @@ -556,15 +596,15 @@ VG_STATIC void world_unload(void) world.audio_things = NULL; world.audio_things_count = 0; - world.logic_entities = NULL; - world.logic_entity_count = 0; - - world.logic_actions = NULL; - world.logic_action_count = 0; - world.triggers = NULL; world.trigger_count = 0; + world.logic_relays = NULL; + world.relay_count = 0; + + world.logic_achievements = NULL; + world.achievement_count = 0; + world.nodes = NULL; world.node_count = 0;