propagate from internal tree
[xonotic/netradiant.git] / radiant / feedback.cpp
1 /*
2 Copyright (C) 1999-2007 id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
4
5 This file is part of GtkRadiant.
6
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.
11
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.
16
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
20 */
21
22 //-----------------------------------------------------------------------------
23 //
24 // DESCRIPTION:
25 // classes used for describing geometry information from q3map feedback
26 //
27
28 #include "stdafx.h"
29
30 #include "feedback.h"
31 #include "glib.h"
32 #include <assert.h>
33
34 CDbgDlg g_DbgDlg;
35
36 void CSelectMsg::saxStartElement (message_info_t *ctx, const xmlChar *name, const xmlChar **attrs)
37 {
38   if (strcmp ((char *)name, "select")==0)
39   {
40     // read the message
41     ESelectState = SELECT_MESSAGE;
42   }
43   else
44   {
45     // read the brush
46     assert (strcmp ((char *)name, "brush")==0);
47     assert (ESelectState == SELECT_MESSAGE);
48     ESelectState = SELECT_BRUSH;
49   }
50 }
51
52 void CSelectMsg::saxEndElement (message_info_t *ctx, const xmlChar *name)
53 {
54   if (strcmp ((char *)name, "select")==0)
55   {
56     ctx->bGeometry = false;
57   }
58 }
59
60 void CSelectMsg::saxCharacters (message_info_t *ctx, const xmlChar *ch, int len)
61 {
62   if (ESelectState == SELECT_MESSAGE)
63   {
64     message = g_string_sized_new (len+1);
65     memcpy (message->str, ch, len);
66     message->str[len]='\0';
67     Sys_Printf ("%s\n", message->str);
68   }
69   else
70   {
71     assert (ESelectState == SELECT_BRUSH);
72     sscanf ((char *)ch, "%i %i", &entitynum, &brushnum);
73   }
74 }
75
76 void CSelectMsg::Highlight ()
77 {
78   Select_Deselect ();
79   SelectBrush (entitynum, brushnum);
80 }
81
82 void CPointMsg::saxStartElement (message_info_t *ctx, const xmlChar *name, const xmlChar **attrs)
83 {
84   if (strcmp ((char *)name, "pointmsg")==0)
85   {
86     // read the message
87     EPointState = POINT_MESSAGE;
88   }
89   else
90   {
91     // read the brush
92     assert (strcmp ((char *)name, "point")==0);
93     assert (EPointState == POINT_MESSAGE);
94     EPointState = POINT_POINT;
95   }
96 }
97
98 void CPointMsg::saxEndElement (message_info_t *ctx, const xmlChar *name)
99 {
100   if (strcmp ((char *)name, "pointmsg")==0)
101   {
102     ctx->bGeometry = false;
103   }
104 }
105
106 void CPointMsg::saxCharacters (message_info_t *ctx, const xmlChar *ch, int len)
107 {
108   if (EPointState == POINT_MESSAGE)
109   {
110     message = g_string_sized_new (len+1);
111     memcpy (message->str, ch, len);
112     message->str[len]='\0';
113     Sys_Printf ("%s\n", message->str);
114   }
115   else
116   {
117     assert (EPointState == POINT_POINT);
118     sscanf ((char *)ch, "%g %g %g", &(pt[0]), &(pt[1]), &(pt[2]));
119   }
120 }
121
122 void CPointMsg::Highlight ()
123 {
124   // use the entity API to push a point
125   // the API requires a ref count, we do it manually for the current instance
126   if (refCount == 0)
127   {
128     refCount++;
129     QERApp_HookGL2DWindow (this);
130   }
131 }
132
133 void CPointMsg::DropHighlight ()
134 {
135   assert (refCount > 0);
136   QERApp_UnHookGL2DWindow (this);
137   // do a refCount-- locally (see Highlight)
138   refCount--;
139 }
140
141 void CPointMsg::Draw2D( VIEWTYPE vt )
142 {
143   int nDim1 = (vt == YZ) ? 1 : 0;
144   int nDim2 = (vt == XY) ? 1 : 2;
145   qglPointSize(4);
146   qglColor3f(1.0f,0.0f,0.0f);
147   qglBegin (GL_POINTS);
148   qglVertex2f (pt[nDim1], pt[nDim2]);
149   qglEnd();
150   qglBegin (GL_LINE_LOOP);
151   qglVertex2f (pt[nDim1]-8, pt[nDim2]-8);
152   qglVertex2f (pt[nDim1]+8, pt[nDim2]-8);
153   qglVertex2f (pt[nDim1]+8, pt[nDim2]+8);
154   qglVertex2f (pt[nDim1]-8, pt[nDim2]+8);
155   qglEnd();
156 }
157
158 void CWindingMsg::saxStartElement (message_info_t *ctx, const xmlChar *name, const xmlChar **attrs)
159 {
160   if (strcmp ((char *)name, "windingmsg")==0)
161   {
162     // read the message
163     EPointState = WINDING_MESSAGE;
164   }
165   else
166   {
167     // read the brush
168     assert (strcmp ((char *)name, "winding")==0);
169     assert (EPointState == WINDING_MESSAGE);
170     EPointState = WINDING_WINDING;
171   }
172 }
173
174 void CWindingMsg::saxEndElement (message_info_t *ctx, const xmlChar *name)
175 {
176   if (strcmp ((char *)name, "windingmsg")==0)
177   {
178     ctx->bGeometry = false;
179   }
180 }
181
182 void CWindingMsg::saxCharacters (message_info_t *ctx, const xmlChar *ch, int len)
183 {
184   if (EPointState == WINDING_MESSAGE)
185   {
186     message = g_string_sized_new (len+1);
187     memcpy (message->str, ch, len);
188     message->str[len]='\0';
189     Sys_Printf ("%s\n", message->str);
190   }
191   else
192   {
193     char* c;
194     int i;
195
196     assert (EPointState == WINDING_WINDING);
197
198
199     c = (char*)ch;
200     sscanf (c, "%i ", &numpoints);
201
202     for(i = 0; i < numpoints; i++)
203     {
204       c = strchr(++c, '(');
205       if (c) // even if we are given the number of points when the cycle begins .. don't trust it too much
206         sscanf(c, "(%g %g %g)", &wt[i][0], &wt[i][1], &wt[i][2]);
207       else
208         break;
209     }
210     numpoints = i;
211   }
212 }
213
214 void CWindingMsg::Highlight ()
215 {
216   // use the entity API to push a point
217   // the API requires a ref count, we do it manually for the current instance
218   if (refCount == 0)
219   {
220     refCount++;
221     QERApp_HookGL2DWindow (this);
222   }
223 }
224
225 void CWindingMsg::DropHighlight ()
226 {
227   assert (refCount > 0);
228   QERApp_UnHookGL2DWindow (this);
229   // do a refCount-- locally (see Highlight)
230   refCount--;
231 }
232
233 void CWindingMsg::Draw2D( VIEWTYPE vt )
234 {
235   int i;
236
237   int nDim1 = (vt == YZ) ? 1 : 0;
238   int nDim2 = (vt == XY) ? 1 : 2;
239   qglColor3f(1.0f,0.f,0.0f);
240
241   qglPointSize(4);
242   qglBegin (GL_POINTS);
243   for(i = 0; i < numpoints; i++)
244         qglVertex2f (wt[i][nDim1], wt[i][nDim2]);
245   qglEnd();
246   qglPointSize(1);
247
248   qglEnable (GL_BLEND);
249   qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
250   qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
251   qglColor4f(0.133f,0.4f,1.0f,0.5f);
252   qglBegin (GL_POLYGON);
253         for(i = 0; i < numpoints; i++)
254                 qglVertex2f (wt[i][nDim1], wt[i][nDim2]);
255   qglEnd();
256   qglDisable (GL_BLEND);
257 }
258
259 // triggered when the user selects an entry in the feedback box
260 static void feedback_selection_changed(GtkTreeSelection* selection, gpointer data)
261 {
262   g_DbgDlg.DropHighlight();
263
264   GtkTreeModel* model;
265   GtkTreeIter selected;
266   if(gtk_tree_selection_get_selected(selection, &model, &selected))
267   {
268     GtkTreePath* path = gtk_tree_model_get_path(model, &selected);
269       g_DbgDlg.SetHighlight(gtk_tree_path_get_indices(path)[0]);
270     gtk_tree_path_free(path);
271   }
272 }
273
274 void CDbgDlg::DropHighlight()
275 {
276   if (m_pHighlight)
277   {
278     m_pHighlight->DropHighlight();
279     m_pHighlight = NULL;
280   }
281 }
282
283 void CDbgDlg::SetHighlight(gint row)
284 {
285   ISAXHandler *h = GetElement(row);
286   if (h != NULL)
287   {
288     h->Highlight();
289     m_pHighlight = h;
290   }
291 }
292
293 ISAXHandler *CDbgDlg::GetElement( gint row ) {
294         return static_cast<ISAXHandler *>( g_ptr_array_index( m_pFeedbackElements, row ) );
295 }
296
297 void CDbgDlg::ClearFeedbackArray() {
298         // free all the ISAXHandler*, clean it
299         while ( m_pFeedbackElements->len ) {
300                 // some ISAXHandler are static and passed around but should never be deleted
301                 ISAXHandler *handler = static_cast< ISAXHandler * >( g_ptr_array_index( m_pFeedbackElements, 0 ) );
302                 if ( handler->ShouldDelete() ) {
303                         delete handler;
304                 }
305                 g_ptr_array_remove_index( m_pFeedbackElements, 0 );
306         }
307 }
308
309 void CDbgDlg::Init() {
310         DropHighlight();
311
312         ClearFeedbackArray();
313
314         if ( m_clist != NULL ) {
315                 gtk_list_store_clear( m_clist );
316         }
317 }
318
319 void CDbgDlg::Push( ISAXHandler *pHandler ) {
320         // push in the list
321         g_ptr_array_add( m_pFeedbackElements, (void *)pHandler );
322
323         if ( m_pWidget == NULL ) {
324                 Create();
325         }
326         // put stuff in the list
327         gtk_list_store_clear( m_clist );
328         unsigned int i;
329         for ( i = 0; i < m_pFeedbackElements->len; i++ ) {
330                 GtkTreeIter iter;
331                 gtk_list_store_append( m_clist, &iter );
332                 gtk_list_store_set( m_clist, &iter, 0, GetElement(i)->getName(), -1 );
333         }
334
335         ShowDlg();
336 }
337
338 void CDbgDlg::BuildDialog ()
339 {
340   gtk_window_set_title (GTK_WINDOW (m_pWidget), "Q3Map debug window");
341
342   GtkWidget* scr = gtk_scrolled_window_new (NULL, NULL);
343   gtk_widget_show (scr);
344   gtk_container_add (GTK_CONTAINER (m_pWidget), GTK_WIDGET (scr));
345   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scr), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
346   gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scr), GTK_SHADOW_IN);
347
348   {
349     GtkListStore* store = gtk_list_store_new(1, G_TYPE_STRING);
350
351     GtkWidget* view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
352     gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE);
353
354     {
355       GtkCellRenderer* renderer = gtk_cell_renderer_text_new();
356       GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("", renderer, "text", 0, NULL);
357       gtk_tree_view_append_column(GTK_TREE_VIEW(view), column);
358     }
359
360     {
361       GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
362       gtk_tree_selection_set_mode(selection, GTK_SELECTION_BROWSE);
363       g_signal_connect(G_OBJECT(selection), "changed", G_CALLBACK(feedback_selection_changed), NULL);
364     }
365
366     gtk_widget_show(view);
367
368     gtk_container_add(GTK_CONTAINER (scr), view);
369
370     g_object_unref(G_OBJECT(store));
371
372     m_clist = store;
373   }
374 }