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.
32 #include "debugging/debugging.h"
36 #include "renderable.h"
38 #include "stream/stringstream.h"
45 #include "camwindow.h"
48 #include "mainframe.h"
55 void Pointfile_Parse(CPointfile &pointfile);
58 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;
78 void PushPoint(const Vector3 &v);
80 void GenerateDisplayList();
85 // blank because not heap-allocated
88 void saxStartElement(message_info_t *ctx, const xmlChar *name, const xmlChar **attrs);
90 void saxEndElement(message_info_t *ctx, const xmlChar *name);
92 void saxCharacters(message_info_t *ctx, const xmlChar *ch, int len);
94 const char *getName();
96 typedef const Vector3 *const_iterator;
98 const_iterator begin() const
100 return &s_pointvecs[0];
103 const_iterator end() const
105 return &s_pointvecs[s_num_points];
110 return m_displaylist != 0;
115 if (show && !shown()) {
116 Pointfile_Parse(*this);
117 GenerateDisplayList();
119 } else if (!show && shown()) {
120 glDeleteLists(m_displaylist, 1);
126 void render(RenderStateFlags state) const
128 glCallList(m_displaylist);
131 void renderSolid(Renderer &renderer, const VolumeTest &volume) const
134 renderer.SetState(m_renderstate, Renderer::eWireframeOnly);
135 renderer.SetState(m_renderstate, Renderer::eFullMaterials);
136 renderer.addRenderable(*this, g_matrix4_identity);
140 void renderWireframe(Renderer &renderer, const VolumeTest &volume) const
142 renderSolid(renderer, volume);
145 static void constructStatic()
147 m_renderstate = GlobalShaderCache().capture("$POINTFILE");
150 static void destroyStatic()
152 GlobalShaderCache().release("$POINTFILE");
156 Shader *CPointfile::m_renderstate = 0;
159 CPointfile s_pointfile;
162 ISAXHandler &g_pointfile = s_pointfile;
164 static CPointfile::const_iterator s_check_point;
166 void CPointfile::Init()
172 void CPointfile::PushPoint(const Vector3 &v)
174 if (s_num_points < MAX_POINTFILE) {
175 s_pointvecs[s_num_points] = v;
180 // create the display list at the end
181 void CPointfile::GenerateDisplayList()
183 m_displaylist = glGenLists(1);
185 glNewList(m_displaylist, GL_COMPILE);
187 glBegin(GL_LINE_STRIP);
188 for (std::size_t i = 0; i < s_num_points; i++)
189 glVertex3fv(vector3_to_array(s_pointvecs[i]));
196 // old (but still relevant) pointfile code -------------------------------------
198 void Pointfile_Delete(void)
200 const char *mapname = Map_Name(g_map);
201 StringOutputStream name(256);
202 name << StringRange(mapname, path_get_filename_base_end(mapname)) << ".lin";
203 file_remove(name.c_str());
206 // advance camera to next point
207 void Pointfile_Next(void)
209 if (!s_pointfile.shown()) {
213 if (s_check_point + 2 == s_pointfile.end()) {
214 globalOutputStream() << "End of pointfile\n";
218 CPointfile::const_iterator i = ++s_check_point;
221 CamWnd &camwnd = *g_pParentWnd->GetCamWnd();
222 Camera_setOrigin(camwnd, *i);
223 g_pParentWnd->GetXYWnd()->SetOrigin(*i);
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 // advance camera to previous point
234 void Pointfile_Prev(void)
236 if (!s_pointfile.shown()) {
240 if (s_check_point == s_pointfile.begin()) {
241 globalOutputStream() << "Start of pointfile\n";
245 CPointfile::const_iterator i = --s_check_point;
247 CamWnd &camwnd = *g_pParentWnd->GetCamWnd();
248 Camera_setOrigin(camwnd, *i);
249 g_pParentWnd->GetXYWnd()->SetOrigin(*i);
251 Vector3 dir(vector3_normalised(vector3_subtracted(*(++i), Camera_getOrigin(camwnd))));
252 Vector3 angles(Camera_getAngles(camwnd));
253 angles[CAMERA_YAW] = static_cast<float>( radians_to_degrees(atan2(dir[1], dir[0])));
254 angles[CAMERA_PITCH] = static_cast<float>( radians_to_degrees(asin(dir[2])));
255 Camera_setAngles(camwnd, angles);
259 int LoadFile(const char *filename, void **bufferptr)
264 f = fopen(filename, "rb");
269 fseek(f, 0, SEEK_END);
273 *bufferptr = malloc(len + 1);
274 if (*bufferptr == 0) {
278 assert(fread(*bufferptr, 1, len, f));
281 // we need to end the buffer with a 0
282 ((char *) (*bufferptr))[len] = 0;
287 void Pointfile_Parse(CPointfile &pointfile)
294 const char *mapname = Map_Name(g_map);
295 StringOutputStream name(256);
296 name << StringRange(mapname, path_get_filename_base_end(mapname)) << ".lin";
298 size = LoadFile(name.c_str(), (void **) &data);
300 globalErrorStream() << "Pointfile " << name.c_str() << " not found\n";
307 globalOutputStream() << "Reading pointfile " << name.c_str() << "\n";
313 if (sscanf(data, "%f %f %f", &v[0], &v[1], &v[2]) != 3) {
314 globalOutputStream() << "Corrupt point file, line " << line << "\n";
318 while (*data && *data != '\n') {
319 if (*(data - 1) == ' ' && *(data) == '-' && *(data + 1) == ' ') {
324 // deal with zhlt style point files.
326 if (sscanf(data, "- %f %f %f", &v[0], &v[1], &v[2]) != 3) {
327 globalOutputStream() << "Corrupt point file, line " << line << "\n";
331 while (*data && *data != '\n') {
336 while (*data == '\n') {
337 data++; // skip the \n
340 pointfile.PushPoint(v);
346 void Pointfile_Clear()
348 s_pointfile.show(false);
351 void Pointfile_Toggle()
353 s_pointfile.show(!s_pointfile.shown());
355 s_check_point = s_pointfile.begin();
358 void Pointfile_Construct()
360 CPointfile::constructStatic();
362 GlobalShaderCache().attachRenderable(s_pointfile);
364 GlobalCommands_insert("TogglePointfile", makeCallbackF(Pointfile_Toggle));
365 GlobalCommands_insert("NextLeakSpot", makeCallbackF(Pointfile_Next),
366 Accelerator('K', (GdkModifierType) (GDK_SHIFT_MASK | GDK_CONTROL_MASK)));
367 GlobalCommands_insert("PrevLeakSpot", makeCallbackF(Pointfile_Prev),
368 Accelerator('L', (GdkModifierType) (GDK_SHIFT_MASK | GDK_CONTROL_MASK)));
371 void Pointfile_Destroy()
373 GlobalShaderCache().detachRenderable(s_pointfile);
375 CPointfile::destroyStatic();
379 // CPointfile implementation for SAX-specific stuff -------------------------------
380 void CPointfile::saxStartElement(message_info_t *ctx, const xmlChar *name, const xmlChar **attrs)
382 if (string_equal(reinterpret_cast<const char *>( name ), "polyline")) {
384 // there's a prefs setting to avoid stopping on leak
385 if (!g_WatchBSP_LeakStop) {
391 void CPointfile::saxEndElement(message_info_t *ctx, const xmlChar *name)
393 if (string_equal(reinterpret_cast<const char *>( name ), "polyline")) {
395 GenerateDisplayList();
397 s_check_point = begin();
398 } else if (string_equal(reinterpret_cast<const char *>( name ), "point")) {
400 sscanf(m_characters.c_str(), "%f %f %f\n", &v[0], &v[1], &v[2]);
402 m_characters.clear();
406 // only "point" is expected to have characters around here
407 void CPointfile::saxCharacters(message_info_t *ctx, const xmlChar *ch, int len)
409 m_characters.write(reinterpret_cast<const char *>( ch ), len);
412 const char *CPointfile::getName()