]> git.xonotic.org Git - xonotic/netradiant.git/blob - radiant/points.cpp
gcc: appease the hardening warnings
[xonotic/netradiant.git] / radiant / points.cpp
1 /*
2    Copyright (C) 1999-2006 Id Software, Inc. and contributors.
3    For a list of contributors, see the accompanying CONTRIBUTORS file.
4
5    This file is part of GtkRadiant.
6
7    GtkRadiant is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    GtkRadiant is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with GtkRadiant; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21
22 /*
23    The following source code is licensed by Id Software and subject to the terms of
24    its LIMITED USE SOFTWARE LICENSE AGREEMENT, a copy of which is included with
25    GtkRadiant. If you did not receive a LIMITED USE SOFTWARE LICENSE AGREEMENT,
26    please contact Id Software immediately at info@idsoftware.com.
27  */
28
29 #include <cassert>
30 #include "points.h"
31
32 #include "debugging/debugging.h"
33
34 #include "irender.h"
35 #include "igl.h"
36 #include "renderable.h"
37
38 #include "stream/stringstream.h"
39 #include "os/path.h"
40 #include "os/file.h"
41 #include "cmdlib.h"
42
43 #include "map.h"
44 #include "qe3.h"
45 #include "camwindow.h"
46 #include "xywindow.h"
47 #include "xmlstuff.h"
48 #include "mainframe.h"
49 #include "watchbsp.h"
50 #include "commands.h"
51
52
53 class CPointfile;
54
55 void Pointfile_Parse(CPointfile &pointfile);
56
57
58 class CPointfile : public ISAXHandler, public Renderable, public OpenGLRenderable {
59     enum {
60         MAX_POINTFILE = 8192,
61     };
62     Vector3 s_pointvecs[MAX_POINTFILE];
63     std::size_t s_num_points;
64     int m_displaylist;
65     static Shader *m_renderstate;
66     StringOutputStream m_characters;
67 public:
68     CPointfile()
69     {
70     }
71
72     ~CPointfile()
73     {
74     }
75
76     void Init();
77
78     void PushPoint(const Vector3 &v);
79
80     void GenerateDisplayList();
81
82 // SAX interface
83     void Release()
84     {
85         // blank because not heap-allocated
86     }
87
88     void saxStartElement(message_info_t *ctx, const xmlChar *name, const xmlChar **attrs);
89
90     void saxEndElement(message_info_t *ctx, const xmlChar *name);
91
92     void saxCharacters(message_info_t *ctx, const xmlChar *ch, int len);
93
94     const char *getName();
95
96     typedef const Vector3 *const_iterator;
97
98     const_iterator begin() const
99     {
100         return &s_pointvecs[0];
101     }
102
103     const_iterator end() const
104     {
105         return &s_pointvecs[s_num_points];
106     }
107
108     bool shown() const
109     {
110         return m_displaylist != 0;
111     }
112
113     void show(bool show)
114     {
115         if (show && !shown()) {
116             Pointfile_Parse(*this);
117             GenerateDisplayList();
118             SceneChangeNotify();
119         } else if (!show && shown()) {
120             glDeleteLists(m_displaylist, 1);
121             m_displaylist = 0;
122             SceneChangeNotify();
123         }
124     }
125
126     void render(RenderStateFlags state) const
127     {
128         glCallList(m_displaylist);
129     }
130
131     void renderSolid(Renderer &renderer, const VolumeTest &volume) const
132     {
133         if (shown()) {
134             renderer.SetState(m_renderstate, Renderer::eWireframeOnly);
135             renderer.SetState(m_renderstate, Renderer::eFullMaterials);
136             renderer.addRenderable(*this, g_matrix4_identity);
137         }
138     }
139
140     void renderWireframe(Renderer &renderer, const VolumeTest &volume) const
141     {
142         renderSolid(renderer, volume);
143     }
144
145     static void constructStatic()
146     {
147         m_renderstate = GlobalShaderCache().capture("$POINTFILE");
148     }
149
150     static void destroyStatic()
151     {
152         GlobalShaderCache().release("$POINTFILE");
153     }
154 };
155
156 Shader *CPointfile::m_renderstate = 0;
157
158 namespace {
159     CPointfile s_pointfile;
160 }
161
162 ISAXHandler &g_pointfile = s_pointfile;
163
164 static CPointfile::const_iterator s_check_point;
165
166 void CPointfile::Init()
167 {
168     s_num_points = 0;
169     m_displaylist = 0;
170 }
171
172 void CPointfile::PushPoint(const Vector3 &v)
173 {
174     if (s_num_points < MAX_POINTFILE) {
175         s_pointvecs[s_num_points] = v;
176         ++s_num_points;
177     }
178 }
179
180 // create the display list at the end
181 void CPointfile::GenerateDisplayList()
182 {
183     m_displaylist = glGenLists(1);
184
185     glNewList(m_displaylist, GL_COMPILE);
186
187     glBegin(GL_LINE_STRIP);
188     for (std::size_t i = 0; i < s_num_points; i++)
189         glVertex3fv(vector3_to_array(s_pointvecs[i]));
190     glEnd();
191     glLineWidth(1);
192
193     glEndList();
194 }
195
196 // old (but still relevant) pointfile code -------------------------------------
197
198 void Pointfile_Delete(void)
199 {
200     const char *mapname = Map_Name(g_map);
201     StringOutputStream name(256);
202     name << StringRange(mapname, path_get_filename_base_end(mapname)) << ".lin";
203     file_remove(name.c_str());
204 }
205
206 // advance camera to next point
207 void Pointfile_Next(void)
208 {
209     if (!s_pointfile.shown()) {
210         return;
211     }
212
213     if (s_check_point + 2 == s_pointfile.end()) {
214         globalOutputStream() << "End of pointfile\n";
215         return;
216     }
217
218     CPointfile::const_iterator i = ++s_check_point;
219
220
221     CamWnd &camwnd = *g_pParentWnd->GetCamWnd();
222     Camera_setOrigin(camwnd, *i);
223     g_pParentWnd->GetXYWnd()->SetOrigin(*i);
224     {
225         Vector3 dir(vector3_normalised(vector3_subtracted(*(++i), Camera_getOrigin(camwnd))));
226         Vector3 angles(Camera_getAngles(camwnd));
227         angles[CAMERA_YAW] = static_cast<float>( radians_to_degrees(atan2(dir[1], dir[0])));
228         angles[CAMERA_PITCH] = static_cast<float>( radians_to_degrees(asin(dir[2])));
229         Camera_setAngles(camwnd, angles);
230     }
231 }
232
233 // advance camera to previous point
234 void Pointfile_Prev(void)
235 {
236     if (!s_pointfile.shown()) {
237         return;
238     }
239
240     if (s_check_point == s_pointfile.begin()) {
241         globalOutputStream() << "Start of pointfile\n";
242         return;
243     }
244
245     CPointfile::const_iterator i = --s_check_point;
246
247     CamWnd &camwnd = *g_pParentWnd->GetCamWnd();
248     Camera_setOrigin(camwnd, *i);
249     g_pParentWnd->GetXYWnd()->SetOrigin(*i);
250     {
251         Vector3 dir(vector3_normalised(vector3_subtracted(*(++i), Camera_getOrigin(camwnd))));
252         Vector3 angles(Camera_getAngles(camwnd));
253         angles[CAMERA_YAW] = static_cast<float>( radians_to_degrees(atan2(dir[1], dir[0])));
254         angles[CAMERA_PITCH] = static_cast<float>( radians_to_degrees(asin(dir[2])));
255         Camera_setAngles(camwnd, angles);
256     }
257 }
258
259 int LoadFile(const char *filename, void **bufferptr)
260 {
261     FILE *f;
262     long len;
263
264     f = fopen(filename, "rb");
265     if (f == 0) {
266         return -1;
267     }
268
269     fseek(f, 0, SEEK_END);
270     len = ftell(f);
271     rewind(f);
272
273     *bufferptr = malloc(len + 1);
274     if (*bufferptr == 0) {
275         return -1;
276     }
277
278     assert(fread(*bufferptr, 1, len, f));
279     fclose(f);
280
281     // we need to end the buffer with a 0
282     ((char *) (*bufferptr))[len] = 0;
283
284     return len;
285 }
286
287 void Pointfile_Parse(CPointfile &pointfile)
288 {
289     int size;
290     char *data;
291     char *text;
292     int line = 1;
293
294     const char *mapname = Map_Name(g_map);
295     StringOutputStream name(256);
296     name << StringRange(mapname, path_get_filename_base_end(mapname)) << ".lin";
297
298     size = LoadFile(name.c_str(), (void **) &data);
299     if (size == -1) {
300         globalErrorStream() << "Pointfile " << name.c_str() << " not found\n";
301         return;
302     }
303
304     // store a pointer
305     text = data;
306
307     globalOutputStream() << "Reading pointfile " << name.c_str() << "\n";
308
309     pointfile.Init();
310
311     while (*data) {
312         Vector3 v;
313         if (sscanf(data, "%f %f %f", &v[0], &v[1], &v[2]) != 3) {
314             globalOutputStream() << "Corrupt point file, line " << line << "\n";
315             break;
316         }
317
318         while (*data && *data != '\n') {
319             if (*(data - 1) == ' ' && *(data) == '-' && *(data + 1) == ' ') {
320                 break;
321             }
322             data++;
323         }
324         // deal with zhlt style point files.
325         if (*data == '-') {
326             if (sscanf(data, "- %f %f %f", &v[0], &v[1], &v[2]) != 3) {
327                 globalOutputStream() << "Corrupt point file, line " << line << "\n";
328                 break;
329             }
330
331             while (*data && *data != '\n') {
332                 data++;
333             }
334
335         }
336         while (*data == '\n') {
337             data++; // skip the \n
338             line++;
339         }
340         pointfile.PushPoint(v);
341     }
342
343     g_free(text);
344 }
345
346 void Pointfile_Clear()
347 {
348     s_pointfile.show(false);
349 }
350
351 void Pointfile_Toggle()
352 {
353     s_pointfile.show(!s_pointfile.shown());
354
355     s_check_point = s_pointfile.begin();
356 }
357
358 void Pointfile_Construct()
359 {
360     CPointfile::constructStatic();
361
362     GlobalShaderCache().attachRenderable(s_pointfile);
363
364     GlobalCommands_insert("TogglePointfile", makeCallbackF(Pointfile_Toggle));
365     GlobalCommands_insert("NextLeakSpot", makeCallbackF(Pointfile_Next),
366                           Accelerator('K', (GdkModifierType) (GDK_SHIFT_MASK | GDK_CONTROL_MASK)));
367     GlobalCommands_insert("PrevLeakSpot", makeCallbackF(Pointfile_Prev),
368                           Accelerator('L', (GdkModifierType) (GDK_SHIFT_MASK | GDK_CONTROL_MASK)));
369 }
370
371 void Pointfile_Destroy()
372 {
373     GlobalShaderCache().detachRenderable(s_pointfile);
374
375     CPointfile::destroyStatic();
376 }
377
378
379 // CPointfile implementation for SAX-specific stuff -------------------------------
380 void CPointfile::saxStartElement(message_info_t *ctx, const xmlChar *name, const xmlChar **attrs)
381 {
382     if (string_equal(reinterpret_cast<const char *>( name ), "polyline")) {
383         Init();
384         // there's a prefs setting to avoid stopping on leak
385         if (!g_WatchBSP_LeakStop) {
386             ctx->stop_depth = 0;
387         }
388     }
389 }
390
391 void CPointfile::saxEndElement(message_info_t *ctx, const xmlChar *name)
392 {
393     if (string_equal(reinterpret_cast<const char *>( name ), "polyline")) {
394         // we are done
395         GenerateDisplayList();
396         SceneChangeNotify();
397         s_check_point = begin();
398     } else if (string_equal(reinterpret_cast<const char *>( name ), "point")) {
399         Vector3 v;
400         sscanf(m_characters.c_str(), "%f %f %f\n", &v[0], &v[1], &v[2]);
401         PushPoint(v);
402         m_characters.clear();
403     }
404 }
405
406 // only "point" is expected to have characters around here
407 void CPointfile::saxCharacters(message_info_t *ctx, const xmlChar *ch, int len)
408 {
409     m_characters.write(reinterpret_cast<const char *>( ch ), len);
410 }
411
412 const char *CPointfile::getName()
413 {
414     return "Map leaked";
415 }