/* Copyright (C) 1999-2006 Id Software, Inc. and contributors. For a list of contributors, see the accompanying CONTRIBUTORS file. This file is part of GtkRadiant. GtkRadiant is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. GtkRadiant is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GtkRadiant; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ /* The following source code is licensed by Id Software and subject to the terms of its LIMITED USE SOFTWARE LICENSE AGREEMENT, a copy of which is included with GtkRadiant. If you did not receive a LIMITED USE SOFTWARE LICENSE AGREEMENT, please contact Id Software immediately at info@idsoftware.com. */ #include "points.h" #include "debugging/debugging.h" #include "irender.h" #include "igl.h" #include "renderable.h" #include "stream/stringstream.h" #include "os/path.h" #include "os/file.h" #include "cmdlib.h" #include "map.h" #include "qe3.h" #include "camwindow.h" #include "xywindow.h" #include "xmlstuff.h" #include "mainframe.h" #include "watchbsp.h" #include "commands.h" class CPointfile; void Pointfile_Parse(CPointfile& pointfile); class CPointfile : public ISAXHandler, public Renderable, public OpenGLRenderable { enum { MAX_POINTFILE = 8192, }; Vector3 s_pointvecs[MAX_POINTFILE]; std::size_t s_num_points; int m_displaylist; static Shader* m_renderstate; StringOutputStream m_characters; public: CPointfile() { } ~CPointfile() { } void Init(); void PushPoint (const Vector3& v); void GenerateDisplayList(); // SAX interface void Release() { // blank because not heap-allocated } void saxStartElement (message_info_t *ctx, const xmlChar *name, const xmlChar **attrs); void saxEndElement (message_info_t *ctx, const xmlChar *name); void saxCharacters (message_info_t *ctx, const xmlChar *ch, int len); const char* getName(); typedef const Vector3* const_iterator; const_iterator begin() const { return &s_pointvecs[0]; } const_iterator end() const { return &s_pointvecs[s_num_points]; } bool shown() const { return m_displaylist != 0; } void show(bool show) { if(show && !shown()) { Pointfile_Parse(*this); GenerateDisplayList(); SceneChangeNotify(); } else if(!show && shown()) { glDeleteLists (m_displaylist, 1); m_displaylist = 0; SceneChangeNotify(); } } void render(RenderStateFlags state) const { glCallList(m_displaylist); } void renderSolid(Renderer& renderer, const VolumeTest& volume) const { if(shown()) { renderer.SetState(m_renderstate, Renderer::eWireframeOnly); renderer.SetState(m_renderstate, Renderer::eFullMaterials); renderer.addRenderable(*this, g_matrix4_identity); } } void renderWireframe(Renderer& renderer, const VolumeTest& volume) const { renderSolid(renderer, volume); } static void constructStatic() { m_renderstate = GlobalShaderCache().capture("$POINTFILE"); } static void destroyStatic() { GlobalShaderCache().release("$POINTFILE"); } }; Shader* CPointfile::m_renderstate = 0; namespace { CPointfile s_pointfile; } ISAXHandler& g_pointfile = s_pointfile; static CPointfile::const_iterator s_check_point; void CPointfile::Init() { s_num_points = 0; m_displaylist = 0; } void CPointfile::PushPoint(const Vector3& v) { if (s_num_points < MAX_POINTFILE) { s_pointvecs[s_num_points] = v; ++s_num_points; } } // create the display list at the end void CPointfile::GenerateDisplayList() { m_displaylist = glGenLists(1); glNewList (m_displaylist, GL_COMPILE); glBegin(GL_LINE_STRIP); for(std::size_t i=0;iGetCamWnd(); Camera_setOrigin(camwnd, *i); g_pParentWnd->GetXYWnd()->SetOrigin(*i); { Vector3 dir(vector3_normalised(vector3_subtracted(*(++i), Camera_getOrigin(camwnd)))); Vector3 angles(Camera_getAngles(camwnd)); angles[CAMERA_YAW] = static_cast(radians_to_degrees(atan2(dir[1], dir[0]))); angles[CAMERA_PITCH] = static_cast(radians_to_degrees(asin(dir[2]))); Camera_setAngles(camwnd, angles); } } // advance camera to previous point void Pointfile_Prev (void) { if(!s_pointfile.shown()) return; if (s_check_point == s_pointfile.begin()) { globalOutputStream() << "Start of pointfile\n"; return; } CPointfile::const_iterator i = --s_check_point; CamWnd& camwnd = *g_pParentWnd->GetCamWnd(); Camera_setOrigin(camwnd, *i); g_pParentWnd->GetXYWnd()->SetOrigin(*i); { Vector3 dir(vector3_normalised(vector3_subtracted(*(++i), Camera_getOrigin(camwnd)))); Vector3 angles(Camera_getAngles(camwnd)); angles[CAMERA_YAW] = static_cast(radians_to_degrees(atan2(dir[1], dir[0]))); angles[CAMERA_PITCH] = static_cast(radians_to_degrees(asin(dir[2]))); Camera_setAngles(camwnd, angles); } } int LoadFile (const char *filename, void **bufferptr) { FILE *f; long len; f = fopen (filename, "rb"); if (f == 0) return -1; fseek (f, 0, SEEK_END); len = ftell (f); rewind (f); *bufferptr = malloc (len+1); if (*bufferptr == 0) return -1; fread (*bufferptr, 1, len, f); fclose (f); // we need to end the buffer with a 0 ((char*) (*bufferptr))[len] = 0; return len; } void Pointfile_Parse(CPointfile& pointfile) { int size; char *data; char *text; int line = 1; const char* mapname = Map_Name(g_map); StringOutputStream name(256); name << StringRange(mapname, path_get_filename_base_end(mapname)) << ".lin"; size = LoadFile (name.c_str(), (void**)&data); if (size == -1) { globalErrorStream() << "Pointfile " << name.c_str() << " not found\n"; return; } // store a pointer text = data; globalOutputStream() << "Reading pointfile " << name.c_str() << "\n"; pointfile.Init(); while (*data) { Vector3 v; if (sscanf(data,"%f %f %f", &v[0], &v[1], &v[2]) != 3) { globalOutputStream() << "Corrupt point file, line " << line << "\n"; break; } while (*data && *data != '\n') { if (*(data-1) == ' ' && *(data) == '-' && *(data+1) == ' ') break; data++; } // deal with zhlt style point files. if (*data == '-') { if (sscanf(data,"- %f %f %f", &v[0], &v[1], &v[2]) != 3) { globalOutputStream() << "Corrupt point file, line " << line << "\n"; break; } while (*data && *data != '\n') data++; } while (*data == '\n') { data++; // skip the \n line++; } pointfile.PushPoint (v); } g_free(text); } void Pointfile_Clear() { s_pointfile.show(false); } void Pointfile_Toggle() { s_pointfile.show(!s_pointfile.shown()); s_check_point = s_pointfile.begin(); } void Pointfile_Construct() { CPointfile::constructStatic(); GlobalShaderCache().attachRenderable(s_pointfile); GlobalCommands_insert("TogglePointfile", FreeCaller()); GlobalCommands_insert("NextLeakSpot", FreeCaller(), Accelerator('K', (GdkModifierType)(GDK_SHIFT_MASK|GDK_CONTROL_MASK))); GlobalCommands_insert("PrevLeakSpot", FreeCaller(), Accelerator('L', (GdkModifierType)(GDK_SHIFT_MASK|GDK_CONTROL_MASK))); } void Pointfile_Destroy() { GlobalShaderCache().detachRenderable(s_pointfile); CPointfile::destroyStatic(); } // CPointfile implementation for SAX-specific stuff ------------------------------- void CPointfile::saxStartElement (message_info_t *ctx, const xmlChar *name, const xmlChar **attrs) { if(string_equal(reinterpret_cast(name), "polyline")) { Init(); // there's a prefs setting to avoid stopping on leak if (!g_WatchBSP_LeakStop) ctx->stop_depth = 0; } } void CPointfile::saxEndElement (message_info_t *ctx, const xmlChar *name) { if(string_equal(reinterpret_cast(name), "polyline")) { // we are done GenerateDisplayList(); SceneChangeNotify(); } else if(string_equal(reinterpret_cast(name), "point")) { Vector3 v; sscanf(m_characters.c_str(), "%f %f %f\n", &v[0], &v[1], &v[2]); PushPoint(v); m_characters.clear(); } } // only "point" is expected to have characters around here void CPointfile::saxCharacters (message_info_t *ctx, const xmlChar *ch, int len) { m_characters.write(reinterpret_cast(ch), len); } const char* CPointfile::getName() { return "Map leaked"; }