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