2 * Copyright (C) 2021-2023 Mt.ZERO Software, Harry Godden - All Rights Reserved
9 #include "world_gate.h"
11 #include "skaterift.h"
18 #include "world_water.h"
19 #include "player_remote.h"
22 * Update the transform matrices for gate
24 static void gate_transform_update( ent_gate
*gate
){
25 if( gate
->flags
& k_ent_gate_flip
){
27 q_axis_angle( qflip
, (v3f
){0.0f
,1.0f
,0.0f
}, VG_PIf
);
28 q_mul( gate
->q
[1], qflip
, gate
->q
[1] );
31 m4x3f to_local
, recv_to_world
;
33 q_m3x3( gate
->q
[0], gate
->to_world
);
34 v3_copy( gate
->co
[0], gate
->to_world
[3] );
36 m4x3_invert_affine( gate
->to_world
, to_local
);
38 q_m3x3( gate
->q
[1], recv_to_world
);
39 v3_copy( gate
->co
[1], recv_to_world
[3] );
40 m4x3_mul( recv_to_world
, to_local
, gate
->transport
);
43 static void world_gates_init(void)
45 vg_info( "world_gates_init\n" );
47 shader_model_gate_register();
49 vg_linear_clear( vg_mem
.scratch
);
52 mdl_open( &mgate
, "models/rs_gate.mdl", vg_mem
.scratch
);
53 mdl_load_metadata_block( &mgate
, vg_mem
.scratch
);
55 mdl_mesh
*surface
= mdl_find_mesh( &mgate
, "rs_gate" );
56 mdl_submesh
*sm
= mdl_arritm(&mgate
.submeshs
,surface
->submesh_start
);
57 world_gates
.sm_surface
= *sm
;
59 const char *names
[] = { "rs_gate_marker", "rs_gate_marker.001",
60 "rs_gate_marker.002", "rs_gate_marker.003" };
62 for( int i
=0; i
<4; i
++ ){
63 mdl_mesh
*marker
= mdl_find_mesh( &mgate
, names
[i
] );
64 sm
= mdl_arritm( &mgate
.submeshs
, marker
->submesh_start
);
65 world_gates
.sm_marker
[i
] = *sm
;
68 mdl_mesh
*icosphere
= mdl_find_mesh( &mgate
, "rs_icosphere" );
69 world_gates
.sm_icosphere
=
70 *((mdl_submesh
*)mdl_arritm( &mgate
.submeshs
, icosphere
->submesh_start
));
72 mdl_async_load_glmesh( &mgate
, &world_gates
.mesh
);
76 static void ent_gate_get_mdl_mtx( ent_gate
*gate
, m4x3f mmdl
){
77 m4x3_copy( gate
->to_world
, mmdl
);
79 if( !(gate
->flags
& k_ent_gate_custom_mesh
) ){
80 m3x3_scale( mmdl
, (v3f
){ gate
->dimensions
[0],
81 gate
->dimensions
[1], 1.0f
} );
86 * Render the view through a gate
88 static int render_gate( world_instance
*world
, world_instance
*world_inside
,
89 ent_gate
*gate
, camera
*cam
, int layer_depth
)
92 m3x3_mulv( cam
->transform
, (v3f
){0.0f
,0.0f
,-1.0f
}, viewdir
);
93 q_mulv( gate
->q
[0], (v3f
){0.0f
,0.0f
,-1.0f
}, gatedir
);
96 v3_sub( cam
->pos
, gate
->co
[0], v0
);
98 float dist
= v3_dot(v0
, gatedir
);
104 if( v3_dist( cam
->pos
, gate
->co
[0] ) > 100.0f
)
108 f32 w
= gate
->dimensions
[0],
109 h
= gate
->dimensions
[1];
112 m4x3_mulv( gate
->to_world
, (v3f
){-w
,-h
,0.0f
}, a
);
113 m4x3_mulv( gate
->to_world
, (v3f
){ w
,-h
,0.0f
}, b
);
114 m4x3_mulv( gate
->to_world
, (v3f
){ w
, h
,0.0f
}, c
);
115 m4x3_mulv( gate
->to_world
, (v3f
){-w
, h
,0.0f
}, d
);
117 vg_line( a
,b
, 0xffffa000 );
118 vg_line( b
,c
, 0xffffa000 );
119 vg_line( c
,d
, 0xffffa000 );
120 vg_line( d
,a
, 0xffffa000 );
121 vg_line( gate
->co
[0], gate
->co
[1], 0xff0000ff );
124 /* update gate camera */
125 world_gates
.cam
.fov
= cam
->fov
;
126 world_gates
.cam
.nearz
= 0.1f
;
127 world_gates
.cam
.farz
= 2000.0f
;
129 m4x3_mul( gate
->transport
, cam
->transform
, world_gates
.cam
.transform
);
130 camera_update_view( &world_gates
.cam
);
131 camera_update_projection( &world_gates
.cam
);
133 /* Add special clipping plane to projection */
135 q_mulv( gate
->q
[1], (v3f
){0.0f
,0.0f
,-1.0f
}, surface
);
136 surface
[3] = v3_dot( surface
, gate
->co
[1] );
138 m4x3_mulp( world_gates
.cam
.transform_inverse
, surface
, surface
);
139 surface
[3] = -fabsf(surface
[3]);
142 m4x4_clip_projection( world_gates
.cam
.mtx
.p
, surface
);
144 /* Ready to draw with new camrea */
145 camera_finalize( &world_gates
.cam
);
147 vg_line_point( world_gates
.cam
.transform
[3], 0.3f
, 0xff00ff00 );
149 shader_model_gate_use();
150 shader_model_gate_uPv( cam
->mtx
.pv
);
151 shader_model_gate_uCam( cam
->pos
);
152 shader_model_gate_uColour( (v4f
){0.0f
,1.0f
,0.0f
,0.0f
} );
153 shader_model_gate_uTime( vg
.time
*0.25f
);
154 shader_model_gate_uInvRes( (v2f
){
155 1.0f
/ (float)vg
.window_x
,
156 1.0f
/ (float)vg
.window_y
});
158 glEnable( GL_STENCIL_TEST
);
159 glStencilOp( GL_KEEP
, GL_KEEP
, GL_REPLACE
);
160 glStencilFunc( GL_ALWAYS
, 1, 0xFF );
161 glStencilMask( 0xFF );
162 glDisable( GL_CULL_FACE
);
165 ent_gate_get_mdl_mtx( gate
, mmdl
);
166 shader_model_gate_uMdl( mmdl
);
168 if( gate
->flags
& k_ent_gate_custom_mesh
){
169 mesh_bind( &world
->mesh_no_collide
);
170 for( u32 i
=0; i
<gate
->submesh_count
; i
++ ){
171 mdl_submesh
*sm
= mdl_arritm( &world
->meta
.submeshs
,
172 gate
->submesh_start
+i
);
173 mdl_draw_submesh( sm
);
177 mesh_bind( &world_gates
.mesh
);
178 mdl_draw_submesh( &world_gates
.sm_surface
);
181 glClear( GL_DEPTH_BUFFER_BIT
);
182 glStencilFunc( GL_EQUAL
, 1, 0xFF );
183 glStencilMask( 0x00 );
184 glEnable( GL_CULL_FACE
);
187 render_world( world_inside
, &world_gates
.cam
, layer_depth
);
188 render_remote_players( world_inside
, &world_gates
.cam
);
191 glDisable( GL_STENCIL_TEST
);
193 render_water_texture( world_inside
, &world_gates
.cam
, layer_depth
);
194 render_fb_bind( gpipeline
.fb_main
, 1 );
196 glEnable( GL_STENCIL_TEST
);
198 render_water_surface( world_inside
, &world_gates
.cam
);
200 glStencilMask( 0xFF );
201 glStencilFunc( GL_ALWAYS
, 1, 0xFF );
202 glDisable( GL_STENCIL_TEST
);
209 * Intersect the plane of a gate with a line segment, plane coordinate result
212 static int gate_intersect_plane( ent_gate
*gate
,
213 v3f pos
, v3f last
, v2f where
)
216 q_mulv( gate
->q
[0], (v3f
){0.0f
,0.0f
,-1.0f
}, surface
);
217 surface
[3] = v3_dot( surface
, gate
->co
[0] );
219 v3f v0
, c
, delta
, p0
;
220 v3_sub( pos
, last
, v0
);
221 float l
= v3_length( v0
);
226 v3_divs( v0
, l
, v0
);
228 v3_muls( surface
, surface
[3], c
);
229 v3_sub( c
, last
, delta
);
231 float d
= v3_dot( surface
, v0
);
234 float t
= v3_dot(delta
, surface
) / d
;
235 if( t
>= 0.0f
&& t
<= l
){
237 v3_muladds( last
, v0
, t
, local
);
238 v3_sub( gate
->co
[0], local
, rel
);
240 where
[0] = v3_dot( rel
, gate
->to_world
[0] );
241 where
[1] = v3_dot( rel
, gate
->to_world
[1] );
243 where
[0] /= v3_dot( gate
->to_world
[0], gate
->to_world
[0] );
244 where
[1] /= v3_dot( gate
->to_world
[1], gate
->to_world
[1] );
254 * Intersect specific gate
256 static int gate_intersect( ent_gate
*gate
, v3f pos
, v3f last
){
259 if( gate_intersect_plane( gate
, pos
, last
, xy
) ){
260 if( (fabsf(xy
[0]) <= gate
->dimensions
[0]) &&
261 (fabsf(xy
[1]) <= gate
->dimensions
[1]) ){
270 * Intersect all gates in the world
272 static u32
world_intersect_gates( world_instance
*world
, v3f pos
, v3f last
){
273 for( u32 i
=0; i
<mdl_arrcount(&world
->ent_gate
); i
++ ){
274 ent_gate
*gate
= mdl_arritm( &world
->ent_gate
, i
);
276 if( !(gate
->flags
& k_ent_gate_linked
) ) continue;
277 if( gate
->flags
& k_ent_gate_locked
) continue;
279 if( gate
->flags
& k_ent_gate_nonlocal_DELETED
)
282 if( gate_intersect( gate
, pos
, last
) )
283 return mdl_entity_id( k_ent_gate
, i
);
289 static void ent_gate_call( world_instance
*world
, ent_call
*call
){
290 u32 index
= mdl_entity_id_id( call
->id
);
291 ent_gate
*gate
= mdl_arritm( &world
->ent_gate
, index
);
293 if( call
->function
== 0 ){ /* unlock() */
294 gate
->flags
&= ~k_ent_gate_locked
;
297 vg_print_backtrace();
298 vg_error( "Unhandled function id: %u\n", call
->function
);
302 #endif /* WORLD_GATE_C */