option between water plane / water trigger
[carveJwlIkooP6JGAAIwe30JlM.git] / world_water.c
1 /*
2 * Copyright (C) 2021-2023 Mt.ZERO Software, Harry Godden - All Rights Reserved
3 */
4
5 #include "world_water.h"
6 #include "world_render.h"
7 #include "render.h"
8 #include "shaders/scene_water.h"
9 #include "shaders/scene_water_fast.h"
10 #include "scene.h"
11 #include "player.h"
12 #include "player_walk.h"
13 #include "player_dead.h"
14
15 struct world_water world_water;
16
17 void world_water_init(void)
18 {
19 vg_info( "world_water_init\n" );
20
21 vg_tex2d_load_qoi_async_file( "textures/water_surf.qoi",
22 VG_TEX2D_LINEAR|VG_TEX2D_REPEAT,
23 &world_water.tex_water_surf );
24
25 vg_success( "done\n" );
26 }
27
28 void water_set_surface( world_instance *world, float height )
29 {
30 world->water.height = height;
31 v4_copy( (v4f){ 0.0f, 1.0f, 0.0f, height }, world->water.plane );
32 }
33
34 void world_link_lighting_ub( world_instance *world, GLuint shader );
35 void world_bind_position_texture( world_instance *world,
36 GLuint shader, GLuint location,
37 int slot );
38 void world_bind_light_array( world_instance *world,
39 GLuint shader, GLuint location,
40 int slot );
41 void world_bind_light_index( world_instance *world,
42 GLuint shader, GLuint location,
43 int slot );
44
45 /*
46 * Does not write motion vectors
47 */
48 void render_water_texture( world_instance *world, vg_camera *cam )
49 {
50 if( !world->water.enabled || (vg.quality_profile == k_quality_profile_low) )
51 return;
52
53 /* Draw reflection buffa */
54 render_fb_bind( gpipeline.fb_water_reflection, 1 );
55 glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT );
56
57 /*
58 * Create flipped view matrix. Don't care about motion vectors
59 */
60 float cam_height = cam->transform[3][1] - world->water.height;
61
62 vg_camera water_cam;
63 water_cam.farz = cam->farz;
64 water_cam.nearz = cam->nearz;
65 v3_copy( cam->transform[3], water_cam.transform[3] );
66 water_cam.transform[3][1] -= 2.0f * cam_height;
67
68 m3x3f flip;
69 m3x3_identity( flip );
70 flip[1][1] = -1.0f;
71 m3x3_mul( flip, cam->transform, water_cam.transform );
72
73 vg_camera_update_view( &water_cam );
74
75 /*
76 * Create clipped projection
77 */
78 v4f clippa = { 0.0f, 1.0f, 0.0f, world->water.height-0.1f };
79 m4x3_mulp( water_cam.transform_inverse, clippa, clippa );
80 clippa[3] *= -1.0f;
81
82 m4x4_copy( cam->mtx.p, water_cam.mtx.p );
83 m4x4_clip_projection( water_cam.mtx.p, clippa );
84
85 vg_camera_finalize( &water_cam );
86
87 /*
88 * Draw world
89 */
90 glEnable( GL_DEPTH_TEST );
91 glDisable( GL_BLEND );
92 glCullFace( GL_FRONT );
93 render_world( world, &water_cam, 0, 1, 0, 1 );
94 glCullFace( GL_BACK );
95
96 /*
97 * Create beneath view matrix
98 */
99 vg_camera beneath_cam;
100 render_fb_bind( gpipeline.fb_water_beneath, 1 );
101 glClearColor( 1.0f, 0.0f, 0.0f, 0.0f );
102 glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT );
103
104 m4x3_copy( cam->transform, beneath_cam.transform );
105 vg_camera_update_view( &beneath_cam );
106
107 float bias = -(cam->transform[3][1]-world->water.height)*0.1f;
108
109 v4f clippb = { 0.0f, -1.0f, 0.0f, -(world->water.height) + bias };
110 m4x3_mulp( beneath_cam.transform_inverse, clippb, clippb );
111 clippb[3] *= -1.0f;
112
113 m4x4_copy( cam->mtx.p, beneath_cam.mtx.p );
114 m4x4_clip_projection( beneath_cam.mtx.p, clippb );
115 vg_camera_finalize( &beneath_cam );
116
117 glEnable( GL_DEPTH_TEST );
118 glDisable( GL_BLEND );
119 render_world_depth( world, &beneath_cam );
120 //glViewport( 0,0, g_render_x, g_render_y );
121 }
122
123 void render_water_surface( world_instance *world, vg_camera *cam )
124 {
125 if( !world->water.enabled )
126 return;
127
128 if( vg.quality_profile == k_quality_profile_high ){
129 /* Draw surface */
130 shader_scene_water_use();
131
132 render_fb_bind_texture( gpipeline.fb_water_reflection, 0, 0 );
133 shader_scene_water_uTexMain( 0 );
134
135 glActiveTexture( GL_TEXTURE1 );
136 glBindTexture( GL_TEXTURE_2D, world_water.tex_water_surf );
137 shader_scene_water_uTexDudv( 1 );
138
139 shader_scene_water_uInvRes( (v2f){
140 1.0f / (float)vg.window_x,
141 1.0f / (float)vg.window_y });
142
143 WORLD_BIND_LIGHT_BUFFERS_UB0_TEX234( world, scene_water );
144
145 render_fb_bind_texture( gpipeline.fb_water_beneath, 0, 5 );
146 shader_scene_water_uTexBack( 5 );
147 shader_scene_water_uTime( world_static.time );
148 shader_scene_water_uCamera( cam->transform[3] );
149 shader_scene_water_uSurfaceY( world->water.height );
150
151 shader_scene_water_uPv( cam->mtx.pv );
152 shader_scene_water_uPvmPrev( cam->mtx_prev.pv );
153
154 m4x3f full;
155 m4x3_identity( full );
156 shader_scene_water_uMdl( full );
157
158 glEnable(GL_BLEND);
159 glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
160 glBlendEquation(GL_FUNC_ADD);
161
162 mesh_bind( &world->mesh_no_collide );
163
164 for( int i=0; i<world->surface_count; i++ )
165 {
166 struct world_surface *mat = &world->surfaces[i];
167 struct shader_props_water *props = mat->info.props.compiled;
168
169 if( mat->info.shader == k_shader_water )
170 {
171 shader_scene_water_uShoreColour( props->shore_colour );
172 shader_scene_water_uOceanColour( props->deep_colour );
173 shader_scene_water_uFresnel( props->fresnel );
174 shader_scene_water_uWaterScale( props->water_sale );
175 shader_scene_water_uWaveSpeed( props->wave_speed );
176
177 mdl_draw_submesh( &mat->sm_no_collide );
178 }
179 }
180
181 glDisable(GL_BLEND);
182 }
183 else if( (vg.quality_profile == k_quality_profile_low) ||
184 (vg.quality_profile == k_quality_profile_min) )
185 {
186 shader_scene_water_fast_use();
187
188 glActiveTexture( GL_TEXTURE1 );
189 glBindTexture( GL_TEXTURE_2D, world_water.tex_water_surf );
190 shader_scene_water_fast_uTexDudv( 1 );
191
192 shader_scene_water_fast_uTime( world_static.time );
193 shader_scene_water_fast_uCamera( cam->transform[3] );
194 shader_scene_water_fast_uSurfaceY( world->water.height );
195
196 WORLD_BIND_LIGHT_BUFFERS_UB0_TEX234( world, scene_water_fast );
197
198 m4x3f full;
199 m4x3_identity( full );
200 shader_scene_water_fast_uMdl( full );
201 shader_scene_water_fast_uPv( cam->mtx.pv );
202 shader_scene_water_fast_uPvmPrev( cam->mtx_prev.pv );
203
204 glEnable(GL_BLEND);
205 glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
206 glBlendEquation(GL_FUNC_ADD);
207
208 mesh_bind( &world->mesh_no_collide );
209
210 for( int i=0; i<world->surface_count; i++ )
211 {
212 struct world_surface *mat = &world->surfaces[i];
213 struct shader_props_water *props = mat->info.props.compiled;
214
215 if( mat->info.shader == k_shader_water )
216 {
217 shader_scene_water_fast_uShoreColour( props->shore_colour );
218 shader_scene_water_fast_uOceanColour( props->deep_colour );
219
220 mdl_draw_submesh( &mat->sm_no_collide );
221 }
222 }
223
224 glDisable(GL_BLEND);
225 }
226 }
227
228 static void world_water_drown(void)
229 {
230 player__networked_sfx( k_player_subsystem_walk, 32,
231 k_player_walk_soundeffect_splash,
232 localplayer.rb.co, 1.0f );
233 vg_info( "player fell of due to walking into walker\n" );
234 player__dead_transition( k_player_die_type_generic );
235 }
236
237 bool world_water_player_safe( world_instance *world, f32 allowance )
238 {
239 if( !world->water.enabled ) return 1;
240 if( world->info.flags & 0x2 ) return 1;
241
242 if( localplayer.rb.co[1]+allowance < world->water.height )
243 {
244 world_water_drown();
245 return 0;
246 }
247
248 return 1;
249 }
250
251 entity_call_result ent_water_call( world_instance *world, ent_call *call )
252 {
253 if( call->function == 0 )
254 {
255 world_water_drown();
256 return k_entity_call_result_OK;
257 }
258
259 return k_entity_call_result_unhandled;
260 }