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