gate groundwork
[carveJwlIkooP6JGAAIwe30JlM.git] / gate.h
1 #ifndef GATE_H
2 #define GATE_H
3
4 #include "vg/vg.h"
5
6 static const float k_gatesize = 4.0f;
7
8 SHADER_DEFINE( shader_gate,
9 "layout (location=0) in vec3 a_co;"
10 "uniform mat4 uPv;"
11 "uniform mat4x3 uMdl;"
12 ""
13 "void main()"
14 "{"
15 "gl_Position = uPv * vec4(uMdl * vec4( a_co, 1.0 ),1.0);"
16 "}",
17
18 /* Fragment */
19 "out vec4 FragColor;"
20 ""
21 "uniform sampler2D uTexMain;"
22 "uniform vec2 uInvRes;"
23 ""
24 "void main()"
25 "{"
26 "vec2 uv = gl_FragCoord.xy*uInvRes;"
27 "FragColor = texture( uTexMain, uv );"
28 "}"
29 ,
30 UNIFORMS({ "uPv", "uMdl", "uTexMain", "uInvRes" })
31 )
32
33 typedef struct teleport_gate teleport_gate;
34
35 static struct
36 {
37 GLuint fb, rgb, rb, vao, vbo;
38 }
39 grender;
40
41 struct teleport_gate
42 {
43 v3f co;
44 v4f q;
45
46 m4x3f to_world, to_local;
47 teleport_gate *other;
48 };
49
50 static void gate_transform_update( teleport_gate *gate )
51 {
52 q_m3x3( gate->q, gate->to_world );
53 v3_copy( gate->co, gate->to_world[3] );
54
55 m4x3_invert_affine( gate->to_world, gate->to_local );
56 }
57
58 static void gate_register(void)
59 {
60 SHADER_INIT( shader_gate );
61 }
62
63 static void gate_init(void)
64 {
65 glGenFramebuffers( 1, &grender.fb );
66 glBindFramebuffer( GL_FRAMEBUFFER, grender.fb );
67
68 glGenTextures( 1, &grender.rgb );
69 glBindTexture( GL_TEXTURE_2D, grender.rgb );
70 glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, vg_window_x, vg_window_y,
71 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
72
73 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
74 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
75 glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
76 GL_TEXTURE_2D, grender.rgb, 0);
77
78 /* TODO: Check for DEPTH32f availiblity and use if possible */
79
80 glGenRenderbuffers( 1, &grender.rb );
81 glBindRenderbuffer( GL_RENDERBUFFER, grender.rb );
82 glRenderbufferStorage( GL_RENDERBUFFER, GL_DEPTH24_STENCIL8,
83 vg_window_x, vg_window_y );
84
85 glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
86 GL_RENDERBUFFER, grender.rb );
87
88 {
89 float ksz = k_gatesize;
90 float quad[] = { -ksz,-ksz,0.0f, ksz, ksz,0.0f, -ksz, ksz,0.0f,
91 -ksz,-ksz,0.0f, ksz,-ksz,0.0f, ksz, ksz,0.0f,
92 -ksz,-ksz,0.0f, -ksz, ksz,0.0f, ksz, ksz,0.0f,
93 -ksz,-ksz,0.0f, ksz, ksz,0.0f, ksz,-ksz,0.0f };
94
95 glGenVertexArrays( 1, &grender.vao );
96 glGenBuffers( 1, &grender.vbo );
97 glBindVertexArray( grender.vao );
98 glBindBuffer( GL_ARRAY_BUFFER, grender.vbo );
99 glBufferData( GL_ARRAY_BUFFER, sizeof(quad), quad, GL_STATIC_DRAW );
100 glBindVertexArray( grender.vao );
101 glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE,
102 sizeof(float)*3, (void*)0 );
103 glEnableVertexAttribArray( 0 );
104 VG_CHECK_GL();
105 }
106 }
107
108 static void render_world(m4x4f pv);
109
110 /*
111 * http://www.terathon.com/lengyel/Lengyel-Oblique.pdf
112 */
113 static void plane_clip_projection( m4x4f mat, v4f plane )
114 {
115 v4f c =
116 {
117 (vg_signf(plane[0]) + mat[2][0]) / mat[0][0],
118 (vg_signf(plane[1]) + mat[2][1]) / mat[1][1],
119 -1.0f,
120 (1.0f + mat[2][2]) / mat[3][2]
121 };
122
123 v4_muls( plane, 2.0f / v4_dot(plane,c), c );
124
125 mat[0][2] = c[0];
126 mat[1][2] = c[1];
127 mat[2][2] = c[2] + 1.0f;
128 mat[3][2] = c[3];
129 }
130
131 static void render_gate( teleport_gate *gate, m4x3f camera, float fov )
132 {
133 m4x3f transport;
134
135 m4x3_mul( gate->other->to_world, gate->to_local, transport );
136
137 v3f a,b,c,d;
138
139 float ksz = k_gatesize;
140 m4x3_mulv( gate->to_world, (v3f){-ksz,-ksz,0.0f}, a );
141 m4x3_mulv( gate->to_world, (v3f){ ksz,-ksz,0.0f}, b );
142 m4x3_mulv( gate->to_world, (v3f){ ksz, ksz,0.0f}, c );
143 m4x3_mulv( gate->to_world, (v3f){-ksz, ksz,0.0f}, d );
144
145 vg_line( a,b, 0xffffa000 );
146 vg_line( b,c, 0xffffa000 );
147 vg_line( c,d, 0xffffa000 );
148 vg_line( d,a, 0xffffa000 );
149
150 vg_line( gate->co, gate->other->co, 0xffffffff );
151
152 m4x3f cam_new;
153 m4x3_mul( transport, camera, cam_new );
154
155 vg_line_pt3( cam_new[3], 0.3f, 0xff00ff00 );
156
157 glBindFramebuffer( GL_FRAMEBUFFER, grender.fb );
158 glClearColor( 0.0f, 0.0f, 1.0f, 1.0f );
159 glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT );
160
161
162 m4x3f inverse;
163 m4x3_invert_affine( cam_new, inverse );
164
165 m4x4f view;
166 m4x3_expand( inverse, view );
167
168 v4f surface;
169 m3x3_mulv( gate->other->to_world, (v3f){0.0f,0.0f,-1.0f}, surface );
170 surface[3] = v3_dot( surface, gate->other->co );
171
172 m4x4f projection;
173 m4x4_projection( projection,
174 fov,
175 (float)vg_window_x / (float)vg_window_y,
176 0.01f, 900.0f );
177
178 #if 0 /* For debugging frustum */
179 {
180 m4x4f devm;
181 m4x4_mul( projection, view, devm );
182 m4x4_inv( devm, devm );
183
184 v4f corners[] =
185 {
186 {-1,-1,-1, 1}, { 1,-1,-1, 1}, { 1, 1,-1, 1}, {-1, 1,-1, 1},
187 {-1,-1, 1, 1}, { 1,-1, 1, 1}, { 1, 1, 1, 1}, {-1, 1, 1, 1}
188 };
189
190 for( int i=0; i<vg_list_size(corners); i++ )
191 {
192 m4x4_mulv( devm, corners[i], corners[i] );
193 v3_muls( corners[i], 1.0f/corners[i][3], corners[i] );
194 }
195
196 vg_line( corners[0], corners[1], 0xffffffff );
197 vg_line( corners[1], corners[2], 0xffffffff );
198 vg_line( corners[2], corners[3], 0xffffffff );
199 vg_line( corners[3], corners[0], 0xffffffff );
200 vg_line( corners[4], corners[5], 0xffffffff );
201 vg_line( corners[5], corners[6], 0xffffffff );
202 vg_line( corners[6], corners[7], 0xffffffff );
203 vg_line( corners[7], corners[4], 0xffffffff );
204 vg_line( corners[0], corners[4], 0xffffffff );
205 vg_line( corners[1], corners[5], 0xffffffff );
206 vg_line( corners[2], corners[6], 0xffffffff );
207 vg_line( corners[3], corners[7], 0xffffffff );
208
209 v3f clipped[4];
210 for( int i=0; i<4; i++ )
211 {
212 v3f v0, c, delta, p0;
213 v3_sub( corners[4+i],corners[0+i], v0 );
214 v3_normalize(v0);
215
216 v3_muls( surface, surface[3], c );
217 v3_sub( c, corners[0+i], delta );
218
219 float t = v3_dot(delta, surface) / v3_dot(surface, v0);
220 v3_muladds( corners[0+i], v0, t, clipped[i] );
221 }
222
223 vg_line( clipped[0], clipped[1], 0xff0000ff );
224 vg_line( clipped[1], clipped[2], 0xff0000ff );
225 vg_line( clipped[2], clipped[3], 0xff0000ff );
226 vg_line( clipped[3], clipped[0], 0xff0000ff );
227
228 m4x3_mulv( gate->other->to_world, (v3f){-2.0f,-2.0f,0.0f}, a );
229 m4x3_mulv( gate->other->to_world, (v3f){ 2.0f,-2.0f,0.0f}, b );
230 m4x3_mulv( gate->other->to_world, (v3f){ 2.0f, 2.0f,0.0f}, c );
231 m4x3_mulv( gate->other->to_world, (v3f){-2.0f, 2.0f,0.0f}, d );
232
233 vg_line( clipped[0], a, 0xff0000ff );
234 vg_line( clipped[1], b, 0xff0000ff );
235 vg_line( clipped[2], c, 0xff0000ff );
236 vg_line( clipped[3], d, 0xff0000ff );
237 }
238 #endif
239
240 m4x3_mulp( inverse, surface, surface );
241 surface[3] = -fabsf(surface[3]);
242 plane_clip_projection( projection, surface );
243
244 m4x4_mul( projection, view, projection );
245
246 render_world( projection );
247 glBindFramebuffer( GL_FRAMEBUFFER, 0 );
248
249 SHADER_USE( shader_gate );
250
251 glUniformMatrix4fv( SHADER_UNIFORM( shader_gate, "uPv" ),
252 1, GL_FALSE, (float *)vg_pv );
253 glUniformMatrix4x3fv( SHADER_UNIFORM( shader_gate, "uMdl" ),
254 1, GL_FALSE, (float *)gate->to_world );
255
256 glActiveTexture( GL_TEXTURE0 );
257 glBindTexture( GL_TEXTURE_2D, grender.rgb );
258 glUniform1i( SHADER_UNIFORM( shader_gate, "uTexMain"), 0 );
259 glUniform2f( SHADER_UNIFORM( shader_gate, "uInvRes"),
260 1.0f / (float)vg_window_x,
261 1.0f / (float)vg_window_y );
262
263 glBindVertexArray( grender.vao );
264 glDrawArrays( GL_TRIANGLES, 0, 12 );
265 }
266
267 static int gate_intersect( teleport_gate *gate, v3f pos, v3f last )
268 {
269 v4f surface;
270 m3x3_mulv( gate->to_world, (v3f){0.0f,0.0f,-1.0f}, surface );
271 surface[3] = v3_dot( surface, gate->co );
272
273 v3f v0, c, delta, p0;
274 v3_sub( pos, last, v0 );
275 float l = v3_length( v0 );
276 v3_divs( v0, l, v0 );
277
278 v3_muls( surface, surface[3], c );
279 v3_sub( c, last, delta );
280
281 float d = v3_dot(surface, v0);
282
283 if( fabsf(d) > 0.00001f )
284 {
285 float t = v3_dot(delta, surface) / d;
286 if( t >= 0.0f && t <= l )
287 {
288 v3f local, rel;
289 v3_muladds( last, v0, t, local );
290 v3_sub( gate->co, local, rel );
291
292 v3f vup, vside;
293 m3x3_mulv( gate->to_world, (v3f){0.0f,1.0f,0.0f}, vup );
294 m3x3_mulv( gate->to_world, (v3f){1.0f,0.0f,0.0f}, vside );
295
296 v2f xy = { v3_dot( rel, vside ), v3_dot( rel, vup ) };
297
298 if( fabsf(xy[0]) <= k_gatesize && fabsf(xy[1]) <= k_gatesize )
299 {
300 return 1;
301 }
302 }
303 }
304
305 return 0;
306 }
307
308 #endif