daemonmap: update submodule
[xonotic/netradiant.git] / contrib / prtview / portals.cpp
1 /*
2    PrtView plugin for GtkRadiant
3    Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com
4
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    This library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with this library; if not, write to the Free Software
17    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19
20 #include "portals.h"
21 #include "globaldefs.h"
22 #include <string.h>
23 #include <stdlib.h>
24 #if !GDEF_OS_MACOS
25 #include <search.h>
26 #endif
27 #include <stdio.h>
28
29 #include "iglrender.h"
30 #include "cullable.h"
31
32 #include "prtview.h"
33
34 const int LINE_BUF = 1000;
35
36 CPortals portals;
37 CPortalsRender render;
38
39 int compare( const void *arg1, const void *arg2 ){
40
41         if ( portals.portal[*( (int *)arg1 )].dist > portals.portal[*( (int *)arg2 )].dist ) {
42                 return -1;
43         }
44         else if ( portals.portal[*( (int *)arg1 )].dist < portals.portal[*( (int *)arg2 )].dist ) {
45                 return 1;
46         }
47
48         return 0;
49 }
50
51
52 CBspPortal::CBspPortal(){
53         memset( this, 0, sizeof( CBspPortal ) );
54 }
55
56 CBspPortal::~CBspPortal(){
57         delete[] point;
58         delete[] inner_point;
59 }
60
61 bool CBspPortal::Build( char *def ){
62         char *c = def;
63         unsigned int n;
64         int dummy1, dummy2;
65         int res_cnt, i;
66
67         if ( portals.hint_flags ) {
68                 res_cnt = sscanf( def, "%u %d %d %d", &point_count, &dummy1, &dummy2, (int *)&hint );
69         }
70         else
71         {
72                 sscanf( def, "%u", &point_count );
73                 hint = false;
74         }
75
76         if ( point_count < 3 || ( portals.hint_flags && res_cnt < 4 ) ) {
77                 return false;
78         }
79
80         point = new CBspPoint[point_count];
81         inner_point = new CBspPoint[point_count];
82
83         for ( n = 0; n < point_count; n++ )
84         {
85                 for (; *c != 0 && *c != '('; c++ ) ;
86
87                 if ( *c == 0 ) {
88                         return false;
89                 }
90
91                 c++;
92
93                 sscanf( c, "%f %f %f", point[n].p, point[n].p + 1, point[n].p + 2 );
94
95                 center.p[0] += point[n].p[0];
96                 center.p[1] += point[n].p[1];
97                 center.p[2] += point[n].p[2];
98
99                 if ( n == 0 ) {
100                         for ( i = 0; i < 3; i++ )
101                         {
102                                 min[i] = point[n].p[i];
103                                 max[i] = point[n].p[i];
104                         }
105                 }
106                 else
107                 {
108                         for ( i = 0; i < 3; i++ )
109                         {
110                                 if ( min[i] > point[n].p[i] ) {
111                                         min[i] = point[n].p[i];
112                                 }
113                                 if ( max[i] < point[n].p[i] ) {
114                                         max[i] = point[n].p[i];
115                                 }
116                         }
117                 }
118         }
119
120         center.p[0] /= (float)point_count;
121         center.p[1] /= (float)point_count;
122         center.p[2] /= (float)point_count;
123
124         for ( n = 0; n < point_count; n++ )
125         {
126                 inner_point[n].p[0] = ( 0.01f * center.p[0] ) + ( 0.99f * point[n].p[0] );
127                 inner_point[n].p[1] = ( 0.01f * center.p[1] ) + ( 0.99f * point[n].p[1] );
128                 inner_point[n].p[2] = ( 0.01f * center.p[2] ) + ( 0.99f * point[n].p[2] );
129         }
130
131         fp_color_random[0] = (float)( rand() & 0xff ) / 255.0f;
132         fp_color_random[1] = (float)( rand() & 0xff ) / 255.0f;
133         fp_color_random[2] = (float)( rand() & 0xff ) / 255.0f;
134         fp_color_random[3] = 1.0f;
135
136         return true;
137 }
138
139 CPortals::CPortals(){
140         memset( this, 0, sizeof( CPortals ) );
141 }
142
143 CPortals::~CPortals(){
144         Purge();
145 }
146
147 void CPortals::Purge(){
148         delete[] portal;
149         delete[] portal_sort;
150         portal = NULL;
151         portal_sort = NULL;
152         portal_count = 0;
153
154         /*
155            delete[] node;
156            node = NULL;
157            node_count = 0;
158          */
159 }
160
161 void CPortals::Load(){
162         char buf[LINE_BUF + 1];
163
164         memset( buf, 0, LINE_BUF + 1 );
165
166         Purge();
167
168         globalOutputStream() << MSG_PREFIX "Loading portal file " << fn << ".\n";
169
170         FILE *in;
171
172         in = fopen( fn, "rt" );
173
174         if ( in == NULL ) {
175                 globalOutputStream() << "  ERROR - could not open file.\n";
176
177                 return;
178         }
179
180         if ( !fgets( buf, LINE_BUF, in ) ) {
181                 fclose( in );
182
183                 globalOutputStream() << "  ERROR - File ended prematurely.\n";
184
185                 return;
186         }
187
188         if ( strncmp( "PRT1", buf, 4 ) != 0 ) {
189                 fclose( in );
190
191                 globalOutputStream() << "  ERROR - File header indicates wrong file type (should be \"PRT1\").\n";
192
193                 return;
194         }
195
196         if ( !fgets( buf, LINE_BUF, in ) ) {
197                 fclose( in );
198
199                 globalOutputStream() << "  ERROR - File ended prematurely.\n";
200
201                 return;
202         }
203
204         sscanf( buf, "%u", &node_count );
205 /*
206     if(node_count > 0xFFFF)
207     {
208         fclose(in);
209
210         node_count = 0;
211
212         globalOutputStream() << "  ERROR - Extreme number of nodes, aborting.\n";
213
214         return;
215     }
216  */
217
218         if ( !fgets( buf, LINE_BUF, in ) ) {
219                 fclose( in );
220
221                 node_count = 0;
222
223                 globalOutputStream() << "  ERROR - File ended prematurely.\n";
224
225                 return;
226         }
227
228         sscanf( buf, "%u", &portal_count );
229
230         if ( portal_count > 0xFFFF ) {
231                 fclose( in );
232
233                 portal_count = 0;
234                 node_count = 0;
235
236                 globalOutputStream() << "  ERROR - Extreme number of portals, aborting.\n";
237
238                 return;
239         }
240
241         if ( portal_count == 0 ) {
242                 fclose( in );
243
244                 portal_count = 0;
245                 node_count = 0;
246
247                 globalOutputStream() << "  ERROR - number of portals equals 0, aborting.\n";
248
249                 return;
250         }
251
252 //      node = new CBspNode[node_count];
253         portal = new CBspPortal[portal_count];
254         portal_sort = new int[portal_count];
255
256         unsigned int n;
257         bool first = true;
258         unsigned test_vals_1, test_vals_2;
259
260         hint_flags = false;
261
262         for ( n = 0; n < portal_count; )
263         {
264                 if ( !fgets( buf, LINE_BUF, in ) ) {
265                         fclose( in );
266
267                         Purge();
268
269                         globalOutputStream() << "  ERROR - Could not find information for portal number " << n + 1 << " of " << portal_count << ".\n";
270
271                         return;
272                 }
273
274                 if ( !portal[n].Build( buf ) ) {
275                         if ( first && sscanf( buf, "%d %d", (int *) &test_vals_1, (int *) &test_vals_2 ) == 1 ) { // skip additional counts of later data, not needed
276                                 // We can count on hint flags being in the file
277                                 hint_flags = true;
278                                 continue;
279                         }
280
281                         first = false;
282
283                         fclose( in );
284
285                         Purge();
286
287                         globalOutputStream() << "  ERROR - Information for portal number " << n + 1 << " of " << portal_count << " is not formatted correctly.\n";
288
289                         return;
290                 }
291
292                 n++;
293         }
294
295         fclose( in );
296
297         globalOutputStream() << "  " << node_count << " portals read in.\n";
298 }
299
300 #include "math/matrix.h"
301
302 const char* g_state_solid = "$plugins/prtview/solid";
303 const char* g_state_solid_outline = "$plugins/prtview/solid_outline";
304 const char* g_state_wireframe = "$plugins/prtview/wireframe";
305 Shader* g_shader_solid = 0;
306 Shader* g_shader_solid_outline = 0;
307 Shader* g_shader_wireframe = 0;
308
309 void Portals_constructShaders(){
310         OpenGLState state;
311         GlobalOpenGLStateLibrary().getDefaultState( state );
312         state.m_state = RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
313         state.m_sort = OpenGLState::eSortOverlayFirst;
314         state.m_linewidth = portals.width_2d * 0.5f;
315         state.m_colour[0] = portals.fp_color_2d[0];
316         state.m_colour[1] = portals.fp_color_2d[1];
317         state.m_colour[2] = portals.fp_color_2d[2];
318         state.m_colour[3] = portals.fp_color_2d[3];
319         if ( portals.aa_2d ) {
320                 state.m_state |= RENDER_BLEND | RENDER_LINESMOOTH;
321         }
322         GlobalOpenGLStateLibrary().insert( g_state_wireframe, state );
323
324         GlobalOpenGLStateLibrary().getDefaultState( state );
325         state.m_state = RENDER_FILL | RENDER_BLEND | RENDER_COLOURWRITE | RENDER_COLOURCHANGE | RENDER_SMOOTH;
326
327         if ( portals.aa_3d ) {
328                 state.m_state |= RENDER_POLYGONSMOOTH;
329         }
330
331         switch ( portals.zbuffer )
332         {
333         case 1:
334                 state.m_state |= RENDER_DEPTHTEST;
335                 break;
336         case 2:
337                 break;
338         default:
339                 state.m_state |= RENDER_DEPTHTEST;
340                 state.m_state |= RENDER_DEPTHWRITE;
341         }
342
343         if ( portals.fog ) {
344                 state.m_state |= RENDER_FOG;
345
346                 state.m_fog.mode = GL_EXP;
347                 state.m_fog.density = 0.001f;
348                 state.m_fog.start = 10.0f;
349                 state.m_fog.end = 10000.0f;
350                 state.m_fog.index = 0;
351                 state.m_fog.colour[0] = portals.fp_color_fog[0];
352                 state.m_fog.colour[1] = portals.fp_color_fog[1];
353                 state.m_fog.colour[2] = portals.fp_color_fog[2];
354                 state.m_fog.colour[3] = portals.fp_color_fog[3];
355         }
356
357         GlobalOpenGLStateLibrary().insert( g_state_solid, state );
358
359         GlobalOpenGLStateLibrary().getDefaultState( state );
360         state.m_state = RENDER_COLOURWRITE | RENDER_DEPTHWRITE;
361         state.m_sort = OpenGLState::eSortOverlayFirst;
362         state.m_linewidth = portals.width_3d * 0.5f;
363         state.m_colour[0] = portals.fp_color_3d[0];
364         state.m_colour[1] = portals.fp_color_3d[1];
365         state.m_colour[2] = portals.fp_color_3d[2];
366         state.m_colour[3] = portals.fp_color_3d[3];
367
368         if ( portals.aa_3d ) {
369                 state.m_state |= RENDER_LINESMOOTH;
370         }
371
372         switch ( portals.zbuffer )
373         {
374         case 1:
375                 state.m_state |= RENDER_DEPTHTEST;
376                 break;
377         case 2:
378                 break;
379         default:
380                 state.m_state |= RENDER_DEPTHTEST;
381                 state.m_state |= RENDER_DEPTHWRITE;
382         }
383
384         if ( portals.fog ) {
385                 state.m_state |= RENDER_FOG;
386
387                 state.m_fog.mode = GL_EXP;
388                 state.m_fog.density = 0.001f;
389                 state.m_fog.start = 10.0f;
390                 state.m_fog.end = 10000.0f;
391                 state.m_fog.index = 0;
392                 state.m_fog.colour[0] = portals.fp_color_fog[0];
393                 state.m_fog.colour[1] = portals.fp_color_fog[1];
394                 state.m_fog.colour[2] = portals.fp_color_fog[2];
395                 state.m_fog.colour[3] = portals.fp_color_fog[3];
396         }
397
398         GlobalOpenGLStateLibrary().insert( g_state_solid_outline, state );
399
400         g_shader_solid = GlobalShaderCache().capture( g_state_solid );
401         g_shader_solid_outline = GlobalShaderCache().capture( g_state_solid_outline );
402         g_shader_wireframe = GlobalShaderCache().capture( g_state_wireframe );
403 }
404
405 void Portals_destroyShaders(){
406         GlobalShaderCache().release( g_state_solid );
407         GlobalShaderCache().release( g_state_solid_outline );
408         GlobalShaderCache().release( g_state_wireframe );
409         GlobalOpenGLStateLibrary().erase( g_state_solid );
410         GlobalOpenGLStateLibrary().erase( g_state_solid_outline );
411         GlobalOpenGLStateLibrary().erase( g_state_wireframe );
412 }
413
414 void Portals_shadersChanged(){
415         Portals_destroyShaders();
416         portals.FixColors();
417         Portals_constructShaders();
418 }
419
420 void CPortals::FixColors(){
421         fp_color_2d[0] = (float)GetRValue( color_2d ) / 255.0f;
422         fp_color_2d[1] = (float)GetGValue( color_2d ) / 255.0f;
423         fp_color_2d[2] = (float)GetBValue( color_2d ) / 255.0f;
424         fp_color_2d[3] = 1.0f;
425
426         fp_color_3d[0] = (float)GetRValue( color_3d ) / 255.0f;
427         fp_color_3d[1] = (float)GetGValue( color_3d ) / 255.0f;
428         fp_color_3d[2] = (float)GetBValue( color_3d ) / 255.0f;
429         fp_color_3d[3] = 1.0f;
430
431         fp_color_fog[0] = 0.0f; //(float)GetRValue(color_fog) / 255.0f;
432         fp_color_fog[1] = 0.0f; //(float)GetGValue(color_fog) / 255.0f;
433         fp_color_fog[2] = 0.0f; //(float)GetBValue(color_fog) / 255.0f;
434         fp_color_fog[3] = 1.0f;
435 }
436
437 void CPortalsRender::renderWireframe( Renderer& renderer, const VolumeTest& volume ) const {
438         if ( !portals.show_2d || portals.portal_count < 1 ) {
439                 return;
440         }
441
442         renderer.SetState( g_shader_wireframe, Renderer::eWireframeOnly );
443
444         renderer.addRenderable( m_drawWireframe, g_matrix4_identity );
445 }
446
447 void CPortalsDrawWireframe::render( RenderStateFlags state ) const {
448         unsigned int n, p;
449
450         for ( n = 0; n < portals.portal_count; n++ )
451         {
452                 glBegin( GL_LINE_LOOP );
453
454                 for ( p = 0; p < portals.portal[n].point_count; p++ )
455                         glVertex3fv( portals.portal[n].point[p].p );
456
457                 glEnd();
458         }
459 }
460
461 CubicClipVolume calculateCubicClipVolume( const Matrix4& viewproj ){
462         CubicClipVolume clip;
463         clip.cam = vector4_projected(
464                 matrix4_transformed_vector4(
465                         matrix4_full_inverse( viewproj ),
466                         Vector4( 0, 0, -1, 1 )
467                         )
468                 );
469         clip.min[0] = clip.cam[0] + ( portals.clip_range * 64.0f );
470         clip.min[1] = clip.cam[1] + ( portals.clip_range * 64.0f );
471         clip.min[2] = clip.cam[2] + ( portals.clip_range * 64.0f );
472         clip.max[0] = clip.cam[0] - ( portals.clip_range * 64.0f );
473         clip.max[1] = clip.cam[1] - ( portals.clip_range * 64.0f );
474         clip.max[2] = clip.cam[2] - ( portals.clip_range * 64.0f );
475         return clip;
476 }
477
478 void CPortalsRender::renderSolid( Renderer& renderer, const VolumeTest& volume ) const {
479         if ( !portals.show_3d || portals.portal_count < 1 ) {
480                 return;
481         }
482
483         CubicClipVolume clip = calculateCubicClipVolume( matrix4_multiplied_by_matrix4( volume.GetProjection(), volume.GetModelview() ) );
484
485         if ( portals.polygons ) {
486                 renderer.SetState( g_shader_solid, Renderer::eWireframeOnly );
487                 renderer.SetState( g_shader_solid, Renderer::eFullMaterials );
488
489                 m_drawSolid.clip = clip;
490                 renderer.addRenderable( m_drawSolid, g_matrix4_identity );
491         }
492
493         if ( portals.lines ) {
494                 renderer.SetState( g_shader_solid_outline, Renderer::eWireframeOnly );
495                 renderer.SetState( g_shader_solid_outline, Renderer::eFullMaterials );
496
497                 m_drawSolidOutline.clip = clip;
498                 renderer.addRenderable( m_drawSolidOutline, g_matrix4_identity );
499         }
500 }
501
502 void CPortalsDrawSolid::render( RenderStateFlags state ) const {
503         float trans = ( 100.0f - portals.trans_3d ) / 100.0f;
504
505         unsigned int n, p;
506
507         if ( portals.zbuffer != 0 ) {
508                 float d;
509
510                 for ( n = 0; n < portals.portal_count; n++ )
511                 {
512                         d = (float)clip.cam[0] - portals.portal[n].center.p[0];
513                         portals.portal[n].dist = d * d;
514
515                         d = (float)clip.cam[1] - portals.portal[n].center.p[1];
516                         portals.portal[n].dist += d * d;
517
518                         d = (float)clip.cam[2] - portals.portal[n].center.p[2];
519                         portals.portal[n].dist += d * d;
520
521                         portals.portal_sort[n] = n;
522                 }
523
524                 qsort( portals.portal_sort, portals.portal_count, 4, compare );
525
526                 for ( n = 0; n < portals.portal_count; n++ )
527                 {
528                         if ( portals.polygons == 2 && !portals.portal[portals.portal_sort[n]].hint ) {
529                                 continue;
530                         }
531
532                         if ( portals.clip ) {
533                                 if ( clip.min[0] < portals.portal[portals.portal_sort[n]].min[0] ) {
534                                         continue;
535                                 }
536                                 else if ( clip.min[1] < portals.portal[portals.portal_sort[n]].min[1] ) {
537                                         continue;
538                                 }
539                                 else if ( clip.min[2] < portals.portal[portals.portal_sort[n]].min[2] ) {
540                                         continue;
541                                 }
542                                 else if ( clip.max[0] > portals.portal[portals.portal_sort[n]].max[0] ) {
543                                         continue;
544                                 }
545                                 else if ( clip.max[1] > portals.portal[portals.portal_sort[n]].max[1] ) {
546                                         continue;
547                                 }
548                                 else if ( clip.max[2] > portals.portal[portals.portal_sort[n]].max[2] ) {
549                                         continue;
550                                 }
551                         }
552
553                         glColor4f( portals.portal[portals.portal_sort[n]].fp_color_random[0], portals.portal[portals.portal_sort[n]].fp_color_random[1],
554                                            portals.portal[portals.portal_sort[n]].fp_color_random[2], trans );
555
556                         glBegin( GL_POLYGON );
557
558                         for ( p = 0; p < portals.portal[portals.portal_sort[n]].point_count; p++ )
559                                 glVertex3fv( portals.portal[portals.portal_sort[n]].point[p].p );
560
561                         glEnd();
562                 }
563         }
564         else
565         {
566                 for ( n = 0; n < portals.portal_count; n++ )
567                 {
568                         if ( portals.polygons == 2 && !portals.portal[n].hint ) {
569                                 continue;
570                         }
571
572                         if ( portals.clip ) {
573                                 if ( clip.min[0] < portals.portal[n].min[0] ) {
574                                         continue;
575                                 }
576                                 else if ( clip.min[1] < portals.portal[n].min[1] ) {
577                                         continue;
578                                 }
579                                 else if ( clip.min[2] < portals.portal[n].min[2] ) {
580                                         continue;
581                                 }
582                                 else if ( clip.max[0] > portals.portal[n].max[0] ) {
583                                         continue;
584                                 }
585                                 else if ( clip.max[1] > portals.portal[n].max[1] ) {
586                                         continue;
587                                 }
588                                 else if ( clip.max[2] > portals.portal[n].max[2] ) {
589                                         continue;
590                                 }
591                         }
592
593                         glColor4f( portals.portal[n].fp_color_random[0], portals.portal[n].fp_color_random[1],
594                                            portals.portal[n].fp_color_random[2], trans );
595
596                         glBegin( GL_POLYGON );
597
598                         for ( p = 0; p < portals.portal[n].point_count; p++ )
599                                 glVertex3fv( portals.portal[n].point[p].p );
600
601                         glEnd();
602                 }
603         }
604 }
605
606 void CPortalsDrawSolidOutline::render( RenderStateFlags state ) const {
607         for ( unsigned int n = 0; n < portals.portal_count; n++ )
608         {
609                 if ( portals.lines == 2 && !portals.portal[n].hint ) {
610                         continue;
611                 }
612
613                 if ( portals.clip ) {
614                         if ( clip.min[0] < portals.portal[n].min[0] ) {
615                                 continue;
616                         }
617                         if ( clip.min[1] < portals.portal[n].min[1] ) {
618                                 continue;
619                         }
620                         if ( clip.min[2] < portals.portal[n].min[2] ) {
621                                 continue;
622                         }
623                         if ( clip.max[0] > portals.portal[n].max[0] ) {
624                                 continue;
625                         }
626                         if ( clip.max[1] > portals.portal[n].max[1] ) {
627                                 continue;
628                         }
629                         if ( clip.max[2] > portals.portal[n].max[2] ) {
630                                 continue;
631                         }
632                 }
633
634                 glBegin( GL_LINE_LOOP );
635
636                 for ( unsigned int p = 0; p < portals.portal[n].point_count; p++ )
637                         glVertex3fv( portals.portal[n].inner_point[p].p );
638
639                 glEnd();
640         }
641 }