/*
-Copyright (C) 1999-2007 id Software, Inc. and contributors.
-For a list of contributors, see the accompanying CONTRIBUTORS file.
+ 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.
+ 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 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.
+ 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
-*/
+ 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
+ */
-#include "stdafx.h"
+/*
+ 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];
+ }
-#define MAX_POINTFILE 8192
-static vec3_t s_pointvecs[MAX_POINTFILE];
-static int s_num_points, s_check_point;
+ bool shown() const
+ {
+ return m_displaylist != 0;
+ }
-CPointfile g_pointfile;
+ 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");
+ }
+};
-// CPointfile routine used by the standard code ---------------------------------
+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;
+ s_num_points = 0;
+ m_displaylist = 0;
}
-void CPointfile::PushPoint (vec3_t v)
+void CPointfile::PushPoint(const Vector3 &v)
{
- if (s_num_points < MAX_POINTFILE)
- {
- VectorCopy (v, s_pointvecs[s_num_points]);
- s_num_points++;
- }
+ 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()
{
- int i;
-
- if (!g_qeglobals.d_pointfile_display_list)
- g_qeglobals.d_pointfile_display_list = qglGenLists(1);
-
- qglNewList (g_qeglobals.d_pointfile_display_list, GL_COMPILE);
-
- qglColor3f (1, 0, 0);
- qglDisable(GL_TEXTURE_2D);
- qglDisable(GL_TEXTURE_1D);
- qglLineWidth (4);
- qglBegin(GL_LINE_STRIP);
- for (i=0;i<s_num_points;i++)
- {
- if (s_num_points < MAX_POINTFILE)
- {
- qglVertex3fv (s_pointvecs[i]);
- }
- }
- qglEnd();
- qglLineWidth (1);
-
- qglEndList ();
-
- s_check_point = 0;
+ m_displaylist = glGenLists(1);
+
+ glNewList(m_displaylist, GL_COMPILE);
+
+ glBegin(GL_LINE_STRIP);
+ for (std::size_t i = 0; i < s_num_points; i++)
+ glVertex3fv(vector3_to_array(s_pointvecs[i]));
+ glEnd();
+ glLineWidth(1);
+
+ glEndList();
}
// old (but still relevant) pointfile code -------------------------------------
-void Pointfile_Delete (void)
+void Pointfile_Delete(void)
{
- char name[1024];
-
- strcpy (name, currentmap);
- StripExtension (name);
- strcat (name, ".lin");
-
- remove(name);
+ const char *mapname = Map_Name(g_map);
+ StringOutputStream name(256);
+ name << StringRange(mapname, path_get_filename_base_end(mapname)) << ".lin";
+ file_remove(name.c_str());
}
// advance camera to next point
-void Pointfile_Next (void)
+void Pointfile_Next(void)
{
- vec3_t dir;
+ if (!s_pointfile.shown()) {
+ return;
+ }
+
+ if (s_check_point + 2 == s_pointfile.end()) {
+ globalOutputStream() << "End of pointfile\n";
+ return;
+ }
+
+ CPointfile::const_iterator i = ++s_check_point;
- if (s_check_point >= s_num_points-2)
- {
- Sys_Status ("End of pointfile", 0);
- return;
- }
- s_check_point++;
- VectorCopy (s_pointvecs[s_check_point], g_pParentWnd->GetCamWnd()->Camera()->origin);
- VectorCopy (s_pointvecs[s_check_point], g_pParentWnd->GetXYWnd()->GetOrigin());
- VectorSubtract (s_pointvecs[s_check_point+1], g_pParentWnd->GetCamWnd()->Camera()->origin, dir);
- VectorNormalize (dir, dir);
- g_pParentWnd->GetCamWnd()->Camera()->angles[1] = atan2 (dir[1], dir[0])*180/3.14159;
- g_pParentWnd->GetCamWnd()->Camera()->angles[0] = asin (dir[2])*180/3.14159;
- Sys_UpdateWindows (W_ALL);
+ 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<float>( radians_to_degrees(atan2(dir[1], dir[0])));
+ angles[CAMERA_PITCH] = static_cast<float>( radians_to_degrees(asin(dir[2])));
+ Camera_setAngles(camwnd, angles);
+ }
}
// advance camera to previous point
-void Pointfile_Prev (void)
+void Pointfile_Prev(void)
{
- vec3_t dir;
+ if (!s_pointfile.shown()) {
+ return;
+ }
+
+ if (s_check_point == s_pointfile.begin()) {
+ globalOutputStream() << "Start of pointfile\n";
+ return;
+ }
- if ( s_check_point == 0)
- {
- Sys_Status ("Start of pointfile", 0);
- return;
- }
- s_check_point--;
- VectorCopy (s_pointvecs[s_check_point], g_pParentWnd->GetCamWnd()->Camera()->origin);
- VectorCopy (s_pointvecs[s_check_point], g_pParentWnd->GetXYWnd()->GetOrigin());
- VectorSubtract (s_pointvecs[s_check_point+1], g_pParentWnd->GetCamWnd()->Camera()->origin, dir);
- VectorNormalize (dir, dir);
- g_pParentWnd->GetCamWnd()->Camera()->angles[1] = atan2 (dir[1], dir[0])*180/3.14159;
- g_pParentWnd->GetCamWnd()->Camera()->angles[0] = asin (dir[2])*180/3.14159;
+ CPointfile::const_iterator i = --s_check_point;
- Sys_UpdateWindows (W_ALL);
+ 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<float>( radians_to_degrees(atan2(dir[1], dir[0])));
+ angles[CAMERA_PITCH] = static_cast<float>( radians_to_degrees(asin(dir[2])));
+ Camera_setAngles(camwnd, angles);
+ }
}
-void WINAPI Pointfile_Check (void)
+int LoadFile(const char *filename, void **bufferptr)
{
- char name[1024];
- int size;
- char *data;
- char *text;
- int line = 1;
- vec3_t v;
+ FILE *f;
+ long len;
- strcpy (name, currentmap);
- StripExtension (name);
- strcat (name, ".lin");
+ f = fopen(filename, "rb");
+ if (f == 0) {
+ return -1;
+ }
- size = vfsLoadFullPathFile (name, (void**)&data);
- if (size <= 0)
- {
- Sys_FPrintf (SYS_ERR, "Pointfile %s not found\n", name);
- return;
- }
+ fseek(f, 0, SEEK_END);
+ len = ftell(f);
+ rewind(f);
- // store a pointer
- text = data;
+ *bufferptr = malloc(len + 1);
+ if (*bufferptr == 0) {
+ return -1;
+ }
- Sys_Printf ("Reading pointfile %s\n", name);
+ fread(*bufferptr, 1, len, f);
+ fclose(f);
- g_pointfile.Init();
+ // we need to end the buffer with a 0
+ ((char *) (*bufferptr))[len] = 0;
- while (*data)
- {
- if (sscanf(data,"%f %f %f", &v[0], &v[1], &v[2]) != 3)
- {
- Sys_Printf("Corrupt point file, line %d\n",line);
- break;
+ 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;
}
- while (*data && *data != '\n')
- {
- if (*(data-1) == ' ' && *(data) == '-' && *(data+1) == ' ')
- break;
- data++;
+ // 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);
}
- // deal with zhlt style point files.
- if (*data == '-')
- {
- if (sscanf(data,"- %f %f %f", &v[0], &v[1], &v[2]) != 3)
- {
- Sys_Printf("Corrupt point file, line %d\n",line);
- break;
- }
- while (*data && *data != '\n')
- data++;
+ g_free(text);
+}
- }
- while (*data == '\n')
- {
- data++; // skip the \n
- line++;
- }
- g_pointfile.PushPoint (v);
- }
+void Pointfile_Clear()
+{
+ s_pointfile.show(false);
+}
- g_free(text);
-
- g_pointfile.GenerateDisplayList();
+void Pointfile_Toggle()
+{
+ s_pointfile.show(!s_pointfile.shown());
- Sys_UpdateWindows (W_ALL);
+ s_check_point = s_pointfile.begin();
}
-void Pointfile_Draw( void )
+void Pointfile_Construct()
{
- qglCallList (g_qeglobals.d_pointfile_display_list);
+ CPointfile::constructStatic();
+
+ GlobalShaderCache().attachRenderable(s_pointfile);
+
+ GlobalCommands_insert("TogglePointfile", makeCallbackF(Pointfile_Toggle));
+ GlobalCommands_insert("NextLeakSpot", makeCallbackF(Pointfile_Next),
+ Accelerator('K', (GdkModifierType) (GDK_SHIFT_MASK | GDK_CONTROL_MASK)));
+ GlobalCommands_insert("PrevLeakSpot", makeCallbackF(Pointfile_Prev),
+ Accelerator('L', (GdkModifierType) (GDK_SHIFT_MASK | GDK_CONTROL_MASK)));
}
-void Pointfile_Clear (void)
+void Pointfile_Destroy()
{
- if (!g_qeglobals.d_pointfile_display_list)
- return;
+ GlobalShaderCache().detachRenderable(s_pointfile);
- qglDeleteLists (g_qeglobals.d_pointfile_display_list, 1);
- g_qeglobals.d_pointfile_display_list = 0;
- Sys_UpdateWindows (W_ALL);
+ CPointfile::destroyStatic();
}
-// CPointfile implementation for SAX speicific stuff -------------------------------
-void CPointfile::saxStartElement (message_info_t *ctx, const xmlChar *name, const xmlChar **attrs)
+
+// CPointfile implementation for SAX-specific stuff -------------------------------
+void CPointfile::saxStartElement(message_info_t *ctx, const xmlChar *name, const xmlChar **attrs)
{
- if (strcmp ((char *)name, "polyline")==0)
- {
- Init();
- // there's a prefs setting to avoid stopping on leak
- if (!g_PrefsDlg.m_bLeakStop)
- ctx->stop_depth = 0;
- }
+ if (string_equal(reinterpret_cast<const char *>( 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)
+void CPointfile::saxEndElement(message_info_t *ctx, const xmlChar *name)
{
- if (strcmp ((char *)name, "polyline")==0)
- {
- // we are done
- GenerateDisplayList();
- ctx->bGeometry = false;
- }
+ if (string_equal(reinterpret_cast<const char *>( name ), "polyline")) {
+ // we are done
+ GenerateDisplayList();
+ SceneChangeNotify();
+ s_check_point = begin();
+ } else if (string_equal(reinterpret_cast<const char *>( 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)
+void CPointfile::saxCharacters(message_info_t *ctx, const xmlChar *ch, int len)
{
- vec3_t v;
-
- sscanf ((char *)ch, "%f %f %f\n", &v[0], &v[1], &v[2]);
- PushPoint (v);
+ m_characters.write(reinterpret_cast<const char *>( ch ), len);
}
-char * CPointfile::getName()
+const char *CPointfile::getName()
{
- return "Map is leaked";
+ return "Map leaked";
}