]> git.xonotic.org Git - xonotic/netradiant.git/blob - radiant/points.cpp
Merge branch 'NateEag-master-patch-12920' into 'master'
[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->ActiveXY()->SetOrigin( *i );
197         g_pParentWnd->ActiveXY()->queueDraw();
198         {
199                 Vector3 dir( vector3_normalised( vector3_subtracted( *( ++i ), Camera_getOrigin( camwnd ) ) ) );
200                 Vector3 angles( Camera_getAngles( camwnd ) );
201                 angles[CAMERA_YAW] = static_cast<float>( radians_to_degrees( atan2( dir[1], dir[0] ) ) );
202                 angles[CAMERA_PITCH] = static_cast<float>( radians_to_degrees( asin( dir[2] ) ) );
203                 Camera_setAngles( camwnd, angles );
204         }
205 }
206
207 // advance camera to previous point
208 void Pointfile_Prev( void ){
209         if ( !s_pointfile.shown() ) {
210                 return;
211         }
212
213         if ( s_check_point == s_pointfile.begin() ) {
214                 globalOutputStream() << "Start of pointfile\n";
215                 return;
216         }
217
218         CPointfile::const_iterator i = --s_check_point;
219
220         CamWnd& camwnd = *g_pParentWnd->GetCamWnd();
221         Camera_setOrigin( camwnd, *i );
222         g_pParentWnd->ActiveXY()->SetOrigin( *i );
223         g_pParentWnd->ActiveXY()->queueDraw();
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 int LoadFile( const char *filename, void **bufferptr ){
234         FILE *f;
235         long len;
236
237         f = fopen( filename, "rb" );
238         if ( f == 0 ) {
239                 return -1;
240         }
241
242         fseek( f, 0, SEEK_END );
243         len = ftell( f );
244         rewind( f );
245
246         *bufferptr = malloc( len + 1 );
247         if ( *bufferptr == 0 ) {
248                 return -1;
249         }
250
251         fread( *bufferptr, 1, len, f );
252         fclose( f );
253
254         // we need to end the buffer with a 0
255         ( (char*) ( *bufferptr ) )[len] = 0;
256
257         return len;
258 }
259
260 void Pointfile_Parse( CPointfile& pointfile ){
261         int size;
262         char    *data;
263         char  *text;
264         int line = 1;
265
266         const char* mapname = Map_Name( g_map );
267         StringOutputStream name( 256 );
268         name << StringRange( mapname, path_get_filename_base_end( mapname ) ) << ".lin";
269
270         size = LoadFile( name.c_str(), (void**)&data );
271         if ( size == -1 ) {
272                 globalErrorStream() << "Pointfile " << name.c_str() << " not found\n";
273                 return;
274         }
275
276         // store a pointer
277         text = data;
278
279         globalOutputStream() << "Reading pointfile " << name.c_str() << "\n";
280
281         pointfile.Init();
282
283         while ( *data )
284         {
285                 Vector3 v;
286                 if ( sscanf( data,"%f %f %f", &v[0], &v[1], &v[2] ) != 3 ) {
287                         globalOutputStream() << "Corrupt point file, line " << line << "\n";
288                         break;
289                 }
290
291                 while ( *data && *data != '\n' )
292                 {
293                         if ( *( data - 1 ) == ' ' && *( data ) == '-' && *( data + 1 ) == ' ' ) {
294                                 break;
295                         }
296                         data++;
297                 }
298                 // deal with zhlt style point files.
299                 if ( *data == '-' ) {
300                         if ( sscanf( data,"- %f %f %f", &v[0], &v[1], &v[2] ) != 3 ) {
301                                 globalOutputStream() << "Corrupt point file, line " << line << "\n";
302                                 break;
303                         }
304
305                         while ( *data && *data != '\n' )
306                                 data++;
307
308                 }
309                 while ( *data == '\n' )
310                 {
311                         data++; // skip the \n
312                         line++;
313                 }
314                 pointfile.PushPoint( v );
315         }
316
317         g_free( text );
318 }
319
320 void Pointfile_Clear(){
321         s_pointfile.show( false );
322 }
323
324 void Pointfile_Toggle(){
325         s_pointfile.show( !s_pointfile.shown() );
326
327         s_check_point = s_pointfile.begin();
328 }
329
330 void Pointfile_Construct(){
331         CPointfile::constructStatic();
332
333         GlobalShaderCache().attachRenderable( s_pointfile );
334
335         GlobalCommands_insert( "TogglePointfile", makeCallbackF(Pointfile_Toggle) );
336         GlobalCommands_insert( "NextLeakSpot", makeCallbackF(Pointfile_Next), Accelerator( 'K', (GdkModifierType)( GDK_SHIFT_MASK | GDK_CONTROL_MASK ) ) );
337         GlobalCommands_insert( "PrevLeakSpot", makeCallbackF(Pointfile_Prev), Accelerator( 'L', (GdkModifierType)( GDK_SHIFT_MASK | GDK_CONTROL_MASK ) ) );
338 }
339
340 void Pointfile_Destroy(){
341         GlobalShaderCache().detachRenderable( s_pointfile );
342
343         CPointfile::destroyStatic();
344 }
345
346
347
348 // CPointfile implementation for SAX-specific stuff -------------------------------
349 void CPointfile::saxStartElement( message_info_t *ctx, const xmlChar *name, const xmlChar **attrs ){
350         if ( string_equal( reinterpret_cast<const char*>( name ), "polyline" ) ) {
351                 Init();
352                 // there's a prefs setting to avoid stopping on leak
353                 if ( !g_WatchBSP_LeakStop ) {
354                         ctx->stop_depth = 0;
355                 }
356         }
357 }
358
359 void CPointfile::saxEndElement( message_info_t *ctx, const xmlChar *name ){
360         if ( string_equal( reinterpret_cast<const char*>( name ), "polyline" ) ) {
361                 // we are done
362                 GenerateDisplayList();
363                 SceneChangeNotify();
364                 s_check_point = begin();
365         }
366         else if ( string_equal( reinterpret_cast<const char*>( name ), "point" ) ) {
367                 Vector3 v;
368                 sscanf( m_characters.c_str(), "%f %f %f\n", &v[0], &v[1], &v[2] );
369                 PushPoint( v );
370                 m_characters.clear();
371         }
372 }
373
374 // only "point" is expected to have characters around here
375 void CPointfile::saxCharacters( message_info_t *ctx, const xmlChar *ch, int len ){
376         m_characters.write( reinterpret_cast<const char*>( ch ), len );
377 }
378
379 const char* CPointfile::getName(){
380         return "Map leaked";
381 }