2 Copyright (C) 1999-2006 Id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
5 This file is part of GtkRadiant.
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.
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.
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
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.
31 #include "debugging/debugging.h"
35 #include "renderable.h"
37 #include "stream/stringstream.h"
44 #include "camwindow.h"
47 #include "mainframe.h"
53 void Pointfile_Parse( CPointfile& pointfile );
56 class CPointfile : public ISAXHandler, public Renderable, public OpenGLRenderable
62 Vector3 s_pointvecs[MAX_POINTFILE];
63 std::size_t s_num_points;
65 static Shader* m_renderstate;
66 StringOutputStream m_characters;
73 void PushPoint( const Vector3& v );
74 void GenerateDisplayList();
77 // blank because not heap-allocated
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();
84 typedef const Vector3* const_iterator;
86 const_iterator begin() const {
87 return &s_pointvecs[0];
89 const_iterator end() const {
90 return &s_pointvecs[s_num_points];
94 return m_displaylist != 0;
96 void show( bool show ){
97 if ( show && !shown() ) {
98 Pointfile_Parse( *this );
99 GenerateDisplayList();
102 else if ( !show && shown() ) {
103 glDeleteLists( m_displaylist, 1 );
109 void render( RenderStateFlags state ) const {
110 glCallList( m_displaylist );
113 void renderSolid( Renderer& renderer, const VolumeTest& volume ) const {
115 renderer.SetState( m_renderstate, Renderer::eWireframeOnly );
116 renderer.SetState( m_renderstate, Renderer::eFullMaterials );
117 renderer.addRenderable( *this, g_matrix4_identity );
120 void renderWireframe( Renderer& renderer, const VolumeTest& volume ) const {
121 renderSolid( renderer, volume );
124 static void constructStatic(){
125 m_renderstate = GlobalShaderCache().capture( "$POINTFILE" );
128 static void destroyStatic(){
129 GlobalShaderCache().release( "$POINTFILE" );
133 Shader* CPointfile::m_renderstate = 0;
137 CPointfile s_pointfile;
140 ISAXHandler& g_pointfile = s_pointfile;
142 static CPointfile::const_iterator s_check_point;
144 void CPointfile::Init(){
149 void CPointfile::PushPoint( const Vector3& v ){
150 if ( s_num_points < MAX_POINTFILE ) {
151 s_pointvecs[s_num_points] = v;
156 // create the display list at the end
157 void CPointfile::GenerateDisplayList(){
158 m_displaylist = glGenLists( 1 );
160 glNewList( m_displaylist, GL_COMPILE );
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] ) );
171 // old (but still relevant) pointfile code -------------------------------------
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() );
180 // advance camera to next point
181 void Pointfile_Next( void ){
182 if ( !s_pointfile.shown() ) {
186 if ( s_check_point + 2 == s_pointfile.end() ) {
187 globalOutputStream() << "End of pointfile\n";
191 CPointfile::const_iterator i = ++s_check_point;
194 CamWnd& camwnd = *g_pParentWnd->GetCamWnd();
195 Camera_setOrigin( camwnd, *i );
196 g_pParentWnd->GetXYWnd()->SetOrigin( *i );
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 );
206 // advance camera to previous point
207 void Pointfile_Prev( void ){
208 if ( !s_pointfile.shown() ) {
212 if ( s_check_point == s_pointfile.begin() ) {
213 globalOutputStream() << "Start of pointfile\n";
217 CPointfile::const_iterator i = --s_check_point;
219 CamWnd& camwnd = *g_pParentWnd->GetCamWnd();
220 Camera_setOrigin( camwnd, *i );
221 g_pParentWnd->GetXYWnd()->SetOrigin( *i );
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 );
231 int LoadFile( const char *filename, void **bufferptr ){
235 f = fopen( filename, "rb" );
240 fseek( f, 0, SEEK_END );
244 *bufferptr = malloc( len + 1 );
245 if ( *bufferptr == 0 ) {
249 fread( *bufferptr, 1, len, f );
252 // we need to end the buffer with a 0
253 ( (char*) ( *bufferptr ) )[len] = 0;
258 void Pointfile_Parse( CPointfile& pointfile ){
264 const char* mapname = Map_Name( g_map );
265 StringOutputStream name( 256 );
266 name << StringRange( mapname, path_get_filename_base_end( mapname ) ) << ".lin";
268 size = LoadFile( name.c_str(), (void**)&data );
270 globalErrorStream() << "Pointfile " << name.c_str() << " not found\n";
277 globalOutputStream() << "Reading pointfile " << name.c_str() << "\n";
284 if ( sscanf( data,"%f %f %f", &v[0], &v[1], &v[2] ) != 3 ) {
285 globalOutputStream() << "Corrupt point file, line " << line << "\n";
289 while ( *data && *data != '\n' )
291 if ( *( data - 1 ) == ' ' && *( data ) == '-' && *( data + 1 ) == ' ' ) {
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";
303 while ( *data && *data != '\n' )
307 while ( *data == '\n' )
309 data++; // skip the \n
312 pointfile.PushPoint( v );
318 void Pointfile_Clear(){
319 s_pointfile.show( false );
322 void Pointfile_Toggle(){
323 s_pointfile.show( !s_pointfile.shown() );
325 s_check_point = s_pointfile.begin();
328 void Pointfile_Construct(){
329 CPointfile::constructStatic();
331 GlobalShaderCache().attachRenderable( s_pointfile );
333 GlobalCommands_insert( "TogglePointfile", FreeCaller<void(), Pointfile_Toggle>() );
334 GlobalCommands_insert( "NextLeakSpot", FreeCaller<void(), Pointfile_Next>(), Accelerator( 'K', (GdkModifierType)( GDK_SHIFT_MASK | GDK_CONTROL_MASK ) ) );
335 GlobalCommands_insert( "PrevLeakSpot", FreeCaller<void(), Pointfile_Prev>(), Accelerator( 'L', (GdkModifierType)( GDK_SHIFT_MASK | GDK_CONTROL_MASK ) ) );
338 void Pointfile_Destroy(){
339 GlobalShaderCache().detachRenderable( s_pointfile );
341 CPointfile::destroyStatic();
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" ) ) {
350 // there's a prefs setting to avoid stopping on leak
351 if ( !g_WatchBSP_LeakStop ) {
357 void CPointfile::saxEndElement( message_info_t *ctx, const xmlChar *name ){
358 if ( string_equal( reinterpret_cast<const char*>( name ), "polyline" ) ) {
360 GenerateDisplayList();
362 s_check_point = begin();
364 else if ( string_equal( reinterpret_cast<const char*>( name ), "point" ) ) {
366 sscanf( m_characters.c_str(), "%f %f %f\n", &v[0], &v[1], &v[2] );
368 m_characters.clear();
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 );
377 const char* CPointfile::getName(){