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