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"
21 * Update the transform matrices for gate
23 VG_STATIC
void gate_transform_update( ent_gate
*gate
)
25 m4x3f to_local
, recv_to_world
;
27 q_m3x3( gate
->q
[0], gate
->to_world
);
28 v3_copy( gate
->co
[0], gate
->to_world
[3] );
30 m4x3_invert_affine( gate
->to_world
, to_local
);
32 q_m3x3( gate
->q
[1], recv_to_world
);
33 v3_copy( gate
->co
[1], recv_to_world
[3] );
34 m4x3_mul( recv_to_world
, to_local
, gate
->transport
);
36 m3x3_scale( gate
->to_world
, (v3f
){ gate
->dimensions
[0],
37 gate
->dimensions
[1], 1.0f
} );
40 VG_STATIC
void world_gates_init(void)
42 vg_info( "world_gates_init\n" );
44 shader_model_gate_register();
46 vg_linear_clear( vg_mem
.scratch
);
49 mdl_open( &mgate
, "models/rs_gate.mdl", vg_mem
.scratch
);
50 mdl_load_metadata_block( &mgate
, vg_mem
.scratch
);
52 mdl_mesh
*surface
= mdl_find_mesh( &mgate
, "rs_gate" );
53 mdl_submesh
*sm
= mdl_arritm(&mgate
.submeshs
,surface
->submesh_start
);
54 world_gates
.sm_surface
= *sm
;
56 const char *names
[] = { "rs_gate_marker", "rs_gate_marker.001",
57 "rs_gate_marker.002", "rs_gate_marker.003" };
59 for( int i
=0; i
<4; i
++ ){
60 mdl_mesh
*marker
= mdl_find_mesh( &mgate
, names
[i
] );
61 sm
= mdl_arritm( &mgate
.submeshs
, marker
->submesh_start
);
62 world_gates
.sm_marker
[i
] = *sm
;
65 mdl_async_load_glmesh( &mgate
, &world_gates
.mesh
);
70 * Render the view through a gate
72 VG_STATIC
int render_gate( world_instance
*world_inside
,
73 ent_gate
*gate
, camera
*cam
, int layer_depth
)
76 m3x3_mulv( cam
->transform
, (v3f
){0.0f
,0.0f
,-1.0f
}, viewdir
);
77 q_mulv( gate
->q
[0], (v3f
){0.0f
,0.0f
,-1.0f
}, gatedir
);
80 v3_sub( cam
->pos
, gate
->co
[0], v0
);
82 float dist
= v3_dot(v0
, gatedir
);
88 if( v3_dist( cam
->pos
, gate
->co
[0] ) > 100.0f
)
94 m4x3_mulv( gate
->to_world
, (v3f
){-1.0f
,-1.0f
,0.0f
}, a
);
95 m4x3_mulv( gate
->to_world
, (v3f
){ 1.0f
,-1.0f
,0.0f
}, b
);
96 m4x3_mulv( gate
->to_world
, (v3f
){ 1.0f
, 1.0f
,0.0f
}, c
);
97 m4x3_mulv( gate
->to_world
, (v3f
){-1.0f
, 1.0f
,0.0f
}, d
);
99 vg_line( a
,b
, 0xffffa000 );
100 vg_line( b
,c
, 0xffffa000 );
101 vg_line( c
,d
, 0xffffa000 );
102 vg_line( d
,a
, 0xffffa000 );
104 vg_line2( gate
->co
[0], gate
->co
[1], 0xff0000ff, 0x00000000 );
107 /* update gate camera */
108 gate_camera
.fov
= cam
->fov
;
109 gate_camera
.nearz
= 0.1f
;
110 gate_camera
.farz
= 2000.0f
;
112 m4x3_mul( gate
->transport
, cam
->transform
, gate_camera
.transform
);
113 camera_update_view( &gate_camera
);
114 camera_update_projection( &gate_camera
);
116 /* Add special clipping plane to projection */
118 q_mulv( gate
->q
[1], (v3f
){0.0f
,0.0f
,-1.0f
}, surface
);
119 surface
[3] = v3_dot( surface
, gate
->co
[1] );
121 m4x3_mulp( gate_camera
.transform_inverse
, surface
, surface
);
122 surface
[3] = -fabsf(surface
[3]);
125 m4x4_clip_projection( gate_camera
.mtx
.p
, surface
);
127 /* Ready to draw with new camrea */
128 camera_finalize( &gate_camera
);
130 vg_line_pt3( gate_camera
.transform
[3], 0.3f
, 0xff00ff00 );
132 shader_model_gate_use();
133 shader_model_gate_uPv( cam
->mtx
.pv
);
134 shader_model_gate_uMdl( gate
->to_world
);
135 shader_model_gate_uCam( cam
->pos
);
136 shader_model_gate_uColour( (v4f
){0.0f
,1.0f
,0.0f
,0.0f
} );
137 shader_model_gate_uTime( vg
.time
*0.25f
);
138 shader_model_gate_uInvRes( (v2f
){
139 1.0f
/ (float)vg
.window_x
,
140 1.0f
/ (float)vg
.window_y
});
142 glEnable( GL_STENCIL_TEST
);
143 glStencilOp( GL_KEEP
, GL_KEEP
, GL_REPLACE
);
144 glStencilFunc( GL_ALWAYS
, 1, 0xFF );
145 glStencilMask( 0xFF );
147 mesh_bind( &world_gates
.mesh
);
148 mdl_draw_submesh( &world_gates
.sm_surface
);
150 glClear( GL_DEPTH_BUFFER_BIT
);
151 glStencilFunc( GL_EQUAL
, 1, 0xFF );
152 glStencilMask( 0x00 );
155 render_world( world_inside
, &gate_camera
, layer_depth
);
158 glDisable( GL_STENCIL_TEST
);
160 render_water_texture( world_inside
, &gate_camera
, layer_depth
);
161 render_fb_bind( gpipeline
.fb_main
, 1 );
163 glEnable( GL_STENCIL_TEST
);
165 render_water_surface( world_inside
, &gate_camera
);
167 glStencilMask( 0xFF );
168 glStencilFunc( GL_ALWAYS
, 1, 0xFF );
169 glDisable( GL_STENCIL_TEST
);
176 * Intersect the plane of a gate with a line segment, plane coordinate result
179 VG_STATIC
int gate_intersect_plane( ent_gate
*gate
,
180 v3f pos
, v3f last
, v2f where
)
183 q_mulv( gate
->q
[0], (v3f
){0.0f
,0.0f
,-1.0f
}, surface
);
184 surface
[3] = v3_dot( surface
, gate
->co
[0] );
186 v3f v0
, c
, delta
, p0
;
187 v3_sub( pos
, last
, v0
);
188 float l
= v3_length( v0
);
193 v3_divs( v0
, l
, v0
);
195 v3_muls( surface
, surface
[3], c
);
196 v3_sub( c
, last
, delta
);
198 float d
= v3_dot( surface
, v0
);
201 float t
= v3_dot(delta
, surface
) / d
;
202 if( t
>= 0.0f
&& t
<= l
){
204 v3_muladds( last
, v0
, t
, local
);
205 v3_sub( gate
->co
[0], local
, rel
);
207 where
[0] = v3_dot( rel
, gate
->to_world
[0] );
208 where
[1] = v3_dot( rel
, gate
->to_world
[1] );
210 where
[0] /= v3_dot( gate
->to_world
[0], gate
->to_world
[0] );
211 where
[1] /= v3_dot( gate
->to_world
[1], gate
->to_world
[1] );
221 * Intersect specific gate
223 VG_STATIC
int gate_intersect( ent_gate
*gate
, v3f pos
, v3f last
)
227 if( gate_intersect_plane( gate
, pos
, last
, xy
) ){
228 if( fabsf(xy
[0]) <= 1.0f
&& fabsf(xy
[1]) <= 1.0f
){
237 * Intersect all gates in the world
239 VG_STATIC ent_gate
*world_intersect_gates( world_instance
*world
,
242 for( u32 i
=0; i
<mdl_arrcount(&world
->ent_gate
); i
++ ){
243 ent_gate
*gate
= mdl_arritm( &world
->ent_gate
, i
);
244 if( gate
->type
== k_gate_type_unlinked
||
245 gate
->type
== k_gate_type_nonlocal_unlinked
)
248 if( gate
->type
== k_gate_type_nonlocel
){
249 if( skaterift
.async_op
== k_async_op_world_loading
||
250 skaterift
.async_op
== k_async_op_world_preloading
){
255 if( gate_intersect( gate
, pos
, last
) ){
264 * detatches any nonlocal gates
266 VG_STATIC
void world_unlink_nonlocal( world_instance
*world
)
268 for( u32 j
=0; j
<mdl_arrcount(&world
->ent_gate
); j
++ ){
269 ent_gate
*gate
= mdl_arritm( &world
->ent_gate
, j
);
271 if( gate
->type
== k_gate_type_nonlocel
){
272 gate
->type
= k_gate_type_nonlocal_unlinked
;
278 * attatches nonlocal gates, to be called from main thread ONLY!
280 VG_STATIC
void world_link_nonlocal_async( void *payload
, u32 size
)
282 world_instance
*world
= payload
;
283 u32 world_id
= world
- world_static
.worlds
;
285 for( u32 j
=0; j
<mdl_arrcount(&world
->ent_gate
); j
++ ){
286 ent_gate
*gate
= mdl_arritm( &world
->ent_gate
, j
);
288 if( gate
->type
== k_gate_type_nonlocal_unlinked
){
289 const char *key
= mdl_pstr( &world
->meta
, gate
->key
);
290 vg_info( "key: %s\n", key
);
292 for( u32 i
=0; i
<vg_list_size(world_static
.worlds
); i
++ ){
293 world_instance
*other
= &world_static
.worlds
[i
];
294 if( other
== world
) continue;
295 if( other
->status
!= k_world_status_loaded
) continue;
296 vg_info( "Checking world %u for key matches\n", i
);
298 for( u32 j
=0; j
<mdl_arrcount( &other
->ent_gate
); j
++ ){
299 ent_gate
*gate2
= mdl_arritm( &other
->ent_gate
, j
);
300 if( gate2
->type
!= k_gate_type_nonlocal_unlinked
) continue;
302 const char *key2
= mdl_pstr( &other
->meta
, gate2
->key
);
303 vg_info( " key2: %s\n", key2
);
305 if( strcmp( key
, key2
) ) continue;
307 vg_success( "Non-local matching pair '%s' found. (%u:%u)\n",
310 gate
->type
= k_gate_type_nonlocel
;
311 gate2
->type
= k_gate_type_nonlocel
;
313 gate2
->target
= world_id
;
315 v3_copy( gate
->co
[0], gate2
->co
[1] );
316 v3_copy( gate2
->co
[0], gate
->co
[1] );
317 v4_copy( gate
->q
[0], gate2
->q
[1] );
318 v4_copy( gate2
->q
[0], gate
->q
[1] );
321 q_axis_angle( qflip
, (v3f
){0.0f
,1.0f
,0.0f
}, VG_PIf
);
322 q_mul( gate
->q
[0], qflip
, gate
->q
[0] );
323 q_mul( gate
->q
[1], qflip
, gate
->q
[1] );
325 gate_transform_update( gate
);
326 gate_transform_update( gate2
);
336 #endif /* WORLD_GATE_C */