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->ActiveXY()->SetOrigin( *i );
197 g_pParentWnd->ActiveXY()->queueDraw();
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 );
207 // advance camera to previous point
208 void Pointfile_Prev( void ){
209 if ( !s_pointfile.shown() ) {
213 if ( s_check_point == s_pointfile.begin() ) {
214 globalOutputStream() << "Start of pointfile\n";
218 CPointfile::const_iterator i = --s_check_point;
220 CamWnd& camwnd = *g_pParentWnd->GetCamWnd();
221 Camera_setOrigin( camwnd, *i );
222 g_pParentWnd->ActiveXY()->SetOrigin( *i );
223 g_pParentWnd->ActiveXY()->queueDraw();
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 );
233 int LoadFile( const char *filename, void **bufferptr ){
237 f = fopen( filename, "rb" );
242 fseek( f, 0, SEEK_END );
246 *bufferptr = malloc( len + 1 );
247 if ( *bufferptr == 0 ) {
251 fread( *bufferptr, 1, len, f );
254 // we need to end the buffer with a 0
255 ( (char*) ( *bufferptr ) )[len] = 0;
260 void Pointfile_Parse( CPointfile& pointfile ){
266 const char* mapname = Map_Name( g_map );
267 StringOutputStream name( 256 );
268 name << StringRange( mapname, path_get_filename_base_end( mapname ) ) << ".lin";
270 size = LoadFile( name.c_str(), (void**)&data );
272 globalErrorStream() << "Pointfile " << name.c_str() << " not found\n";
279 globalOutputStream() << "Reading pointfile " << name.c_str() << "\n";
286 if ( sscanf( data,"%f %f %f", &v[0], &v[1], &v[2] ) != 3 ) {
287 globalOutputStream() << "Corrupt point file, line " << line << "\n";
291 while ( *data && *data != '\n' )
293 if ( *( data - 1 ) == ' ' && *( data ) == '-' && *( data + 1 ) == ' ' ) {
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";
305 while ( *data && *data != '\n' )
309 while ( *data == '\n' )
311 data++; // skip the \n
314 pointfile.PushPoint( v );
320 void Pointfile_Clear(){
321 s_pointfile.show( false );
324 void Pointfile_Toggle(){
325 s_pointfile.show( !s_pointfile.shown() );
327 s_check_point = s_pointfile.begin();
330 void Pointfile_Construct(){
331 CPointfile::constructStatic();
333 GlobalShaderCache().attachRenderable( s_pointfile );
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 ) ) );
340 void Pointfile_Destroy(){
341 GlobalShaderCache().detachRenderable( s_pointfile );
343 CPointfile::destroyStatic();
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" ) ) {
352 // there's a prefs setting to avoid stopping on leak
353 if ( !g_WatchBSP_LeakStop ) {
359 void CPointfile::saxEndElement( message_info_t *ctx, const xmlChar *name ){
360 if ( string_equal( reinterpret_cast<const char*>( name ), "polyline" ) ) {
362 GenerateDisplayList();
364 s_check_point = begin();
366 else if ( string_equal( reinterpret_cast<const char*>( name ), "point" ) ) {
368 sscanf( m_characters.c_str(), "%f %f %f\n", &v[0], &v[1], &v[2] );
370 m_characters.clear();
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 );
379 const char* CPointfile::getName(){