frame rate independence
[carveJwlIkooP6JGAAIwe30JlM.git] / world_gate.h
1 /*
2 * Copyright (C) 2021-2022 Mt.ZERO Software, Harry Godden - All Rights Reserved
3 */
4
5 #ifndef WORLD_GATE_H
6 #define WORLD_GATE_H
7
8 #define GATE_RENDER_PERFORMANCE
9
10 #include "common.h"
11 #include "model.h"
12 #include "render.h"
13
14 #ifndef GATE_RENDER_PERFORMANCE
15 #include "shaders/gate.h"
16 #else
17 #include "shaders/gatelq.h"
18 #endif
19
20 #include "world_water.h"
21
22
23 typedef struct teleport_gate teleport_gate;
24
25 static struct
26 {
27 struct framebuffer fb;
28 glmesh mdl;
29 }
30 grender =
31 {
32 .fb = {
33 .format = GL_RGB,
34 .div = 1
35 }
36 };
37
38 static void gate_transform_update( teleport_gate *gate )
39 {
40 m4x3f to_local;
41
42 q_m3x3( gate->q[0], gate->to_world );
43 v3_copy( gate->co[0], gate->to_world[3] );
44
45 m4x3_invert_affine( gate->to_world, to_local );
46
47 q_m3x3( gate->q[1], gate->recv_to_world );
48 v3_copy( gate->co[1], gate->recv_to_world[3] );
49 m4x3_mul( gate->recv_to_world, to_local, gate->transport );
50 }
51
52 static void world_gates_init(void)
53 {
54 vg_info( "world_gates_init\n" );
55
56 #ifndef GATE_RENDER_PERFORMANCE
57 shader_gate_register();
58 #else
59 shader_gatelq_register();
60 #endif
61
62 mdl_header *mgate = mdl_load( "models/rs_gate.mdl" );
63
64 vg_acquire_thread_sync();
65 {
66 fb_init( &grender.fb );
67 mdl_unpack_glmesh( mgate, &grender.mdl );
68 }
69 vg_release_thread_sync();
70 }
71
72 static void world_gates_free(void*_)
73 {
74 fb_free( &grender.fb );
75 }
76
77 static void gate_fb_resize(void)
78 {
79 fb_resize( &grender.fb );
80 }
81
82 static int render_gate( teleport_gate *gate, v3f viewpos, m4x3f camera )
83 {
84 v3f viewdir, gatedir;
85 m3x3_mulv( camera, (v3f){0.0f,0.0f,-1.0f}, viewdir );
86 m3x3_mulv( gate->to_world, (v3f){0.0f,0.0f,-1.0f}, gatedir );
87
88 v3f v0;
89 v3_sub( viewpos, gate->co[0], v0 );
90 if( v3_dot(v0, gatedir) >= 0.0f )
91 return 0;
92
93 if( v3_dist( viewpos, gate->co[0] ) > 100.0f )
94 return 0;
95
96 v3f a,b,c,d;
97
98 float sx = gate->dims[0],
99 sy = gate->dims[1];
100 m4x3_mulv( gate->to_world, (v3f){-sx,-sy,0.0f}, a );
101 m4x3_mulv( gate->to_world, (v3f){ sx,-sy,0.0f}, b );
102 m4x3_mulv( gate->to_world, (v3f){ sx, sy,0.0f}, c );
103 m4x3_mulv( gate->to_world, (v3f){-sx, sy,0.0f}, d );
104
105 vg_line( a,b, 0xffffa000 );
106 vg_line( b,c, 0xffffa000 );
107 vg_line( c,d, 0xffffa000 );
108 vg_line( d,a, 0xffffa000 );
109
110 vg_line2( gate->co[0], gate->co[1], 0xff0000ff, 0x00000000 );
111
112 m4x3f cam_new;
113 m4x3_mul( gate->transport, camera, cam_new );
114
115 vg_line_pt3( cam_new[3], 0.3f, 0xff00ff00 );
116
117 m4x3f gate_xform;
118 m4x3_copy( gate->to_world, gate_xform );
119 m4x3_scalev( gate_xform, (v3f){ gate->dims[0], gate->dims[1], 1.0f } );
120
121 m4x3f inverse;
122 m4x3_invert_affine( cam_new, inverse );
123
124 m4x4f view;
125 m4x3_expand( inverse, view );
126
127 v4f surface;
128 m3x3_mulv( gate->recv_to_world, (v3f){0.0f,0.0f,-1.0f}, surface );
129 surface[3] = v3_dot( surface, gate->co[1] );
130
131 m4x4f projection;
132 pipeline_projection( projection, 0.1f, 900.0f );
133
134 m4x3_mulp( inverse, surface, surface );
135 surface[3] = -fabsf(surface[3]);
136 plane_clip_projection( projection, surface );
137
138 m4x4_mul( projection, view, projection );
139
140 #ifndef GATE_RENDER_PERFORMANCE
141 fb_use( &grender.fb );
142 glClearColor( 0.11f, 0.35f, 0.37f, 1.0f );
143 glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT );
144 #else
145 shader_gatelq_use();
146 shader_gatelq_uPv( vg.pv );
147 shader_gatelq_uMdl( gate_xform );
148 shader_gatelq_uCam( viewpos );
149 shader_gatelq_uTime( vg.time*0.25f );
150 shader_gatelq_uInvRes( (v2f){
151 1.0f / (float)vg.window_x,
152 1.0f / (float)vg.window_y });
153
154 glEnable( GL_STENCIL_TEST );
155 glStencilOp( GL_KEEP, GL_KEEP, GL_REPLACE );
156 glStencilFunc( GL_ALWAYS, 1, 0xFF );
157 glStencilMask( 0xFF );
158
159 mesh_bind( &grender.mdl );
160 mesh_draw( &grender.mdl );
161
162 glClear( GL_DEPTH_BUFFER_BIT );
163 glStencilFunc( GL_EQUAL, 1, 0xFF );
164 glStencilMask( 0x00 );
165 #endif
166
167 render_world( projection, cam_new );
168
169 #ifndef GATE_RENDER_PERFORMANCE
170
171 /*
172 * NOTE: Need to find a way to draw a stencil buffer into the water
173 * rendering
174 */
175
176 render_water_texture( cam_new );
177 fb_use( &grender.fb );
178
179 render_water_surface( projection, cam_new );
180 fb_use( NULL );
181
182 shader_gate_use();
183
184 shader_gate_uPv( vg_pv );
185 shader_gate_uMdl( gate_xform );
186
187 fb_bindtex( &grender.fb, 0 );
188
189 shader_gate_uCam( viewpos );
190 shader_gate_uTexMain( 0 );
191 shader_gate_uTexWater( 1 );
192 shader_gate_uTime( vg_time*0.25f );
193 shader_gate_uInvRes( (v2f){
194 1.0f / (float)vg_window_x,
195 1.0f / (float)vg_window_y });
196
197 glEnable(GL_BLEND);
198 glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
199 glBlendEquation(GL_FUNC_ADD);
200
201 mesh_bind( &grender.mdl );
202 mesh_draw( &grender.mdl );
203
204 glDisable(GL_BLEND);
205 #else
206 glDisable( GL_STENCIL_TEST );
207
208 render_water_texture( cam_new );
209 fb_use( NULL );
210 glEnable( GL_STENCIL_TEST );
211
212 render_water_surface( projection, cam_new );
213
214 glStencilMask( 0xFF );
215 glStencilFunc( GL_ALWAYS, 1, 0xFF );
216 glDisable( GL_STENCIL_TEST );
217 #endif
218
219 return 1;
220 }
221
222 static int gate_intersect( teleport_gate *gate, v3f pos, v3f last )
223 {
224 v4f surface;
225 m3x3_mulv( gate->to_world, (v3f){0.0f,0.0f,-1.0f}, surface );
226 surface[3] = v3_dot( surface, gate->co[0] );
227
228 v3f v0, c, delta, p0;
229 v3_sub( pos, last, v0 );
230 float l = v3_length( v0 );
231 v3_divs( v0, l, v0 );
232
233 v3_muls( surface, surface[3], c );
234 v3_sub( c, last, delta );
235
236 float d = v3_dot(surface, v0);
237
238 if( d > 0.00001f )
239 {
240 float t = v3_dot(delta, surface) / d;
241 if( t >= 0.0f && t <= l )
242 {
243 v3f local, rel;
244 v3_muladds( last, v0, t, local );
245 v3_sub( gate->co[0], local, rel );
246
247 v3f vup, vside;
248 m3x3_mulv( gate->to_world, (v3f){0.0f,1.0f,0.0f}, vup );
249 m3x3_mulv( gate->to_world, (v3f){1.0f,0.0f,0.0f}, vside );
250
251 v2f xy = { v3_dot( rel, vside ), v3_dot( rel, vup ) };
252
253 if( fabsf(xy[0]) <= gate->dims[0] && fabsf(xy[1]) <= gate->dims[1] )
254 {
255 return 1;
256 }
257 }
258 }
259
260 return 0;
261 }
262
263 #endif /* WORLD_GATE_H */