1 /*
2 Copyright (C) 1999-2006 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 "feedback.h"
29
30 #include "debugging/debugging.h"
31
32 #include "igl.h"
33 #include "iselection.h"
34
35 #include <gtk/gtktreeview.h>
36 #include <gtk/gtktreeselection.h>
37 #include <gtk/gtkliststore.h>
38 #include <gtk/gtkcellrenderertext.h>
39 #include <gtk/gtkwindow.h>
40 #include <gtk/gtkscrolledwindow.h>
41
42 #include "map.h"
43 #include "dialog.h"
44 #include "mainframe.h"
45
46
47 CDbgDlg g_DbgDlg;
48
Feedback_draw2D(VIEWTYPE viewType)49 void Feedback_draw2D(VIEWTYPE viewType)
50 {
51 g_DbgDlg.draw2D(viewType);
52 }
53
saxStartElement(message_info_t * ctx,const xmlChar * name,const xmlChar ** attrs)54 void CSelectMsg::saxStartElement(message_info_t *ctx, const xmlChar *name, const xmlChar **attrs)
55 {
56 if(string_equal(reinterpret_cast<const char*>(name), "select"))
57 {
58 // read the message
59 ESelectState = SELECT_MESSAGE;
60 }
61 else
62 {
63 // read the brush
64 ASSERT_MESSAGE(string_equal(reinterpret_cast<const char*>(name), "brush"), "FEEDBACK PARSE ERROR");
65 ASSERT_MESSAGE(ESelectState == SELECT_MESSAGE, "FEEDBACK PARSE ERROR");
66 ESelectState = SELECT_BRUSH;
67 globalOutputStream() << message.c_str() << '\n';
68 }
69 }
70
saxEndElement(message_info_t * ctx,const xmlChar * name)71 void CSelectMsg::saxEndElement(message_info_t *ctx, const xmlChar *name)
72 {
73 if(string_equal(reinterpret_cast<const char*>(name), "select"))
74 {
75 }
76 }
77
saxCharacters(message_info_t * ctx,const xmlChar * ch,int len)78 void CSelectMsg::saxCharacters(message_info_t *ctx, const xmlChar *ch, int len)
79 {
80 if(ESelectState == SELECT_MESSAGE)
81 {
82 message.write(reinterpret_cast<const char*>(ch), len);
83 }
84 else
85 {
86 brush.write(reinterpret_cast<const char*>(ch), len);
87 }
88 }
89
Highlight()90 IGL2DWindow* CSelectMsg::Highlight()
91 {
92 GlobalSelectionSystem().setSelectedAll(false);
93 int entitynum, brushnum;
94 if(sscanf(reinterpret_cast<const char*>(brush.c_str()), "%i %i", &entitynum, &brushnum) == 2)
95 {
96 SelectBrush (entitynum, brushnum);
97 }
98 return 0;
99 }
100
saxStartElement(message_info_t * ctx,const xmlChar * name,const xmlChar ** attrs)101 void CPointMsg::saxStartElement(message_info_t *ctx, const xmlChar *name, const xmlChar **attrs)
102 {
103 if(string_equal(reinterpret_cast<const char*>(name), "pointmsg"))
104 {
105 // read the message
106 EPointState = POINT_MESSAGE;
107 }
108 else
109 {
110 // read the brush
111 ASSERT_MESSAGE(string_equal(reinterpret_cast<const char*>(name), "point"), "FEEDBACK PARSE ERROR");
112 ASSERT_MESSAGE(EPointState == POINT_MESSAGE, "FEEDBACK PARSE ERROR");
113 EPointState = POINT_POINT;
114 globalOutputStream() << message.c_str() << '\n';
115 }
116 }
117
saxEndElement(message_info_t * ctx,const xmlChar * name)118 void CPointMsg::saxEndElement (message_info_t *ctx, const xmlChar *name)
119 {
120 if(string_equal(reinterpret_cast<const char*>(name), "pointmsg"))
121 {
122 }
123 else if(string_equal(reinterpret_cast<const char*>(name), "point"))
124 {
125 sscanf(point.c_str(), "%g %g %g", &(pt[0]), &(pt[1]), &(pt[2]));
126 point.clear();
127 }
128 }
129
saxCharacters(message_info_t * ctx,const xmlChar * ch,int len)130 void CPointMsg::saxCharacters (message_info_t *ctx, const xmlChar *ch, int len)
131 {
132 if(EPointState == POINT_MESSAGE)
133 {
134 message.write(reinterpret_cast<const char*>(ch), len);
135 }
136 else
137 {
138 ASSERT_MESSAGE(EPointState == POINT_POINT, "FEEDBACK PARSE ERROR");
139 point.write(reinterpret_cast<const char*>(ch), len);
140 }
141 }
142
Highlight()143 IGL2DWindow* CPointMsg::Highlight()
144 {
145 return this;
146 }
147
DropHighlight()148 void CPointMsg::DropHighlight()
149 {
150 }
151
Draw2D(VIEWTYPE vt)152 void CPointMsg::Draw2D( VIEWTYPE vt )
153 {
154 int nDim1 = (vt == YZ) ? 1 : 0;
155 int nDim2 = (vt == XY) ? 1 : 2;
156 glPointSize(4);
157 glColor3f(1.0f,0.0f,0.0f);
158 glBegin (GL_POINTS);
159 glVertex2f (pt[nDim1], pt[nDim2]);
160 glEnd();
161 glBegin (GL_LINE_LOOP);
162 glVertex2f (pt[nDim1]-8, pt[nDim2]-8);
163 glVertex2f (pt[nDim1]+8, pt[nDim2]-8);
164 glVertex2f (pt[nDim1]+8, pt[nDim2]+8);
165 glVertex2f (pt[nDim1]-8, pt[nDim2]+8);
166 glEnd();
167 }
168
saxStartElement(message_info_t * ctx,const xmlChar * name,const xmlChar ** attrs)169 void CWindingMsg::saxStartElement(message_info_t *ctx, const xmlChar *name, const xmlChar **attrs)
170 {
171 if(string_equal(reinterpret_cast<const char*>(name), "windingmsg"))
172 {
173 // read the message
174 EPointState = WINDING_MESSAGE;
175 }
176 else
177 {
178 // read the brush
179 ASSERT_MESSAGE(string_equal(reinterpret_cast<const char*>(name), "winding"), "FEEDBACK PARSE ERROR");
180 ASSERT_MESSAGE(EPointState == WINDING_MESSAGE, "FEEDBACK PARSE ERROR");
181 EPointState = WINDING_WINDING;
182 globalOutputStream() << message.c_str() << '\n';
183 }
184 }
185
saxEndElement(message_info_t * ctx,const xmlChar * name)186 void CWindingMsg::saxEndElement(message_info_t *ctx, const xmlChar *name)
187 {
188 if(string_equal(reinterpret_cast<const char*>(name), "windingmsg"))
189 {
190 }
191 else if(string_equal(reinterpret_cast<const char*>(name), "winding"))
192 {
193 const char* c = winding.c_str();
194 sscanf(c, "%i ", &numpoints);
195
196 int i = 0;
197 for(; i < numpoints; i++)
198 {
199 c = strchr(c + 1, '(');
200 if(c) // even if we are given the number of points when the cycle begins .. don't trust it too much
201 sscanf(c, "(%g %g %g)", &wt[i][0], &wt[i][1], &wt[i][2]);
202 else
203 break;
204 }
205 numpoints = i;
206 }
207 }
208
saxCharacters(message_info_t * ctx,const xmlChar * ch,int len)209 void CWindingMsg::saxCharacters(message_info_t *ctx, const xmlChar *ch, int len)
210 {
211 if(EPointState == WINDING_MESSAGE)
212 {
213 message.write(reinterpret_cast<const char*>(ch), len);
214 }
215 else
216 {
217 ASSERT_MESSAGE(EPointState == WINDING_WINDING, "FEEDBACK PARSE ERROR");
218 winding.write(reinterpret_cast<const char*>(ch), len);
219 }
220 }
221
Highlight()222 IGL2DWindow* CWindingMsg::Highlight()
223 {
224 return this;
225 }
226
DropHighlight()227 void CWindingMsg::DropHighlight()
228 {
229 }
230
Draw2D(VIEWTYPE vt)231 void CWindingMsg::Draw2D( VIEWTYPE vt )
232 {
233 int i;
234
235 int nDim1 = (vt == YZ) ? 1 : 0;
236 int nDim2 = (vt == XY) ? 1 : 2;
237 glColor3f(1.0f,0.f,0.0f);
238
239 glPointSize(4);
240 glBegin (GL_POINTS);
241 for(i = 0; i < numpoints; i++)
242 glVertex2f (wt[i][nDim1], wt[i][nDim2]);
243 glEnd();
244 glPointSize(1);
245
246 glEnable (GL_BLEND);
247 glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
248 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
249 glColor4f(0.133f,0.4f,1.0f,0.5f);
250 glBegin (GL_POLYGON);
251 for(i = 0; i < numpoints; i++)
252 glVertex2f (wt[i][nDim1], wt[i][nDim2]);
253 glEnd();
254 glDisable (GL_BLEND);
255 }
256
257 // triggered when the user selects an entry in the feedback box
feedback_selection_changed(GtkTreeSelection * selection,gpointer data)258 static void feedback_selection_changed(GtkTreeSelection* selection, gpointer data)
259 {
260 g_DbgDlg.DropHighlight();
261
262 GtkTreeModel* model;
263 GtkTreeIter selected;
264 if(gtk_tree_selection_get_selected(selection, &model, &selected))
265 {
266 GtkTreePath* path = gtk_tree_model_get_path(model, &selected);
267 g_DbgDlg.SetHighlight(gtk_tree_path_get_indices(path)[0]);
268 gtk_tree_path_free(path);
269 }
270 }
271
DropHighlight()272 void CDbgDlg::DropHighlight()
273 {
274 if(m_pHighlight != 0)
275 {
276 m_pHighlight->DropHighlight();
277 m_pHighlight = 0;
278 m_pDraw2D = 0;
279 }
280 }
281
SetHighlight(gint row)282 void CDbgDlg::SetHighlight(gint row)
283 {
284 ISAXHandler *h = GetElement(row);
285 if(h != NULL)
286 {
287 m_pDraw2D = h->Highlight();
288 m_pHighlight = h;
289 }
290 }
291
GetElement(std::size_t row)292 ISAXHandler *CDbgDlg::GetElement (std::size_t row)
293 {
294 return static_cast<ISAXHandler *>(g_ptr_array_index(m_pFeedbackElements, gint(row)));
295 }
296
Init()297 void CDbgDlg::Init()
298 {
299 DropHighlight();
300
301 // free all the ISAXHandler*, clean it
302 while (m_pFeedbackElements->len)
303 {
304 static_cast<ISAXHandler *>(g_ptr_array_index (m_pFeedbackElements, 0))->Release();
305 g_ptr_array_remove_index (m_pFeedbackElements, 0);
306 }
307
308 if(m_clist != NULL)
309 gtk_list_store_clear (m_clist);
310 }
311
Push(ISAXHandler * pHandler)312 void CDbgDlg::Push (ISAXHandler *pHandler)
313 {
314 // push in the list
315 g_ptr_array_add (m_pFeedbackElements, (void *)pHandler);
316
317 if(GetWidget() == 0)
318 {
319 Create();
320 }
321
322 // put stuff in the list
323 gtk_list_store_clear (m_clist);
324 for(std::size_t i = 0; i < static_cast<std::size_t>(m_pFeedbackElements->len); ++i)
325 {
326 GtkTreeIter iter;
327 gtk_list_store_append(m_clist, &iter);
328 gtk_list_store_set(m_clist, &iter, 0, GetElement(i)->getName(), -1);
329 }
330
331 ShowDlg();
332 }
333
BuildDialog()334 GtkWindow* CDbgDlg::BuildDialog()
335 {
336 GtkWindow* window = create_floating_window("Q3Map debug window", MainFrame_getWindow());
337
338 GtkWidget* scr = gtk_scrolled_window_new (NULL, NULL);
339 gtk_widget_show (scr);
340 gtk_container_add (GTK_CONTAINER (window), GTK_WIDGET (scr));
341 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scr), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
342 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scr), GTK_SHADOW_IN);
343
344 {
345 GtkListStore* store = gtk_list_store_new(1, G_TYPE_STRING);
346
347 GtkWidget* view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
348 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE);
349
350 {
351 GtkCellRenderer* renderer = gtk_cell_renderer_text_new();
352 GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("", renderer, "text", 0, NULL);
353 gtk_tree_view_append_column(GTK_TREE_VIEW(view), column);
354 }
355
356 {
357 GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
358 gtk_tree_selection_set_mode(selection, GTK_SELECTION_BROWSE);
359 g_signal_connect(G_OBJECT(selection), "changed", G_CALLBACK(feedback_selection_changed), NULL);
360 }
361
362 gtk_widget_show(view);
363
364 gtk_container_add(GTK_CONTAINER (scr), view);
365
366 g_object_unref(G_OBJECT(store));
367
368 m_clist = store;
369 }
370
371 return window;
372 }
373