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