-/*\r
-Copyright (C) 1999-2007 id Software, Inc. and contributors.\r
-For a list of contributors, see the accompanying CONTRIBUTORS file.\r
-\r
-This file is part of GtkRadiant.\r
-\r
-GtkRadiant is free software; you can redistribute it and/or modify\r
-it under the terms of the GNU General Public License as published by\r
-the Free Software Foundation; either version 2 of the License, or\r
-(at your option) any later version.\r
-\r
-GtkRadiant is distributed in the hope that it will be useful,\r
-but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
-GNU General Public License for more details.\r
-\r
-You should have received a copy of the GNU General Public License\r
-along with GtkRadiant; if not, write to the Free Software\r
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\r
-*/\r
-\r
-//\r
-// bkgrnd2d Plugin\r
-//\r
-// Code by reyalP aka Reed Mideke\r
-//\r
-// Based on various other plugins\r
-//\r
-\r
-#include "bkgrnd2d.h"\r
-\r
-CBackgroundRender render;\r
-\r
-CBackgroundImage backgroundXY(XY),backgroundXZ(XZ),backgroundYZ(YZ);\r
-\r
-CBackgroundRender::CBackgroundRender()\r
-{\r
- refCount = 1;\r
-}\r
-\r
-CBackgroundRender::~CBackgroundRender()\r
-{\r
-}\r
-\r
-void CBackgroundRender::Register()\r
-{\r
- g_QglTable.m_pfnHookGL2DWindow( this );\r
-}\r
-\r
-void CBackgroundRender::Draw2D( VIEWTYPE vt )\r
-{\r
- switch(vt)\r
- {\r
- case XY:\r
- backgroundXY.Render();\r
- break;\r
- case XZ:\r
- backgroundXZ.Render();\r
- break;\r
- case YZ:\r
- backgroundYZ.Render();\r
- break;\r
- }\r
-}\r
-\r
-\r
-CBackgroundImage::CBackgroundImage(VIEWTYPE vt)\r
-{\r
- m_tex = NULL;\r
- m_alpha = 0.5;\r
-\r
- // TODO, sensible defaults ? Or not show until we have extents ?\r
- m_xmin = m_ymin = 0.0f;\r
- m_xmax = m_ymax = 0.0f;\r
-\r
- m_bActive = false;\r
-\r
- m_vt = vt;\r
-\r
- switch(m_vt)\r
- {\r
- case XY:\r
- m_ix = 0;\r
- m_iy = 1;\r
- break;\r
- case XZ:\r
- m_ix = 0;\r
- m_iy = 2;\r
- break;\r
- case YZ:\r
- m_ix = 1;\r
- m_iy = 2;\r
- break;\r
- }\r
-}\r
-\r
-/*\r
- * should cleanup, but I don't think we can be sure it happens before our \r
- * interfaces are gone\r
-CBackgroundImage::~CBackgroundImage()\r
-{\r
-}\r
-*/\r
-\r
-void CBackgroundImage::Cleanup()\r
-{\r
- if(m_tex) {\r
- g_QglTable.m_pfn_qglDeleteTextures(1,&m_tex->texture_number);\r
- g_free(m_tex);\r
- m_tex = NULL;\r
- }\r
-}\r
-\r
-void CBackgroundImage::Render()\r
-{\r
- if (!m_bActive || !Valid())\r
- return;\r
- g_QglTable.m_pfn_qglPushAttrib(GL_ALL_ATTRIB_BITS);\r
-\r
- g_QglTable.m_pfn_qglEnable(GL_TEXTURE_2D);\r
- g_QglTable.m_pfn_qglEnable(GL_BLEND);\r
- g_QglTable.m_pfn_qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\r
- g_QglTable.m_pfn_qglTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);\r
- g_QglTable.m_pfn_qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);\r
- g_QglTable.m_pfn_qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);\r
-\r
- g_QglTable.m_pfn_qglPolygonMode(GL_FRONT,GL_FILL);\r
- // TODO, just so we can tell if we end up going the wrong way\r
- // g_QglTable.m_pfn_qglPolygonMode(GL_BACK,GL_LINE);\r
- // TODO any other state we should not assume ?\r
-\r
- g_QglTable.m_pfn_qglBindTexture(GL_TEXTURE_2D, m_tex->texture_number);\r
- g_QglTable.m_pfn_qglBegin(GL_QUADS);\r
-\r
- g_QglTable.m_pfn_qglColor4f(1.0,1.0,1.0,m_alpha);\r
- g_QglTable.m_pfn_qglTexCoord2f(0.0,1.0);\r
- g_QglTable.m_pfn_qglVertex2f(m_xmin,m_ymin);\r
-\r
- g_QglTable.m_pfn_qglTexCoord2f(1.0,1.0);\r
- g_QglTable.m_pfn_qglVertex2f(m_xmax,m_ymin);\r
-\r
- g_QglTable.m_pfn_qglTexCoord2f(1.0,0.0);\r
- g_QglTable.m_pfn_qglVertex2f(m_xmax,m_ymax);\r
-\r
- g_QglTable.m_pfn_qglTexCoord2f(0.0,0.0);\r
- g_QglTable.m_pfn_qglVertex2f(m_xmin,m_ymax);\r
-\r
- g_QglTable.m_pfn_qglEnd();\r
- g_QglTable.m_pfn_qglBindTexture(GL_TEXTURE_2D, 0);\r
-\r
- g_QglTable.m_pfn_qglPopAttrib();\r
-}\r
-\r
-bool CBackgroundImage::Load(const char *filename)\r
-{\r
- qtexture_t *newtex;\r
- \r
- unsigned char *image = NULL; // gets allocated with what ? g_malloc\r
- int width = 0, height = 0;\r
-\r
- g_FuncTable.m_pfnLoadImage(filename,&image,&width,&height);\r
-\r
- if(!image) {\r
- Syn_Printf(MSG_WARN "load %s failed\n",filename);\r
- return false;\r
- }\r
-\r
-// just in case we want to build for an old version\r
-// http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=900\r
-#ifdef BKGRND2D_JPG_WORKAROUND\r
- if ( strlen(filename) > 4 && !strcmp(".jpg",filename + strlen(filename) - 4)) {\r
- Syn_Printf(MSG_PREFIX ".jpg workaround, clearing alpha channel\n");\r
- int size = width*height*4;\r
- int i;\r
- for (i = 3; i < size; i+=4) {\r
- image[i] = 255;\r
- }\r
- }\r
-#endif\r
- \r
- //TODO bug for stored texture size\r
- //TODO whose gl context are we in, anyway ?\r
- newtex = g_FuncTable.m_pfnLoadTextureRGBA(image,width,height);\r
-\r
- g_free(image);\r
-\r
- if(!newtex) {\r
- Syn_Printf(MSG_WARN "image to texture failed\n");\r
- return false;\r
- }\r
-\r
- Cleanup();\r
- m_tex = newtex;\r
-\r
- g_FuncTable.m_pfnSysUpdateWindows(W_XY);\r
-\r
- return true;\r
-}\r
-\r
-bool CBackgroundImage::SetExtentsMM()\r
-{\r
- entity_s *worldentity;\r
- const char *val;\r
- int xmin = 0, ymin = 0, xmax = 0, ymax = 0;\r
-\r
- worldentity = (entity_s *)g_FuncTable.m_pfnGetEntityHandle(0);\r
- if(!worldentity) {\r
- Syn_Printf(MSG_WARN "SetExtentsMM worldspawn not found\n");\r
- return false;\r
- }\r
- //TODO val is not NULL even if key does not exist\r
- val = g_EntityTable.m_pfnValueForKey(worldentity,"mapcoordsmins");\r
- if(!val || !val[0]) {\r
- Syn_Printf(MSG_WARN "SetExtentsMM mapcoordsmins not found\n");\r
- return false;\r
- }\r
-// we could be more robust\r
-// note contortions due to splashs strange idea of min and max\r
- if(sscanf(val, "%d %d",&xmin,&ymax) != 2)\r
- {\r
- Syn_Printf(MSG_WARN "SetExtentsMM mapcoordsmins malformed\n");\r
- return false;\r
- }\r
-\r
- val = g_EntityTable.m_pfnValueForKey(worldentity,"mapcoordsmaxs");\r
- if(!val || !val[0]) {\r
- Syn_Printf(MSG_WARN "SetExtentsMM mapcoordsmaxs not found\n");\r
- return false;\r
- }\r
- if(sscanf(val, "%d %d",&xmax,&ymin) != 2)\r
- {\r
- Syn_Printf(MSG_WARN "SetExtentsMM mapcoordsmaxs malformed\n");\r
- return false;\r
- }\r
- //might do sanity check before we commit\r
- m_xmin = (float)xmin;\r
- m_ymin = (float)ymin;\r
- m_xmax = (float)xmax;\r
- m_ymax = (float)ymax;\r
-\r
- g_FuncTable.m_pfnSysUpdateWindows(W_XY);\r
- return true;\r
-}\r
-\r
-// TODO, this should just be exported from core\r
-// ripped directly from radiant/select.cpp:Select_GetBounds\r
-//\r
-static bool get_selection_bounds (vec3_t mins, vec3_t maxs)\r
-{\r
- brush_t *b;\r
- int i;\r
- brush_t *selected_brushes = g_DataTable.m_pfnSelectedBrushes();\r
- //TODO should never happen\r
- if(!selected_brushes) {\r
- Sys_Printf (MSG_PREFIX "selected_brushes = NULL\n"); \r
- return false;\r
- }\r
- // this should mean no selection\r
- if(selected_brushes == selected_brushes->next) {\r
- Sys_Printf (MSG_PREFIX "nothing selected\n"); \r
-\r
- return false;\r
- }\r
-\r
- for (i=0 ; i<3 ; i++)\r
- {\r
- mins[i] = 99999;\r
- maxs[i] = -99999;\r
- }\r
-\r
- for (b=selected_brushes->next ; b != selected_brushes ; b=b->next)\r
- {\r
- if (b->owner->eclass->fixedsize)\r
- {\r
- for (i=0 ; i<3 ; i++)\r
- {\r
- if (b->owner->origin[i] < mins[i])\r
- mins[i] = b->owner->origin[i];\r
- if (b->owner->origin[i] > maxs[i])\r
- maxs[i] = b->owner->origin[i];\r
- }\r
- }\r
- else\r
- {\r
- for (i=0 ; i<3 ; i++)\r
- {\r
- if (b->mins[i] < mins[i])\r
- mins[i] = b->mins[i];\r
- if (b->maxs[i] > maxs[i])\r
- maxs[i] = b->maxs[i];\r
- }\r
- }\r
- }\r
- return true;\r
-}\r
-\r
-bool CBackgroundImage::SetExtentsSel()\r
-{\r
- vec3_t mins,maxs;\r
-\r
- if(!get_selection_bounds(mins,maxs)) \r
- return false;\r
-\r
- if(((int)mins[m_ix] == (int)maxs[m_ix]) ||\r
- ((int)mins[m_iy] == (int)maxs[m_iy])) {\r
- Syn_Printf(MSG_PREFIX "tiny selection\n");\r
- return false;\r
- }\r
-\r
- m_xmin = mins[m_ix];\r
- m_ymin = mins[m_iy];\r
- m_xmax = maxs[m_ix];\r
- m_ymax = maxs[m_iy];\r
-\r
- g_FuncTable.m_pfnSysUpdateWindows(W_XY);\r
-\r
- return true;\r
-}\r
-\r
+/*
+Copyright (C) 1999-2007 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
+*/
+
+//
+// bkgrnd2d Plugin
+//
+// Code by reyalP aka Reed Mideke
+//
+// Based on various other plugins
+//
+
+#include "bkgrnd2d.h"
+
+CBackgroundRender render;
+
+CBackgroundImage backgroundXY(XY),backgroundXZ(XZ),backgroundYZ(YZ);
+
+CBackgroundRender::CBackgroundRender()
+{
+ refCount = 1;
+}
+
+CBackgroundRender::~CBackgroundRender()
+{
+}
+
+void CBackgroundRender::Register()
+{
+ g_QglTable.m_pfnHookGL2DWindow( this );
+}
+
+void CBackgroundRender::Draw2D( VIEWTYPE vt )
+{
+ switch(vt)
+ {
+ case XY:
+ backgroundXY.Render();
+ break;
+ case XZ:
+ backgroundXZ.Render();
+ break;
+ case YZ:
+ backgroundYZ.Render();
+ break;
+ }
+}
+
+
+CBackgroundImage::CBackgroundImage(VIEWTYPE vt)
+{
+ m_tex = NULL;
+ m_alpha = 0.5;
+
+ // TODO, sensible defaults ? Or not show until we have extents ?
+ m_xmin = m_ymin = 0.0f;
+ m_xmax = m_ymax = 0.0f;
+
+ m_bActive = false;
+
+ m_vt = vt;
+
+ switch(m_vt)
+ {
+ case XY:
+ m_ix = 0;
+ m_iy = 1;
+ break;
+ case XZ:
+ m_ix = 0;
+ m_iy = 2;
+ break;
+ case YZ:
+ m_ix = 1;
+ m_iy = 2;
+ break;
+ }
+}
+
+/*
+ * should cleanup, but I don't think we can be sure it happens before our
+ * interfaces are gone
+CBackgroundImage::~CBackgroundImage()
+{
+}
+*/
+
+void CBackgroundImage::Cleanup()
+{
+ if(m_tex) {
+ g_QglTable.m_pfn_qglDeleteTextures(1,&m_tex->texture_number);
+ g_free(m_tex);
+ m_tex = NULL;
+ }
+}
+
+void CBackgroundImage::Render()
+{
+ if (!m_bActive || !Valid())
+ return;
+ g_QglTable.m_pfn_qglPushAttrib(GL_ALL_ATTRIB_BITS);
+
+ g_QglTable.m_pfn_qglEnable(GL_TEXTURE_2D);
+ g_QglTable.m_pfn_qglEnable(GL_BLEND);
+ g_QglTable.m_pfn_qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ g_QglTable.m_pfn_qglTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ g_QglTable.m_pfn_qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+ g_QglTable.m_pfn_qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+
+ g_QglTable.m_pfn_qglPolygonMode(GL_FRONT,GL_FILL);
+ // TODO, just so we can tell if we end up going the wrong way
+ // g_QglTable.m_pfn_qglPolygonMode(GL_BACK,GL_LINE);
+ // TODO any other state we should not assume ?
+
+ g_QglTable.m_pfn_qglBindTexture(GL_TEXTURE_2D, m_tex->texture_number);
+ g_QglTable.m_pfn_qglBegin(GL_QUADS);
+
+ g_QglTable.m_pfn_qglColor4f(1.0,1.0,1.0,m_alpha);
+ g_QglTable.m_pfn_qglTexCoord2f(0.0,1.0);
+ g_QglTable.m_pfn_qglVertex2f(m_xmin,m_ymin);
+
+ g_QglTable.m_pfn_qglTexCoord2f(1.0,1.0);
+ g_QglTable.m_pfn_qglVertex2f(m_xmax,m_ymin);
+
+ g_QglTable.m_pfn_qglTexCoord2f(1.0,0.0);
+ g_QglTable.m_pfn_qglVertex2f(m_xmax,m_ymax);
+
+ g_QglTable.m_pfn_qglTexCoord2f(0.0,0.0);
+ g_QglTable.m_pfn_qglVertex2f(m_xmin,m_ymax);
+
+ g_QglTable.m_pfn_qglEnd();
+ g_QglTable.m_pfn_qglBindTexture(GL_TEXTURE_2D, 0);
+
+ g_QglTable.m_pfn_qglPopAttrib();
+}
+
+bool CBackgroundImage::Load(const char *filename)
+{
+ qtexture_t *newtex;
+
+ unsigned char *image = NULL; // gets allocated with what ? g_malloc
+ int width = 0, height = 0;
+
+ g_FuncTable.m_pfnLoadImage(filename,&image,&width,&height);
+
+ if(!image) {
+ Syn_Printf(MSG_WARN "load %s failed\n",filename);
+ return false;
+ }
+
+// just in case we want to build for an old version
+// http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=900
+#ifdef BKGRND2D_JPG_WORKAROUND
+ if ( strlen(filename) > 4 && !strcmp(".jpg",filename + strlen(filename) - 4)) {
+ Syn_Printf(MSG_PREFIX ".jpg workaround, clearing alpha channel\n");
+ int size = width*height*4;
+ int i;
+ for (i = 3; i < size; i+=4) {
+ image[i] = 255;
+ }
+ }
+#endif
+
+ //TODO bug for stored texture size
+ //TODO whose gl context are we in, anyway ?
+ newtex = g_FuncTable.m_pfnLoadTextureRGBA(image,width,height);
+
+ g_free(image);
+
+ if(!newtex) {
+ Syn_Printf(MSG_WARN "image to texture failed\n");
+ return false;
+ }
+
+ Cleanup();
+ m_tex = newtex;
+
+ g_FuncTable.m_pfnSysUpdateWindows(W_XY);
+
+ return true;
+}
+
+bool CBackgroundImage::SetExtentsMM()
+{
+ entity_s *worldentity;
+ const char *val;
+ int xmin = 0, ymin = 0, xmax = 0, ymax = 0;
+
+ worldentity = (entity_s *)g_FuncTable.m_pfnGetEntityHandle(0);
+ if(!worldentity) {
+ Syn_Printf(MSG_WARN "SetExtentsMM worldspawn not found\n");
+ return false;
+ }
+ //TODO val is not NULL even if key does not exist
+ val = g_EntityTable.m_pfnValueForKey(worldentity,"mapcoordsmins");
+ if(!val || !val[0]) {
+ Syn_Printf(MSG_WARN "SetExtentsMM mapcoordsmins not found\n");
+ return false;
+ }
+// we could be more robust
+// note contortions due to splashs strange idea of min and max
+ if(sscanf(val, "%d %d",&xmin,&ymax) != 2)
+ {
+ Syn_Printf(MSG_WARN "SetExtentsMM mapcoordsmins malformed\n");
+ return false;
+ }
+
+ val = g_EntityTable.m_pfnValueForKey(worldentity,"mapcoordsmaxs");
+ if(!val || !val[0]) {
+ Syn_Printf(MSG_WARN "SetExtentsMM mapcoordsmaxs not found\n");
+ return false;
+ }
+ if(sscanf(val, "%d %d",&xmax,&ymin) != 2)
+ {
+ Syn_Printf(MSG_WARN "SetExtentsMM mapcoordsmaxs malformed\n");
+ return false;
+ }
+ //might do sanity check before we commit
+ m_xmin = (float)xmin;
+ m_ymin = (float)ymin;
+ m_xmax = (float)xmax;
+ m_ymax = (float)ymax;
+
+ g_FuncTable.m_pfnSysUpdateWindows(W_XY);
+ return true;
+}
+
+// TODO, this should just be exported from core
+// ripped directly from radiant/select.cpp:Select_GetBounds
+//
+static bool get_selection_bounds (vec3_t mins, vec3_t maxs)
+{
+ brush_t *b;
+ int i;
+ brush_t *selected_brushes = g_DataTable.m_pfnSelectedBrushes();
+ //TODO should never happen
+ if(!selected_brushes) {
+ Sys_Printf (MSG_PREFIX "selected_brushes = NULL\n");
+ return false;
+ }
+ // this should mean no selection
+ if(selected_brushes == selected_brushes->next) {
+ Sys_Printf (MSG_PREFIX "nothing selected\n");
+
+ return false;
+ }
+
+ for (i=0 ; i<3 ; i++)
+ {
+ mins[i] = 99999;
+ maxs[i] = -99999;
+ }
+
+ for (b=selected_brushes->next ; b != selected_brushes ; b=b->next)
+ {
+ if (b->owner->eclass->fixedsize)
+ {
+ for (i=0 ; i<3 ; i++)
+ {
+ if (b->owner->origin[i] < mins[i])
+ mins[i] = b->owner->origin[i];
+ if (b->owner->origin[i] > maxs[i])
+ maxs[i] = b->owner->origin[i];
+ }
+ }
+ else
+ {
+ for (i=0 ; i<3 ; i++)
+ {
+ if (b->mins[i] < mins[i])
+ mins[i] = b->mins[i];
+ if (b->maxs[i] > maxs[i])
+ maxs[i] = b->maxs[i];
+ }
+ }
+ }
+ return true;
+}
+
+bool CBackgroundImage::SetExtentsSel()
+{
+ vec3_t mins,maxs;
+
+ if(!get_selection_bounds(mins,maxs))
+ return false;
+
+ if(((int)mins[m_ix] == (int)maxs[m_ix]) ||
+ ((int)mins[m_iy] == (int)maxs[m_iy])) {
+ Syn_Printf(MSG_PREFIX "tiny selection\n");
+ return false;
+ }
+
+ m_xmin = mins[m_ix];
+ m_ymin = mins[m_iy];
+ m_xmax = maxs[m_ix];
+ m_ymax = maxs[m_iy];
+
+ g_FuncTable.m_pfnSysUpdateWindows(W_XY);
+
+ return true;
+}
+
-/*\r
-Copyright (C) 1999-2007 id Software, Inc. and contributors.\r
-For a list of contributors, see the accompanying CONTRIBUTORS file.\r
-\r
-This file is part of GtkRadiant.\r
-\r
-GtkRadiant is free software; you can redistribute it and/or modify\r
-it under the terms of the GNU General Public License as published by\r
-the Free Software Foundation; either version 2 of the License, or\r
-(at your option) any later version.\r
-\r
-GtkRadiant is distributed in the hope that it will be useful,\r
-but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
-GNU General Public License for more details.\r
-\r
-You should have received a copy of the GNU General Public License\r
-along with GtkRadiant; if not, write to the Free Software\r
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\r
-*/\r
-\r
-//\r
-// bkgrnd2d Plugin dialog\r
-//\r
-// Code by reyalP aka Reed Mideke\r
-//\r
-// Based on various other plugins\r
-//\r
-\r
-#include <gtk/gtk.h>\r
-\r
-#include "bkgrnd2d.h"\r
-#include "dialog.h"\r
-\r
-// spaces to make label nice and big\r
-#define NO_FILE_MSG " (no file loaded) "\r
-\r
-static GtkWidget *pDialogWnd;\r
-static GtkWidget *pNotebook;\r
-static GtkTooltips *pTooltips;\r
-\r
-class CBackgroundDialogPage\r
-{\r
-private:\r
- GtkWidget *m_pWidget;\r
- GtkWidget *m_pTabLabel;\r
- GtkWidget *m_pFileLabel;\r
- GtkWidget *m_pPosLabel;\r
- VIEWTYPE m_vt;\r
- bool m_bValidFile;\r
-\r
-public:\r
- CBackgroundImage *m_pImage;\r
- CBackgroundDialogPage( VIEWTYPE vt );\r
- void Append(GtkWidget *notebook);\r
- void Browse();\r
- void Reload();\r
- void SetPosLabel();\r
-// ~BackgroundDialogPage();\r
-};\r
-\r
-\r
-// dialog page callbacks\r
-static void browse_callback( GtkWidget *widget, gpointer data )\r
-{\r
- ((CBackgroundDialogPage *)data)->Browse();\r
-}\r
-\r
-static void reload_callback( GtkWidget *widget, gpointer data )\r
-{\r
- ((CBackgroundDialogPage *)data)->Reload();\r
-}\r
-\r
-static void size_sel_callback( GtkWidget *widget, gpointer data )\r
-{\r
- CBackgroundDialogPage *pPage = (CBackgroundDialogPage *)data;\r
- if (pPage->m_pImage->SetExtentsSel())\r
- pPage->SetPosLabel();\r
-}\r
-\r
-static void size_mm_callback( GtkWidget *widget, gpointer data )\r
-{\r
- CBackgroundDialogPage *pPage = (CBackgroundDialogPage *)data;\r
- if(pPage->m_pImage->SetExtentsMM())\r
- pPage->SetPosLabel();\r
-}\r
-\r
-static void alpha_adjust_callback( GtkWidget *widget, gpointer data )\r
-{\r
- CBackgroundDialogPage *pPage = (CBackgroundDialogPage *)data;\r
- pPage->m_pImage->m_alpha = (float)gtk_range_get_value (GTK_RANGE(widget));\r
- g_FuncTable.m_pfnSysUpdateWindows(W_XY);\r
-}\r
-\r
-void CBackgroundDialogPage::Reload()\r
-{\r
- if(m_bValidFile)\r
- m_pImage->Load(gtk_label_get_text(GTK_LABEL(m_pFileLabel)));\r
-}\r
-\r
-void CBackgroundDialogPage::Browse()\r
-{\r
- char browsedir[PATH_MAX];\r
- const char *ct;\r
- const char *newfile;\r
- char *t;\r
- \r
- //TODO GetMapName saves the map. eeep!\r
- //also with no map, returns unnamed.map, otherwise returns full path\r
-// Syn_Printf(MSG_PREFIX "GetMapName() %s\n",\r
-// g_FuncTable.m_pfnGetMapName());\r
- \r
- ct = g_FuncTable.m_pfnReadProjectKey("basepath");\r
- // TODO shouldn't need this stuff\r
- if(!ct || !strlen(ct)) {\r
- Syn_Printf(MSG_PREFIX "basepath = NULL or empty\n");\r
- return;\r
- }\r
- Syn_Printf(MSG_PREFIX "basepath: %s\n",ct);\r
- if(strlen(ct) >= PATH_MAX) {\r
- Syn_Printf(MSG_PREFIX "base game dir too long\n");\r
- return;\r
- }\r
-\r
- strcpy(browsedir,ct);\r
- // make sure we have a trailing / \r
- if(browsedir[strlen(browsedir) - 1] != '/')\r
- strcat(browsedir,"/");\r
-\r
- //if we dont have a file yet, don't try to use it for default dir\r
- if(m_bValidFile) {\r
- // filename should always be a nice clean unix style relative path\r
- ct = gtk_label_get_text(GTK_LABEL(m_pFileLabel));\r
- strcat(browsedir,ct);\r
- Syn_Printf(MSG_PREFIX "full path: %s\n",browsedir);\r
-\r
- // lop off the file part\r
- t = browsedir + strlen(browsedir) - 1;\r
- while (t != browsedir && *t != '/') \r
- t--;\r
- *t = 0;\r
- }\r
- Syn_Printf(MSG_PREFIX "browse directory %s\n",browsedir);\r
- \r
-//does NOT need freeing contrary to include/qerplugin.h comments\r
-//TODO bug/patch for comments\r
-//TODO patern gets fucked up sometimes if empty\r
-//http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=915\r
- newfile = g_FuncTable.m_pfnFileDialog(pDialogWnd,TRUE,\r
- "Load Background Image",browsedir,FILETYPE_KEY);\r
- if(!newfile) {\r
- Syn_Printf(MSG_PREFIX "newfile = NULL\n");\r
- return;\r
- }\r
- Syn_Printf(MSG_PREFIX "newfile: %s\n",newfile);\r
- newfile = g_FileSystemTable.m_pfnExtractRelativePath(newfile);\r
-\r
- if(!newfile) {\r
- Syn_Printf(MSG_PREFIX "newfile = NULL\n");\r
- return;\r
- }\r
- Syn_Printf(MSG_PREFIX "newfile: %s\n",newfile);\r
-\r
- if(m_pImage->Load(newfile)) {\r
- m_bValidFile = true;\r
- gtk_label_set_text(GTK_LABEL(m_pFileLabel),newfile);\r
- }\r
-}\r
-\r
-void CBackgroundDialogPage::SetPosLabel()\r
-{\r
- char s[64];\r
- // TODO no snprintf ?\r
- sprintf(s, "Size/Position (%d,%d) (%d,%d)",(int)(m_pImage->m_xmin),\r
- (int)(m_pImage->m_ymin),(int)(m_pImage->m_xmax),(int)(m_pImage->m_ymax));\r
- gtk_label_set_text(GTK_LABEL(m_pPosLabel),s);\r
-}\r
-\r
-CBackgroundDialogPage::CBackgroundDialogPage(VIEWTYPE vt )\r
-{\r
- GtkWidget *frame;\r
- GtkWidget *hbox;\r
- GtkWidget *w;\r
-\r
- m_vt = vt;\r
-\r
- m_bValidFile = false;\r
-\r
- switch(m_vt)\r
- {\r
- case XY:\r
- m_pTabLabel = gtk_label_new("X/Y");\r
- m_pImage = &backgroundXY;\r
- break;\r
- case XZ:\r
- m_pTabLabel = gtk_label_new("X/Z");\r
- m_pImage = &backgroundXZ;\r
- break;\r
- case YZ:\r
- m_pTabLabel = gtk_label_new("Y/Z");\r
- m_pImage = &backgroundYZ;\r
- break;\r
- }\r
-// A vbox to hold everything\r
- m_pWidget = gtk_vbox_new(FALSE,0); \r
-// Frame for file row\r
- frame = gtk_frame_new("File");\r
- gtk_box_pack_start (GTK_BOX (m_pWidget),frame, FALSE, FALSE, 2);\r
-\r
-// hbox for first row\r
- hbox = gtk_hbox_new(FALSE,5);\r
- gtk_container_set_border_width(GTK_CONTAINER (hbox),4);\r
- gtk_container_add (GTK_CONTAINER (frame), hbox);\r
-\r
-// label to display filename\r
- m_pFileLabel = gtk_label_new(NO_FILE_MSG);\r
- gtk_label_set_selectable(GTK_LABEL(m_pFileLabel),TRUE);\r
-//TODO set min size ? done with spaces right now\r
- gtk_box_pack_start (GTK_BOX (hbox),m_pFileLabel, TRUE, TRUE, 5);\r
-\r
- gtk_widget_show (m_pFileLabel);\r
-\r
- w = gtk_button_new_with_label ("Browse...");\r
- g_signal_connect (G_OBJECT (w), "clicked", G_CALLBACK (browse_callback),\r
- (gpointer)this);\r
- gtk_box_pack_start (GTK_BOX (hbox),w, FALSE, FALSE, 5);\r
- gtk_tooltips_set_tip (pTooltips, w, "Select a file", NULL);\r
- gtk_widget_show (w);\r
- \r
- w = gtk_button_new_with_label ("Reload");\r
- g_signal_connect (G_OBJECT (w), "clicked", G_CALLBACK (reload_callback),\r
- (gpointer)this);\r
- // TODO disable until we have file\r
- // gtk_widget_set_sensitive(w,FALSE);\r
- gtk_tooltips_set_tip (pTooltips, w, "Reload current file", NULL);\r
- gtk_box_pack_start (GTK_BOX (hbox),w, FALSE, FALSE, 5);\r
- gtk_widget_show (w);\r
-\r
- gtk_widget_show (hbox);\r
- gtk_widget_show (frame);\r
-\r
-// second row (rendering options)\r
- frame = gtk_frame_new("Rendering");\r
- gtk_box_pack_start (GTK_BOX (m_pWidget),frame, FALSE, FALSE, 2);\r
-\r
- hbox = gtk_hbox_new(FALSE,5);\r
- gtk_container_set_border_width(GTK_CONTAINER (hbox),4);\r
- gtk_container_add (GTK_CONTAINER (frame), hbox);\r
-\r
- w = gtk_label_new("Vertex alpha:");\r
- gtk_box_pack_start (GTK_BOX (hbox),w, FALSE, FALSE, 5);\r
- gtk_widget_show (w);\r
-\r
- w = gtk_hscale_new_with_range(0.0,1.0,0.01);\r
- gtk_range_set_value(GTK_RANGE(w),0.5);\r
- gtk_scale_set_value_pos(GTK_SCALE(w),GTK_POS_LEFT);\r
- g_signal_connect (G_OBJECT (w), "value-changed",\r
- G_CALLBACK (alpha_adjust_callback), (gpointer)this);\r
- gtk_box_pack_start (GTK_BOX (hbox),w, TRUE, TRUE, 5);\r
- gtk_tooltips_set_tip (pTooltips, w, "Set image transparancy", NULL);\r
- gtk_widget_show (w);\r
-\r
- gtk_widget_show (hbox);\r
- gtk_widget_show (frame);\r
-// Third row (size and position)\r
- frame = gtk_frame_new("Size/Position (undefined)");\r
- m_pPosLabel = gtk_frame_get_label_widget (GTK_FRAME(frame));\r
- gtk_box_pack_start ( GTK_BOX (m_pWidget), frame, FALSE, FALSE, 2);\r
-\r
- hbox = gtk_hbox_new(FALSE,5);\r
- gtk_container_add (GTK_CONTAINER (frame), hbox);\r
- gtk_container_set_border_width(GTK_CONTAINER (hbox),4);\r
-\r
- w = gtk_button_new_with_label ("from selection");\r
- gtk_box_pack_start (GTK_BOX (hbox),w, TRUE, FALSE, 5);\r
- g_signal_connect (G_OBJECT (w), "clicked", G_CALLBACK (size_sel_callback),\r
- (gpointer)this);\r
- gtk_tooltips_set_tip (pTooltips, w, "Set the size of the image to the bounding rectangle of all selected brushes and entities", NULL);\r
- gtk_widget_show (w);\r
-\r
- if(m_vt == XY) {\r
- w = gtk_button_new_with_label ("from map mins/maxs");\r
- gtk_box_pack_start ( GTK_BOX (hbox),w, TRUE, FALSE, 2);\r
- g_signal_connect (G_OBJECT (w), "clicked", G_CALLBACK (size_mm_callback),\r
- (gpointer)this);\r
- gtk_tooltips_set_tip (pTooltips, w, "Set the size of the image using the mapcoordsmins and mapcoordsmaxs keys of the worldspawn entity", NULL);\r
- gtk_widget_show (w);\r
- }\r
-\r
- gtk_widget_show (hbox);\r
- gtk_widget_show (frame);\r
-\r
- gtk_widget_show ( m_pWidget );\r
-}\r
-\r
-void CBackgroundDialogPage::Append(GtkWidget *notebook)\r
-{\r
- gtk_notebook_append_page( GTK_NOTEBOOK(notebook), m_pWidget, m_pTabLabel);\r
-}\r
-\r
-// dialog global callbacks\r
-/*\r
-static gint expose_callback( GtkWidget *widget, gpointer data )\r
-{\r
- return FALSE;\r
-}\r
-*/\r
-\r
-static void response_callback( GtkWidget *widget, gint response, gpointer data )\r
-{\r
- if( response == GTK_RESPONSE_CLOSE )\r
- gtk_widget_hide( pDialogWnd );\r
-}\r
-\r
-static gint close_callback( GtkWidget *widget, gpointer data )\r
-{\r
- gtk_widget_hide( pDialogWnd );\r
- return TRUE;\r
-}\r
-\r
-void InitBackgroundDialog()\r
-{\r
- CBackgroundDialogPage *pPage;\r
-\r
- pDialogWnd = gtk_dialog_new_with_buttons ("Background Images",\r
- GTK_WINDOW(g_pMainWidget),\r
- (GtkDialogFlags)(GTK_DIALOG_DESTROY_WITH_PARENT),\r
- // TODO dialog with no buttons\r
- // GTK_STOCK_CLOSE,\r
- // GTK_RESPONSE_CLOSE,\r
- NULL);\r
- gtk_signal_connect( GTK_OBJECT (pDialogWnd), "delete_event",\r
- GTK_SIGNAL_FUNC( close_callback ), NULL );\r
- gtk_signal_connect( GTK_OBJECT (pDialogWnd), "response",\r
- GTK_SIGNAL_FUNC( response_callback ), NULL );\r
-// gtk_signal_connect( GTK_OBJECT (pDialogWnd), "expose_event", GTK_SIGNAL_FUNC( ci_expose ), NULL );\r
-\r
- pTooltips = gtk_tooltips_new();\r
-\r
- pNotebook = gtk_notebook_new();\r
- pPage = new CBackgroundDialogPage(XY);\r
- pPage->Append(pNotebook);\r
- pPage = new CBackgroundDialogPage(XZ);\r
- pPage->Append(pNotebook);\r
- pPage = new CBackgroundDialogPage(YZ);\r
- pPage->Append(pNotebook);\r
-\r
- gtk_box_pack_start (GTK_BOX (GTK_DIALOG(pDialogWnd)->vbox), pNotebook, TRUE, TRUE, 0);\r
-\r
- gtk_widget_show ( pNotebook );\r
- \r
- gtk_widget_realize( pDialogWnd );\r
-}\r
-\r
-void ShowBackgroundDialog()\r
-{\r
- gtk_window_present( GTK_WINDOW(pDialogWnd) );\r
-}\r
-\r
-void ShowBackgroundDialogPG(int page)\r
-{\r
- gtk_notebook_set_current_page(GTK_NOTEBOOK(pNotebook),page);\r
- ShowBackgroundDialog();\r
-}\r
-\r
+/*
+Copyright (C) 1999-2007 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
+*/
+
+//
+// bkgrnd2d Plugin dialog
+//
+// Code by reyalP aka Reed Mideke
+//
+// Based on various other plugins
+//
+
+#include <gtk/gtk.h>
+
+#include "bkgrnd2d.h"
+#include "dialog.h"
+
+// spaces to make label nice and big
+#define NO_FILE_MSG " (no file loaded) "
+
+static GtkWidget *pDialogWnd;
+static GtkWidget *pNotebook;
+static GtkTooltips *pTooltips;
+
+class CBackgroundDialogPage
+{
+private:
+ GtkWidget *m_pWidget;
+ GtkWidget *m_pTabLabel;
+ GtkWidget *m_pFileLabel;
+ GtkWidget *m_pPosLabel;
+ VIEWTYPE m_vt;
+ bool m_bValidFile;
+
+public:
+ CBackgroundImage *m_pImage;
+ CBackgroundDialogPage( VIEWTYPE vt );
+ void Append(GtkWidget *notebook);
+ void Browse();
+ void Reload();
+ void SetPosLabel();
+// ~BackgroundDialogPage();
+};
+
+
+// dialog page callbacks
+static void browse_callback( GtkWidget *widget, gpointer data )
+{
+ ((CBackgroundDialogPage *)data)->Browse();
+}
+
+static void reload_callback( GtkWidget *widget, gpointer data )
+{
+ ((CBackgroundDialogPage *)data)->Reload();
+}
+
+static void size_sel_callback( GtkWidget *widget, gpointer data )
+{
+ CBackgroundDialogPage *pPage = (CBackgroundDialogPage *)data;
+ if (pPage->m_pImage->SetExtentsSel())
+ pPage->SetPosLabel();
+}
+
+static void size_mm_callback( GtkWidget *widget, gpointer data )
+{
+ CBackgroundDialogPage *pPage = (CBackgroundDialogPage *)data;
+ if(pPage->m_pImage->SetExtentsMM())
+ pPage->SetPosLabel();
+}
+
+static void alpha_adjust_callback( GtkWidget *widget, gpointer data )
+{
+ CBackgroundDialogPage *pPage = (CBackgroundDialogPage *)data;
+ pPage->m_pImage->m_alpha = (float)gtk_range_get_value (GTK_RANGE(widget));
+ g_FuncTable.m_pfnSysUpdateWindows(W_XY);
+}
+
+void CBackgroundDialogPage::Reload()
+{
+ if(m_bValidFile)
+ m_pImage->Load(gtk_label_get_text(GTK_LABEL(m_pFileLabel)));
+}
+
+void CBackgroundDialogPage::Browse()
+{
+ char browsedir[PATH_MAX];
+ const char *ct;
+ const char *newfile;
+ char *t;
+
+ //TODO GetMapName saves the map. eeep!
+ //also with no map, returns unnamed.map, otherwise returns full path
+// Syn_Printf(MSG_PREFIX "GetMapName() %s\n",
+// g_FuncTable.m_pfnGetMapName());
+
+ ct = g_FuncTable.m_pfnReadProjectKey("basepath");
+ // TODO shouldn't need this stuff
+ if(!ct || !strlen(ct)) {
+ Syn_Printf(MSG_PREFIX "basepath = NULL or empty\n");
+ return;
+ }
+ Syn_Printf(MSG_PREFIX "basepath: %s\n",ct);
+ if(strlen(ct) >= PATH_MAX) {
+ Syn_Printf(MSG_PREFIX "base game dir too long\n");
+ return;
+ }
+
+ strcpy(browsedir,ct);
+ // make sure we have a trailing /
+ if(browsedir[strlen(browsedir) - 1] != '/')
+ strcat(browsedir,"/");
+
+ //if we dont have a file yet, don't try to use it for default dir
+ if(m_bValidFile) {
+ // filename should always be a nice clean unix style relative path
+ ct = gtk_label_get_text(GTK_LABEL(m_pFileLabel));
+ strcat(browsedir,ct);
+ Syn_Printf(MSG_PREFIX "full path: %s\n",browsedir);
+
+ // lop off the file part
+ t = browsedir + strlen(browsedir) - 1;
+ while (t != browsedir && *t != '/')
+ t--;
+ *t = 0;
+ }
+ Syn_Printf(MSG_PREFIX "browse directory %s\n",browsedir);
+
+//does NOT need freeing contrary to include/qerplugin.h comments
+//TODO bug/patch for comments
+//TODO patern gets fucked up sometimes if empty
+//http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=915
+ newfile = g_FuncTable.m_pfnFileDialog(pDialogWnd,TRUE,
+ "Load Background Image",browsedir,FILETYPE_KEY);
+ if(!newfile) {
+ Syn_Printf(MSG_PREFIX "newfile = NULL\n");
+ return;
+ }
+ Syn_Printf(MSG_PREFIX "newfile: %s\n",newfile);
+ newfile = g_FileSystemTable.m_pfnExtractRelativePath(newfile);
+
+ if(!newfile) {
+ Syn_Printf(MSG_PREFIX "newfile = NULL\n");
+ return;
+ }
+ Syn_Printf(MSG_PREFIX "newfile: %s\n",newfile);
+
+ if(m_pImage->Load(newfile)) {
+ m_bValidFile = true;
+ gtk_label_set_text(GTK_LABEL(m_pFileLabel),newfile);
+ }
+}
+
+void CBackgroundDialogPage::SetPosLabel()
+{
+ char s[64];
+ // TODO no snprintf ?
+ sprintf(s, "Size/Position (%d,%d) (%d,%d)",(int)(m_pImage->m_xmin),
+ (int)(m_pImage->m_ymin),(int)(m_pImage->m_xmax),(int)(m_pImage->m_ymax));
+ gtk_label_set_text(GTK_LABEL(m_pPosLabel),s);
+}
+
+CBackgroundDialogPage::CBackgroundDialogPage(VIEWTYPE vt )
+{
+ GtkWidget *frame;
+ GtkWidget *hbox;
+ GtkWidget *w;
+
+ m_vt = vt;
+
+ m_bValidFile = false;
+
+ switch(m_vt)
+ {
+ case XY:
+ m_pTabLabel = gtk_label_new("X/Y");
+ m_pImage = &backgroundXY;
+ break;
+ case XZ:
+ m_pTabLabel = gtk_label_new("X/Z");
+ m_pImage = &backgroundXZ;
+ break;
+ case YZ:
+ m_pTabLabel = gtk_label_new("Y/Z");
+ m_pImage = &backgroundYZ;
+ break;
+ }
+// A vbox to hold everything
+ m_pWidget = gtk_vbox_new(FALSE,0);
+// Frame for file row
+ frame = gtk_frame_new("File");
+ gtk_box_pack_start (GTK_BOX (m_pWidget),frame, FALSE, FALSE, 2);
+
+// hbox for first row
+ hbox = gtk_hbox_new(FALSE,5);
+ gtk_container_set_border_width(GTK_CONTAINER (hbox),4);
+ gtk_container_add (GTK_CONTAINER (frame), hbox);
+
+// label to display filename
+ m_pFileLabel = gtk_label_new(NO_FILE_MSG);
+ gtk_label_set_selectable(GTK_LABEL(m_pFileLabel),TRUE);
+//TODO set min size ? done with spaces right now
+ gtk_box_pack_start (GTK_BOX (hbox),m_pFileLabel, TRUE, TRUE, 5);
+
+ gtk_widget_show (m_pFileLabel);
+
+ w = gtk_button_new_with_label ("Browse...");
+ g_signal_connect (G_OBJECT (w), "clicked", G_CALLBACK (browse_callback),
+ (gpointer)this);
+ gtk_box_pack_start (GTK_BOX (hbox),w, FALSE, FALSE, 5);
+ gtk_tooltips_set_tip (pTooltips, w, "Select a file", NULL);
+ gtk_widget_show (w);
+
+ w = gtk_button_new_with_label ("Reload");
+ g_signal_connect (G_OBJECT (w), "clicked", G_CALLBACK (reload_callback),
+ (gpointer)this);
+ // TODO disable until we have file
+ // gtk_widget_set_sensitive(w,FALSE);
+ gtk_tooltips_set_tip (pTooltips, w, "Reload current file", NULL);
+ gtk_box_pack_start (GTK_BOX (hbox),w, FALSE, FALSE, 5);
+ gtk_widget_show (w);
+
+ gtk_widget_show (hbox);
+ gtk_widget_show (frame);
+
+// second row (rendering options)
+ frame = gtk_frame_new("Rendering");
+ gtk_box_pack_start (GTK_BOX (m_pWidget),frame, FALSE, FALSE, 2);
+
+ hbox = gtk_hbox_new(FALSE,5);
+ gtk_container_set_border_width(GTK_CONTAINER (hbox),4);
+ gtk_container_add (GTK_CONTAINER (frame), hbox);
+
+ w = gtk_label_new("Vertex alpha:");
+ gtk_box_pack_start (GTK_BOX (hbox),w, FALSE, FALSE, 5);
+ gtk_widget_show (w);
+
+ w = gtk_hscale_new_with_range(0.0,1.0,0.01);
+ gtk_range_set_value(GTK_RANGE(w),0.5);
+ gtk_scale_set_value_pos(GTK_SCALE(w),GTK_POS_LEFT);
+ g_signal_connect (G_OBJECT (w), "value-changed",
+ G_CALLBACK (alpha_adjust_callback), (gpointer)this);
+ gtk_box_pack_start (GTK_BOX (hbox),w, TRUE, TRUE, 5);
+ gtk_tooltips_set_tip (pTooltips, w, "Set image transparancy", NULL);
+ gtk_widget_show (w);
+
+ gtk_widget_show (hbox);
+ gtk_widget_show (frame);
+// Third row (size and position)
+ frame = gtk_frame_new("Size/Position (undefined)");
+ m_pPosLabel = gtk_frame_get_label_widget (GTK_FRAME(frame));
+ gtk_box_pack_start ( GTK_BOX (m_pWidget), frame, FALSE, FALSE, 2);
+
+ hbox = gtk_hbox_new(FALSE,5);
+ gtk_container_add (GTK_CONTAINER (frame), hbox);
+ gtk_container_set_border_width(GTK_CONTAINER (hbox),4);
+
+ w = gtk_button_new_with_label ("from selection");
+ gtk_box_pack_start (GTK_BOX (hbox),w, TRUE, FALSE, 5);
+ g_signal_connect (G_OBJECT (w), "clicked", G_CALLBACK (size_sel_callback),
+ (gpointer)this);
+ gtk_tooltips_set_tip (pTooltips, w, "Set the size of the image to the bounding rectangle of all selected brushes and entities", NULL);
+ gtk_widget_show (w);
+
+ if(m_vt == XY) {
+ w = gtk_button_new_with_label ("from map mins/maxs");
+ gtk_box_pack_start ( GTK_BOX (hbox),w, TRUE, FALSE, 2);
+ g_signal_connect (G_OBJECT (w), "clicked", G_CALLBACK (size_mm_callback),
+ (gpointer)this);
+ gtk_tooltips_set_tip (pTooltips, w, "Set the size of the image using the mapcoordsmins and mapcoordsmaxs keys of the worldspawn entity", NULL);
+ gtk_widget_show (w);
+ }
+
+ gtk_widget_show (hbox);
+ gtk_widget_show (frame);
+
+ gtk_widget_show ( m_pWidget );
+}
+
+void CBackgroundDialogPage::Append(GtkWidget *notebook)
+{
+ gtk_notebook_append_page( GTK_NOTEBOOK(notebook), m_pWidget, m_pTabLabel);
+}
+
+// dialog global callbacks
+/*
+static gint expose_callback( GtkWidget *widget, gpointer data )
+{
+ return FALSE;
+}
+*/
+
+static void response_callback( GtkWidget *widget, gint response, gpointer data )
+{
+ if( response == GTK_RESPONSE_CLOSE )
+ gtk_widget_hide( pDialogWnd );
+}
+
+static gint close_callback( GtkWidget *widget, gpointer data )
+{
+ gtk_widget_hide( pDialogWnd );
+ return TRUE;
+}
+
+void InitBackgroundDialog()
+{
+ CBackgroundDialogPage *pPage;
+
+ pDialogWnd = gtk_dialog_new_with_buttons ("Background Images",
+ GTK_WINDOW(g_pMainWidget),
+ (GtkDialogFlags)(GTK_DIALOG_DESTROY_WITH_PARENT),
+ // TODO dialog with no buttons
+ // GTK_STOCK_CLOSE,
+ // GTK_RESPONSE_CLOSE,
+ NULL);
+ gtk_signal_connect( GTK_OBJECT (pDialogWnd), "delete_event",
+ GTK_SIGNAL_FUNC( close_callback ), NULL );
+ gtk_signal_connect( GTK_OBJECT (pDialogWnd), "response",
+ GTK_SIGNAL_FUNC( response_callback ), NULL );
+// gtk_signal_connect( GTK_OBJECT (pDialogWnd), "expose_event", GTK_SIGNAL_FUNC( ci_expose ), NULL );
+
+ pTooltips = gtk_tooltips_new();
+
+ pNotebook = gtk_notebook_new();
+ pPage = new CBackgroundDialogPage(XY);
+ pPage->Append(pNotebook);
+ pPage = new CBackgroundDialogPage(XZ);
+ pPage->Append(pNotebook);
+ pPage = new CBackgroundDialogPage(YZ);
+ pPage->Append(pNotebook);
+
+ gtk_box_pack_start (GTK_BOX (GTK_DIALOG(pDialogWnd)->vbox), pNotebook, TRUE, TRUE, 0);
+
+ gtk_widget_show ( pNotebook );
+
+ gtk_widget_realize( pDialogWnd );
+}
+
+void ShowBackgroundDialog()
+{
+ gtk_window_present( GTK_WINDOW(pDialogWnd) );
+}
+
+void ShowBackgroundDialogPG(int page)
+{
+ gtk_notebook_set_current_page(GTK_NOTEBOOK(pNotebook),page);
+ ShowBackgroundDialog();
+}
+
-/*\r
-Copyright (C) 1999-2007 id Software, Inc. and contributors.\r
-For a list of contributors, see the accompanying CONTRIBUTORS file.\r
-\r
-This file is part of GtkRadiant.\r
-\r
-GtkRadiant is free software; you can redistribute it and/or modify\r
-it under the terms of the GNU General Public License as published by\r
-the Free Software Foundation; either version 2 of the License, or\r
-(at your option) any later version.\r
-\r
-GtkRadiant is distributed in the hope that it will be useful,\r
-but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
-GNU General Public License for more details.\r
-\r
-You should have received a copy of the GNU General Public License\r
-along with GtkRadiant; if not, write to the Free Software\r
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\r
-*/\r
-\r
-//\r
-// 2d background Plugin\r
-//\r
-// Code by reyalP aka Reed Mideke\r
-//\r
-// Based on \r
-//\r
-\r
-/*\r
- Overview\r
- ========\r
- This little plugin allows you to display an image in the background of the\r
- gtkradiant XY window.\r
-\r
- Version History\r
- ===============\r
-\r
- v0.1\r
- - Initial version.\r
- v0.2\r
- - three views, dialog box, toolbar\r
- v0.25\r
- - tooltips, follow gtkradiant coding conventions\r
-\r
- Why ?\r
- -----\r
- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=88\r
-\r
-\r
- How ?\r
- -----\r
- - textures 'n widgets 'n stuff.\r
-*/\r
-\r
-//#include "plugin.h"\r
-//TODO we just poke the objects directly\r
-#include "bkgrnd2d.h"\r
-#include "dialog.h"\r
-\r
-#define CMD_SEP "-" \r
-#define CMD_CONFIG "Configure..."\r
-#define CMD_ABOUT "About..."\r
-// =============================================================================\r
-// Globals\r
-\r
-// function tables\r
-_QERFuncTable_1 g_FuncTable;\r
-_QERQglTable g_QglTable;\r
-_QERFileSystemTable g_FileSystemTable;\r
-_QEREntityTable g_EntityTable;\r
-_QERAppDataTable g_DataTable;\r
-\r
-// for the file load dialog\r
-void *g_pMainWidget;\r
-\r
-// =============================================================================\r
-// plugin implementation\r
-\r
-static const char *PLUGIN_NAME = "2d window background plugin";\r
-\r
-//backwards for some reason\r
-static const char *PLUGIN_COMMANDS = CMD_ABOUT ";" \r
- CMD_SEP ";"\r
- CMD_CONFIG\r
- ;\r
-\r
-static const char *PLUGIN_ABOUT = "2d window background v0.25\n\n"\r
- "By reyalP (hellsownpuppy@yahoo.com)";\r
-\r
-\r
-\r
-\r
-void DoBkgrndToggleXY();\r
-void DoBkgrndToggleXZ();\r
-void DoBkgrndToggleYZ();\r
-\r
-#define NUM_TOOLBAR_BUTTONS 4\r
-struct toolbar_button_info_s\r
-{\r
- char *image;\r
- char *text;\r
- char *tip;\r
- void (*func)();\r
- IToolbarButton::EType type;\r
-};\r
-\r
-struct toolbar_button_info_s toolbar_buttons[NUM_TOOLBAR_BUTTONS] = \r
-{\r
- {\r
- "bkgrnd2d_xy_toggle.bmp",\r
- "xy background",\r
- "Toggle xy background image",\r
- DoBkgrndToggleXY,\r
- IToolbarButton::eToggleButton\r
- },\r
- {\r
- "bkgrnd2d_xz_toggle.bmp",\r
- "xz background",\r
- "Toggle xz background image",\r
- DoBkgrndToggleXZ,\r
- IToolbarButton::eToggleButton\r
- },\r
- {\r
- "bkgrnd2d_yz_toggle.bmp",\r
- "yz background",\r
- "Toggle yz background image",\r
- DoBkgrndToggleYZ,\r
- IToolbarButton::eToggleButton\r
- },\r
- {\r
- "bkgrnd2d_conf.bmp",\r
- "Configure",\r
- "Configure background images",\r
- ShowBackgroundDialog,\r
- IToolbarButton::eButton\r
- },\r
-};\r
-\r
-class Bkgrnd2dButton : public IToolbarButton\r
-{\r
-public:\r
- const toolbar_button_info_s *bi;\r
- virtual const char* getImage() const\r
- {\r
- return bi->image;\r
- }\r
- virtual const char* getText() const\r
- {\r
- return bi->text;\r
- }\r
- virtual const char* getTooltip() const\r
- {\r
- return bi->tip;\r
- }\r
- virtual void activate() const\r
- {\r
- bi->func();\r
- return ;\r
- }\r
- virtual EType getType() const\r
- {\r
- return bi->type;\r
- }\r
-};\r
-\r
-Bkgrnd2dButton g_bkgrnd2dbuttons[NUM_TOOLBAR_BUTTONS];\r
-\r
-unsigned int ToolbarButtonCount()\r
-{\r
- return NUM_TOOLBAR_BUTTONS;\r
-}\r
-\r
-const IToolbarButton* GetToolbarButton(unsigned int index)\r
-{\r
- g_bkgrnd2dbuttons[index].bi = &toolbar_buttons[index];\r
- return &g_bkgrnd2dbuttons[index];\r
-}\r
-\r
-extern "C" const char* QERPlug_Init (void *hApp, void* pMainWidget)\r
-{\r
- g_pMainWidget = pMainWidget;\r
-\r
- InitBackgroundDialog();\r
- render.Register();\r
-\r
-//TODO is it right ? is it wrong ? it works\r
-//TODO figure out supported image types\r
- GetFileTypeRegistry()->addType(FILETYPE_KEY, filetype_t("all files", "*.*"));\r
- GetFileTypeRegistry()->addType(FILETYPE_KEY, filetype_t("jpeg files", "*.jpg"));\r
- GetFileTypeRegistry()->addType(FILETYPE_KEY, filetype_t("targa files", "*.tga"));\r
- return (char *) PLUGIN_NAME;\r
-}\r
-\r
-extern "C" const char* QERPlug_GetName ()\r
-{\r
- return (char *) PLUGIN_NAME;\r
-}\r
-\r
-extern "C" const char* QERPlug_GetCommandList ()\r
-{\r
- return (char *) PLUGIN_COMMANDS;\r
-}\r
-\r
-extern "C" void QERPlug_Dispatch (const char *p, vec3_t vMin, vec3_t vMax, bool bSingleBrush)\r
-{\r
- Sys_Printf (MSG_PREFIX "Command \"%s\"\n",p); \r
- if(!strcmp(p, CMD_ABOUT)) {\r
- g_FuncTable.m_pfnMessageBox(NULL, PLUGIN_ABOUT, "About", MB_OK, NULL);\r
- } \r
- else if(!strcmp(p,CMD_CONFIG)) {\r
- ShowBackgroundDialog();\r
- }\r
-}\r
-\r
-//TODO these three suck\r
-void DoBkgrndToggleXY()\r
-{\r
- Sys_Printf (MSG_PREFIX "DoBkgrndToggleXY\n"); \r
- // always toggle, since the buttons do\r
- backgroundXY.m_bActive = (backgroundXY.m_bActive) ? false:true;\r
- // if we don't have image or extents, and we activated,\r
- // bring up the dialog with the corresponding page\r
- // would be better to hide or grey out button, but we can't\r
- if(backgroundXY.m_bActive && !backgroundXY.Valid())\r
- ShowBackgroundDialogPG(0);\r
- else\r
- g_FuncTable.m_pfnSysUpdateWindows(W_XY);\r
-}\r
-\r
-void DoBkgrndToggleXZ()\r
-{\r
- Sys_Printf (MSG_PREFIX "DoBkgrndToggleXZ\n"); \r
- backgroundXZ.m_bActive = (backgroundXZ.m_bActive) ? false:true;\r
- if(backgroundXZ.m_bActive && !backgroundXZ.Valid())\r
- ShowBackgroundDialogPG(1);\r
- else\r
- g_FuncTable.m_pfnSysUpdateWindows(W_XY);\r
-}\r
-\r
-void DoBkgrndToggleYZ()\r
-{\r
- Sys_Printf (MSG_PREFIX "DoBkgrndToggleYZ\n"); \r
- backgroundYZ.m_bActive = (backgroundYZ.m_bActive) ? false:true;\r
- if(backgroundYZ.m_bActive && !backgroundYZ.Valid())\r
- ShowBackgroundDialogPG(2);\r
- else\r
- g_FuncTable.m_pfnSysUpdateWindows(W_XY);\r
-}\r
-\r
-// =============================================================================\r
-// SYNAPSE\r
-\r
-CSynapseServer* g_pSynapseServer = NULL;\r
-CSynapseClientBkgrnd2d g_SynapseClient;\r
- \r
-#if __GNUC__ >= 4\r
-#pragma GCC visibility push(default)\r
-#endif\r
-extern "C" CSynapseClient* SYNAPSE_DLL_EXPORT Synapse_EnumerateInterfaces( const char *version, CSynapseServer *pServer ) {\r
-#if __GNUC__ >= 4\r
-#pragma GCC visibility pop\r
-#endif\r
- if (strcmp(version, SYNAPSE_VERSION))\r
- {\r
- Syn_Printf("ERROR: synapse API version mismatch: should be '" SYNAPSE_VERSION "', got '%s'\n", version);\r
- return NULL;\r
- }\r
- g_pSynapseServer = pServer;\r
- g_pSynapseServer->IncRef();\r
- Set_Syn_Printf(g_pSynapseServer->Get_Syn_Printf());\r
-\r
- g_SynapseClient.AddAPI(TOOLBAR_MAJOR, BKGRND2D_MINOR, sizeof(_QERPlugToolbarTable));\r
- g_SynapseClient.AddAPI(PLUGIN_MAJOR, BKGRND2D_MINOR, sizeof( _QERPluginTable ) );\r
-\r
- g_SynapseClient.AddAPI( RADIANT_MAJOR, NULL, sizeof( g_FuncTable ), SYN_REQUIRE, &g_FuncTable );\r
- g_SynapseClient.AddAPI( QGL_MAJOR, NULL, sizeof( g_QglTable ), SYN_REQUIRE, &g_QglTable );\r
-// TODO is this the right way to ask for 'whichever VFS we have loaded' ? Seems to work\r
-// for misc filename functions\r
- g_SynapseClient.AddAPI( VFS_MAJOR, "*", sizeof( g_FileSystemTable ), SYN_REQUIRE, &g_FileSystemTable );\r
-// get worldspawn\r
- g_SynapseClient.AddAPI( ENTITY_MAJOR, NULL, sizeof( g_EntityTable ), SYN_REQUIRE, &g_EntityTable );\r
-// selected brushes\r
- g_SynapseClient.AddAPI( DATA_MAJOR, NULL, sizeof( g_DataTable ), SYN_REQUIRE, &g_DataTable );\r
-\r
- return &g_SynapseClient;\r
-}\r
-\r
-bool CSynapseClientBkgrnd2d::RequestAPI(APIDescriptor_t *pAPI)\r
-{\r
- if (!strcmp(pAPI->major_name, PLUGIN_MAJOR))\r
- {\r
- _QERPluginTable* pTable= static_cast<_QERPluginTable*>(pAPI->mpTable);\r
-\r
- pTable->m_pfnQERPlug_Init = QERPlug_Init;\r
- pTable->m_pfnQERPlug_GetName = QERPlug_GetName;\r
- pTable->m_pfnQERPlug_GetCommandList = QERPlug_GetCommandList;\r
- pTable->m_pfnQERPlug_Dispatch = QERPlug_Dispatch;\r
- return true;\r
- }\r
- if (!strcmp(pAPI->major_name, TOOLBAR_MAJOR))\r
- {\r
- _QERPlugToolbarTable* pTable= static_cast<_QERPlugToolbarTable*>(pAPI->mpTable);\r
-\r
- pTable->m_pfnToolbarButtonCount = &ToolbarButtonCount;\r
- pTable->m_pfnGetToolbarButton = &GetToolbarButton;\r
- return true;\r
- }\r
-\r
- Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo());\r
- return false;\r
-}\r
-\r
-#include "version.h"\r
-\r
-const char* CSynapseClientBkgrnd2d::GetInfo()\r
-{\r
- return "2d Background plugin built " __DATE__ " " RADIANT_VERSION;\r
-}\r
-\r
-const char* CSynapseClientBkgrnd2d::GetName()\r
-{\r
- return "bkgrnd2d";\r
-}\r
-\r
+/*
+Copyright (C) 1999-2007 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
+*/
+
+//
+// 2d background Plugin
+//
+// Code by reyalP aka Reed Mideke
+//
+// Based on
+//
+
+/*
+ Overview
+ ========
+ This little plugin allows you to display an image in the background of the
+ gtkradiant XY window.
+
+ Version History
+ ===============
+
+ v0.1
+ - Initial version.
+ v0.2
+ - three views, dialog box, toolbar
+ v0.25
+ - tooltips, follow gtkradiant coding conventions
+
+ Why ?
+ -----
+ http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=88
+
+
+ How ?
+ -----
+ - textures 'n widgets 'n stuff.
+*/
+
+//#include "plugin.h"
+//TODO we just poke the objects directly
+#include "bkgrnd2d.h"
+#include "dialog.h"
+
+#define CMD_SEP "-"
+#define CMD_CONFIG "Configure..."
+#define CMD_ABOUT "About..."
+// =============================================================================
+// Globals
+
+// function tables
+_QERFuncTable_1 g_FuncTable;
+_QERQglTable g_QglTable;
+_QERFileSystemTable g_FileSystemTable;
+_QEREntityTable g_EntityTable;
+_QERAppDataTable g_DataTable;
+
+// for the file load dialog
+void *g_pMainWidget;
+
+// =============================================================================
+// plugin implementation
+
+static const char *PLUGIN_NAME = "2d window background plugin";
+
+//backwards for some reason
+static const char *PLUGIN_COMMANDS = CMD_ABOUT ";"
+ CMD_SEP ";"
+ CMD_CONFIG
+ ;
+
+static const char *PLUGIN_ABOUT = "2d window background v0.25\n\n"
+ "By reyalP (hellsownpuppy@yahoo.com)";
+
+
+
+
+void DoBkgrndToggleXY();
+void DoBkgrndToggleXZ();
+void DoBkgrndToggleYZ();
+
+#define NUM_TOOLBAR_BUTTONS 4
+struct toolbar_button_info_s
+{
+ char *image;
+ char *text;
+ char *tip;
+ void (*func)();
+ IToolbarButton::EType type;
+};
+
+struct toolbar_button_info_s toolbar_buttons[NUM_TOOLBAR_BUTTONS] =
+{
+ {
+ "bkgrnd2d_xy_toggle.bmp",
+ "xy background",
+ "Toggle xy background image",
+ DoBkgrndToggleXY,
+ IToolbarButton::eToggleButton
+ },
+ {
+ "bkgrnd2d_xz_toggle.bmp",
+ "xz background",
+ "Toggle xz background image",
+ DoBkgrndToggleXZ,
+ IToolbarButton::eToggleButton
+ },
+ {
+ "bkgrnd2d_yz_toggle.bmp",
+ "yz background",
+ "Toggle yz background image",
+ DoBkgrndToggleYZ,
+ IToolbarButton::eToggleButton
+ },
+ {
+ "bkgrnd2d_conf.bmp",
+ "Configure",
+ "Configure background images",
+ ShowBackgroundDialog,
+ IToolbarButton::eButton
+ },
+};
+
+class Bkgrnd2dButton : public IToolbarButton
+{
+public:
+ const toolbar_button_info_s *bi;
+ virtual const char* getImage() const
+ {
+ return bi->image;
+ }
+ virtual const char* getText() const
+ {
+ return bi->text;
+ }
+ virtual const char* getTooltip() const
+ {
+ return bi->tip;
+ }
+ virtual void activate() const
+ {
+ bi->func();
+ return ;
+ }
+ virtual EType getType() const
+ {
+ return bi->type;
+ }
+};
+
+Bkgrnd2dButton g_bkgrnd2dbuttons[NUM_TOOLBAR_BUTTONS];
+
+unsigned int ToolbarButtonCount()
+{
+ return NUM_TOOLBAR_BUTTONS;
+}
+
+const IToolbarButton* GetToolbarButton(unsigned int index)
+{
+ g_bkgrnd2dbuttons[index].bi = &toolbar_buttons[index];
+ return &g_bkgrnd2dbuttons[index];
+}
+
+extern "C" const char* QERPlug_Init (void *hApp, void* pMainWidget)
+{
+ g_pMainWidget = pMainWidget;
+
+ InitBackgroundDialog();
+ render.Register();
+
+//TODO is it right ? is it wrong ? it works
+//TODO figure out supported image types
+ GetFileTypeRegistry()->addType(FILETYPE_KEY, filetype_t("all files", "*.*"));
+ GetFileTypeRegistry()->addType(FILETYPE_KEY, filetype_t("jpeg files", "*.jpg"));
+ GetFileTypeRegistry()->addType(FILETYPE_KEY, filetype_t("targa files", "*.tga"));
+ return (char *) PLUGIN_NAME;
+}
+
+extern "C" const char* QERPlug_GetName ()
+{
+ return (char *) PLUGIN_NAME;
+}
+
+extern "C" const char* QERPlug_GetCommandList ()
+{
+ return (char *) PLUGIN_COMMANDS;
+}
+
+extern "C" void QERPlug_Dispatch (const char *p, vec3_t vMin, vec3_t vMax, bool bSingleBrush)
+{
+ Sys_Printf (MSG_PREFIX "Command \"%s\"\n",p);
+ if(!strcmp(p, CMD_ABOUT)) {
+ g_FuncTable.m_pfnMessageBox(NULL, PLUGIN_ABOUT, "About", MB_OK, NULL);
+ }
+ else if(!strcmp(p,CMD_CONFIG)) {
+ ShowBackgroundDialog();
+ }
+}
+
+//TODO these three suck
+void DoBkgrndToggleXY()
+{
+ Sys_Printf (MSG_PREFIX "DoBkgrndToggleXY\n");
+ // always toggle, since the buttons do
+ backgroundXY.m_bActive = (backgroundXY.m_bActive) ? false:true;
+ // if we don't have image or extents, and we activated,
+ // bring up the dialog with the corresponding page
+ // would be better to hide or grey out button, but we can't
+ if(backgroundXY.m_bActive && !backgroundXY.Valid())
+ ShowBackgroundDialogPG(0);
+ else
+ g_FuncTable.m_pfnSysUpdateWindows(W_XY);
+}
+
+void DoBkgrndToggleXZ()
+{
+ Sys_Printf (MSG_PREFIX "DoBkgrndToggleXZ\n");
+ backgroundXZ.m_bActive = (backgroundXZ.m_bActive) ? false:true;
+ if(backgroundXZ.m_bActive && !backgroundXZ.Valid())
+ ShowBackgroundDialogPG(1);
+ else
+ g_FuncTable.m_pfnSysUpdateWindows(W_XY);
+}
+
+void DoBkgrndToggleYZ()
+{
+ Sys_Printf (MSG_PREFIX "DoBkgrndToggleYZ\n");
+ backgroundYZ.m_bActive = (backgroundYZ.m_bActive) ? false:true;
+ if(backgroundYZ.m_bActive && !backgroundYZ.Valid())
+ ShowBackgroundDialogPG(2);
+ else
+ g_FuncTable.m_pfnSysUpdateWindows(W_XY);
+}
+
+// =============================================================================
+// SYNAPSE
+
+CSynapseServer* g_pSynapseServer = NULL;
+CSynapseClientBkgrnd2d g_SynapseClient;
+
+#if __GNUC__ >= 4
+#pragma GCC visibility push(default)
+#endif
+extern "C" CSynapseClient* SYNAPSE_DLL_EXPORT Synapse_EnumerateInterfaces( const char *version, CSynapseServer *pServer ) {
+#if __GNUC__ >= 4
+#pragma GCC visibility pop
+#endif
+ if (strcmp(version, SYNAPSE_VERSION))
+ {
+ Syn_Printf("ERROR: synapse API version mismatch: should be '" SYNAPSE_VERSION "', got '%s'\n", version);
+ return NULL;
+ }
+ g_pSynapseServer = pServer;
+ g_pSynapseServer->IncRef();
+ Set_Syn_Printf(g_pSynapseServer->Get_Syn_Printf());
+
+ g_SynapseClient.AddAPI(TOOLBAR_MAJOR, BKGRND2D_MINOR, sizeof(_QERPlugToolbarTable));
+ g_SynapseClient.AddAPI(PLUGIN_MAJOR, BKGRND2D_MINOR, sizeof( _QERPluginTable ) );
+
+ g_SynapseClient.AddAPI( RADIANT_MAJOR, NULL, sizeof( g_FuncTable ), SYN_REQUIRE, &g_FuncTable );
+ g_SynapseClient.AddAPI( QGL_MAJOR, NULL, sizeof( g_QglTable ), SYN_REQUIRE, &g_QglTable );
+// TODO is this the right way to ask for 'whichever VFS we have loaded' ? Seems to work
+// for misc filename functions
+ g_SynapseClient.AddAPI( VFS_MAJOR, "*", sizeof( g_FileSystemTable ), SYN_REQUIRE, &g_FileSystemTable );
+// get worldspawn
+ g_SynapseClient.AddAPI( ENTITY_MAJOR, NULL, sizeof( g_EntityTable ), SYN_REQUIRE, &g_EntityTable );
+// selected brushes
+ g_SynapseClient.AddAPI( DATA_MAJOR, NULL, sizeof( g_DataTable ), SYN_REQUIRE, &g_DataTable );
+
+ return &g_SynapseClient;
+}
+
+bool CSynapseClientBkgrnd2d::RequestAPI(APIDescriptor_t *pAPI)
+{
+ if (!strcmp(pAPI->major_name, PLUGIN_MAJOR))
+ {
+ _QERPluginTable* pTable= static_cast<_QERPluginTable*>(pAPI->mpTable);
+
+ pTable->m_pfnQERPlug_Init = QERPlug_Init;
+ pTable->m_pfnQERPlug_GetName = QERPlug_GetName;
+ pTable->m_pfnQERPlug_GetCommandList = QERPlug_GetCommandList;
+ pTable->m_pfnQERPlug_Dispatch = QERPlug_Dispatch;
+ return true;
+ }
+ if (!strcmp(pAPI->major_name, TOOLBAR_MAJOR))
+ {
+ _QERPlugToolbarTable* pTable= static_cast<_QERPlugToolbarTable*>(pAPI->mpTable);
+
+ pTable->m_pfnToolbarButtonCount = &ToolbarButtonCount;
+ pTable->m_pfnGetToolbarButton = &GetToolbarButton;
+ return true;
+ }
+
+ Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo());
+ return false;
+}
+
+#include "version.h"
+
+const char* CSynapseClientBkgrnd2d::GetInfo()
+{
+ return "2d Background plugin built " __DATE__ " " RADIANT_VERSION;
+}
+
+const char* CSynapseClientBkgrnd2d::GetName()
+{
+ return "bkgrnd2d";
+}
+
-/*\r
-BobToolz plugin for GtkRadiant\r
-Copyright (C) 2001 Gordon Biggans\r
-\r
-This library is free software; you can redistribute it and/or\r
-modify it under the terms of the GNU Lesser General Public\r
-License as published by the Free Software Foundation; either\r
-version 2.1 of the License, or (at your option) any later version.\r
-\r
-This library is distributed in the hope that it will be useful,\r
-but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
-Lesser General Public License for more details.\r
-\r
-You should have received a copy of the GNU Lesser General Public\r
-License along with this library; if not, write to the Free Software\r
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
-*/\r
-\r
-// BobView.cpp: implementation of the DBobView class.\r
-//\r
-//////////////////////////////////////////////////////////////////////\r
-\r
-#include "StdAfx.h"\r
-#include "DBobView.h"\r
-#include "DListener.h"\r
-#include "misc.h"\r
-#include "funchandlers.h"\r
-\r
-//////////////////////////////////////////////////////////////////////\r
-// Construction/Destruction\r
-//////////////////////////////////////////////////////////////////////\r
-\r
-DBobView::DBobView()\r
-{\r
- nPathCount = 0;\r
- refCount = 1;\r
- \r
- m_bHooked = FALSE;\r
-\r
- path = NULL;\r
- eyes = NULL;\r
-\r
- boundingShow = BOUNDS_APEX;\r
-}\r
-\r
-DBobView::~DBobView()\r
-{\r
- if(path)\r
- delete[] path;\r
-\r
- // oops forgot to remove our eyes, was causing access violation when it tried\r
- // to talk to it's parent\r
- if(eyes)\r
- delete eyes;\r
-\r
- if(m_bHooked)\r
- UnRegister();\r
-\r
- g_PathView = NULL;\r
-}\r
-\r
-//////////////////////////////////////////////////////////////////////\r
-// Implementation\r
-//////////////////////////////////////////////////////////////////////\r
-\r
-void DBobView::Draw2D(VIEWTYPE vt)\r
-{\r
- if(!path)\r
- return;\r
-\r
- g_QglTable.m_pfn_qglPushAttrib(GL_ALL_ATTRIB_BITS);\r
-\r
- g_QglTable.m_pfn_qglDisable(GL_BLEND);\r
- g_QglTable.m_pfn_qglEnable(GL_LINE_SMOOTH);\r
-\r
- g_QglTable.m_pfn_qglPushMatrix();\r
- \r
- switch(vt)\r
- {\r
- case XY:\r
- break;\r
- case XZ:\r
- g_QglTable.m_pfn_qglRotatef(270.0f, 1.0f, 0.0f, 0.0f);\r
- break;\r
- case YZ:\r
- g_QglTable.m_pfn_qglRotatef(270.0f, 1.0f, 0.0f, 0.0f);\r
- g_QglTable.m_pfn_qglRotatef(270.0f, 0.0f, 0.0f, 1.0f);\r
- break;\r
- }\r
-\r
- g_QglTable.m_pfn_qglLineWidth(1.0f);\r
- g_QglTable.m_pfn_qglColor4f(1.0f, 0.0f, 0.0f, 1.0f);\r
-\r
- int i;\r
-\r
- g_QglTable.m_pfn_qglBegin(GL_LINE_STRIP);\r
-\r
- for(i = 0; i < nPathCount; i++)\r
- g_QglTable.m_pfn_qglVertex3fv(path[i]);\r
-\r
- g_QglTable.m_pfn_qglEnd();\r
-\r
- if(m_bShowExtra)\r
- {\r
- // +mars\r
- // for the bounding box stuff\r
- g_QglTable.m_pfn_qglColor4f(0.25f, 0.75f, 0.75f, 1.0f);\r
-\r
- g_QglTable.m_pfn_qglTranslatef( 16.0f, 16.0f, 28.0f );\r
-\r
- g_QglTable.m_pfn_qglBegin( GL_LINE_STRIP );\r
- \r
- for ( i = 0; i < nPathCount; i++ )\r
- g_QglTable.m_pfn_qglVertex3fv( path[i] );\r
-\r
- g_QglTable.m_pfn_qglEnd();\r
- \r
- // ---------------\r
-\r
- g_QglTable.m_pfn_qglTranslatef( -16.0f, -16.0f, -28.0f ); // back to where we were\r
- g_QglTable.m_pfn_qglTranslatef( -16.0f, 16.0f, 28.0f ); // move to new postion\r
- \r
- g_QglTable.m_pfn_qglBegin( GL_LINE_STRIP );\r
-\r
- for ( i = 0; i < nPathCount; i++ )\r
- g_QglTable.m_pfn_qglVertex3fv( path[i] );\r
-\r
- g_QglTable.m_pfn_qglEnd();\r
-\r
- // --------------\r
-\r
- g_QglTable.m_pfn_qglTranslatef( 16.0f, -16.0f, -28.0f ); // back to where we were\r
- g_QglTable.m_pfn_qglTranslatef( 16.0f, -16.0f, -28.0f ); // new pos\r
-\r
- g_QglTable.m_pfn_qglBegin( GL_LINE_STRIP );\r
- \r
- for ( i = 0; i < nPathCount; i++ )\r
- g_QglTable.m_pfn_qglVertex3fv( path[i] );\r
-\r
- g_QglTable.m_pfn_qglEnd();\r
-\r
- // ----------------\r
-\r
- g_QglTable.m_pfn_qglTranslatef( -16.0f, 16.0f, 28.0f ); // back to where we were\r
-\r
-/* g_QglTable.m_pfn_qglTranslatef( -16.0f, -16.0f, -28.0f ); // new pos\r
-\r
- g_QglTable.m_pfn_qglBegin( GL_LINE_STRIP );\r
- \r
- if ( boundingShow == BOUNDS_ALL )\r
- {\r
- for ( i = 0; i < nPathCount; i++ )\r
- g_QglTable.m_pfn_qglVertex3fv( path[i] );\r
- }\r
- else if ( boundingShow == BOUNDS_APEX )\r
- {\r
- for ( i = (nPathCount/4); i < (nPathCount/4) * 3; i++ )\r
- g_QglTable.m_pfn_qglVertex3fv( path[i] );\r
- }\r
-\r
- g_QglTable.m_pfn_qglEnd();*/ // djbob: er, um doesn't really seem to do anyhting\r
- }\r
-\r
- // -mars\r
- \r
- g_QglTable.m_pfn_qglPopMatrix();\r
-\r
- g_QglTable.m_pfn_qglPopAttrib();\r
-}\r
-\r
-void DBobView::Draw3D()\r
-{\r
- if(!path)\r
- return;\r
-\r
- g_QglTable.m_pfn_qglPushAttrib(GL_ALL_ATTRIB_BITS);\r
-\r
- g_QglTable.m_pfn_qglDisable(GL_BLEND);\r
- g_QglTable.m_pfn_qglEnable(GL_LINE_SMOOTH);\r
-\r
- g_QglTable.m_pfn_qglLineWidth(1.0f);\r
- g_QglTable.m_pfn_qglColor4f(1.0f, 0.0f, 0.0f, 1.0f);\r
-\r
- g_QglTable.m_pfn_qglBegin(GL_LINE_STRIP);\r
-\r
- for(int i = 0; i < nPathCount; i++)\r
- g_QglTable.m_pfn_qglVertex3fv(path[i]);\r
-\r
- g_QglTable.m_pfn_qglEnd();\r
-\r
- if(m_bShowExtra)\r
- {\r
- // +mars\r
- // ahhh -- a nice C&P job :)\r
- // for the bounding box stuff\r
- g_QglTable.m_pfn_qglColor4f(0.25f, 0.75f, 0.75f, 1.0f);\r
-\r
- g_QglTable.m_pfn_qglTranslatef( 16.0f, 16.0f, 28.0f );\r
-\r
- g_QglTable.m_pfn_qglBegin( GL_LINE_STRIP );\r
- \r
- int i; \r
- for ( i = 0; i < nPathCount; i++ )\r
- g_QglTable.m_pfn_qglVertex3fv( path[i] );\r
-\r
- g_QglTable.m_pfn_qglEnd();\r
- \r
- // ---------------\r
-\r
- g_QglTable.m_pfn_qglTranslatef( -16.0f, -16.0f, -28.0f ); // back to where we were\r
- g_QglTable.m_pfn_qglTranslatef( -16.0f, 16.0f, 28.0f ); // move to new postion\r
- \r
- g_QglTable.m_pfn_qglBegin( GL_LINE_STRIP );\r
- \r
- for ( i = 0; i < nPathCount; i++ )\r
- g_QglTable.m_pfn_qglVertex3fv( path[i] );\r
-\r
- g_QglTable.m_pfn_qglEnd();\r
-\r
- // --------------\r
-\r
- g_QglTable.m_pfn_qglTranslatef( 16.0f, -16.0f, -28.0f ); // back to where we were\r
- g_QglTable.m_pfn_qglTranslatef( 16.0f, -16.0f, -28.0f ); // new pos\r
-\r
- g_QglTable.m_pfn_qglBegin( GL_LINE_STRIP );\r
- \r
- for ( i = 0; i < nPathCount; i++ )\r
- g_QglTable.m_pfn_qglVertex3fv( path[i] );\r
-\r
- g_QglTable.m_pfn_qglEnd();\r
-\r
- // ----------------\r
-\r
- g_QglTable.m_pfn_qglTranslatef( -16.0f, 16.0f, 28.0f ); // back to where we were\r
- g_QglTable.m_pfn_qglTranslatef( -16.0f, -16.0f, -28.0f ); // new pos\r
-\r
- g_QglTable.m_pfn_qglBegin( GL_LINE_STRIP );\r
- \r
- for ( i = 0; i < nPathCount; i++ )\r
- g_QglTable.m_pfn_qglVertex3fv( path[i] );\r
-\r
- g_QglTable.m_pfn_qglEnd();\r
- }\r
- // -mars\r
-\r
- g_QglTable.m_pfn_qglPopAttrib();\r
-}\r
-\r
-void DBobView::Register()\r
-{\r
- g_QglTable.m_pfnHookGL2DWindow( this );\r
- g_QglTable.m_pfnHookGL3DWindow( this );\r
- m_bHooked = TRUE;\r
-}\r
-\r
-void DBobView::UnRegister()\r
-{\r
- g_QglTable.m_pfnUnHookGL2DWindow( this );\r
- g_QglTable.m_pfnUnHookGL3DWindow( this );\r
- m_bHooked = FALSE;\r
-}\r
-\r
-void DBobView::SetPath(vec3_t *pPath)\r
-{\r
- if(path)\r
- delete[] path;\r
-\r
- path = pPath;\r
-}\r
-\r
-#define LOCAL_GRAVITY -800.0f\r
-\r
-bool DBobView::CalculateTrajectory(vec3_t start, vec3_t apex, float multiplier, int points, float varGravity)\r
-{\r
- if(apex[2] <= start[2])\r
- {\r
- SetPath(NULL);\r
- return FALSE;\r
- }\r
- // ----think q3a actually would allow these\r
- //scrub that, coz the plugin wont :]\r
-\r
- vec3_t dist, speed;\r
- VectorSubtract(apex, start, dist);\r
-\r
- vec_t speed_z = (float)sqrt(-2*LOCAL_GRAVITY*dist[2]);\r
- float flight_time = -speed_z/LOCAL_GRAVITY;\r
-\r
-\r
- VectorScale(dist, 1/flight_time, speed);\r
- speed[2] = speed_z;\r
-\r
-// Sys_Printf("Speed: (%.4f %.4f %.4f)\n", speed[0], speed[1], speed[2]);\r
-\r
- vec3_t* pPath = new vec3_t[points];\r
-\r
- float interval = multiplier*flight_time/points;\r
- for(int i = 0; i < points; i++)\r
- {\r
- float ltime = interval*i;\r
-\r
- VectorScale(speed, ltime, pPath[i]);\r
- VectorAdd(pPath[i], start, pPath[i]);\r
-\r
- // could do this all with vectors\r
- // vGrav = {0, 0, -800.0f}\r
- // VectorScale(vGrav, 0.5f*ltime*ltime, vAdd);\r
- // VectorScale(speed, ltime, pPath[i]);\r
- // _VectorAdd(pPath[i], start, pPath[i])\r
- // _VectorAdd(pPath[i], vAdd, pPath[i])\r
-\r
- pPath[i][2] = start[2] + (speed_z*ltime) + (varGravity*0.5f*ltime*ltime);\r
- }\r
-\r
- SetPath(pPath);\r
- return TRUE;\r
-}\r
-\r
-void DBobView::Begin(const char* trigger, const char *target, float multiplier, int points, float varGravity, bool bNoUpdate, bool bShowExtra)\r
-{\r
- strcpy(entTrigger, trigger);\r
- strcpy(entTarget, target);\r
-\r
- fMultiplier = multiplier;\r
- fVarGravity = varGravity;\r
- nPathCount = points;\r
- m_bShowExtra = bShowExtra;\r
-\r
- Register();\r
-\r
- if(UpdatePath())\r
- {\r
- if(!bNoUpdate)\r
- {\r
- eyes = new DListener;\r
- eyes->parent = this;\r
- eyes->Register();\r
- }\r
- }\r
- else\r
- {\r
- Sys_ERROR("Initialization Failure in DBobView::Begin");\r
- delete this;\r
- }\r
-}\r
-\r
-bool DBobView::UpdatePath()\r
-{\r
- vec3_t start, apex;\r
-\r
- if(GetEntityCentre(entTrigger, start))\r
- {\r
- if(GetEntityCentre(entTarget, apex))\r
- {\r
- CalculateTrajectory(start, apex, fMultiplier, nPathCount, fVarGravity);\r
- return TRUE;\r
- }\r
- }\r
- return FALSE;\r
-}\r
+/*
+BobToolz plugin for GtkRadiant
+Copyright (C) 2001 Gordon Biggans
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+// BobView.cpp: implementation of the DBobView class.
+//
+//////////////////////////////////////////////////////////////////////
+
+#include "StdAfx.h"
+#include "DBobView.h"
+#include "DListener.h"
+#include "misc.h"
+#include "funchandlers.h"
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+DBobView::DBobView()
+{
+ nPathCount = 0;
+ refCount = 1;
+
+ m_bHooked = FALSE;
+
+ path = NULL;
+ eyes = NULL;
+
+ boundingShow = BOUNDS_APEX;
+}
+
+DBobView::~DBobView()
+{
+ if(path)
+ delete[] path;
+
+ // oops forgot to remove our eyes, was causing access violation when it tried
+ // to talk to it's parent
+ if(eyes)
+ delete eyes;
+
+ if(m_bHooked)
+ UnRegister();
+
+ g_PathView = NULL;
+}
+
+//////////////////////////////////////////////////////////////////////
+// Implementation
+//////////////////////////////////////////////////////////////////////
+
+void DBobView::Draw2D(VIEWTYPE vt)
+{
+ if(!path)
+ return;
+
+ g_QglTable.m_pfn_qglPushAttrib(GL_ALL_ATTRIB_BITS);
+
+ g_QglTable.m_pfn_qglDisable(GL_BLEND);
+ g_QglTable.m_pfn_qglEnable(GL_LINE_SMOOTH);
+
+ g_QglTable.m_pfn_qglPushMatrix();
+
+ switch(vt)
+ {
+ case XY:
+ break;
+ case XZ:
+ g_QglTable.m_pfn_qglRotatef(270.0f, 1.0f, 0.0f, 0.0f);
+ break;
+ case YZ:
+ g_QglTable.m_pfn_qglRotatef(270.0f, 1.0f, 0.0f, 0.0f);
+ g_QglTable.m_pfn_qglRotatef(270.0f, 0.0f, 0.0f, 1.0f);
+ break;
+ }
+
+ g_QglTable.m_pfn_qglLineWidth(1.0f);
+ g_QglTable.m_pfn_qglColor4f(1.0f, 0.0f, 0.0f, 1.0f);
+
+ int i;
+
+ g_QglTable.m_pfn_qglBegin(GL_LINE_STRIP);
+
+ for(i = 0; i < nPathCount; i++)
+ g_QglTable.m_pfn_qglVertex3fv(path[i]);
+
+ g_QglTable.m_pfn_qglEnd();
+
+ if(m_bShowExtra)
+ {
+ // +mars
+ // for the bounding box stuff
+ g_QglTable.m_pfn_qglColor4f(0.25f, 0.75f, 0.75f, 1.0f);
+
+ g_QglTable.m_pfn_qglTranslatef( 16.0f, 16.0f, 28.0f );
+
+ g_QglTable.m_pfn_qglBegin( GL_LINE_STRIP );
+
+ for ( i = 0; i < nPathCount; i++ )
+ g_QglTable.m_pfn_qglVertex3fv( path[i] );
+
+ g_QglTable.m_pfn_qglEnd();
+
+ // ---------------
+
+ g_QglTable.m_pfn_qglTranslatef( -16.0f, -16.0f, -28.0f ); // back to where we were
+ g_QglTable.m_pfn_qglTranslatef( -16.0f, 16.0f, 28.0f ); // move to new postion
+
+ g_QglTable.m_pfn_qglBegin( GL_LINE_STRIP );
+
+ for ( i = 0; i < nPathCount; i++ )
+ g_QglTable.m_pfn_qglVertex3fv( path[i] );
+
+ g_QglTable.m_pfn_qglEnd();
+
+ // --------------
+
+ g_QglTable.m_pfn_qglTranslatef( 16.0f, -16.0f, -28.0f ); // back to where we were
+ g_QglTable.m_pfn_qglTranslatef( 16.0f, -16.0f, -28.0f ); // new pos
+
+ g_QglTable.m_pfn_qglBegin( GL_LINE_STRIP );
+
+ for ( i = 0; i < nPathCount; i++ )
+ g_QglTable.m_pfn_qglVertex3fv( path[i] );
+
+ g_QglTable.m_pfn_qglEnd();
+
+ // ----------------
+
+ g_QglTable.m_pfn_qglTranslatef( -16.0f, 16.0f, 28.0f ); // back to where we were
+
+/* g_QglTable.m_pfn_qglTranslatef( -16.0f, -16.0f, -28.0f ); // new pos
+
+ g_QglTable.m_pfn_qglBegin( GL_LINE_STRIP );
+
+ if ( boundingShow == BOUNDS_ALL )
+ {
+ for ( i = 0; i < nPathCount; i++ )
+ g_QglTable.m_pfn_qglVertex3fv( path[i] );
+ }
+ else if ( boundingShow == BOUNDS_APEX )
+ {
+ for ( i = (nPathCount/4); i < (nPathCount/4) * 3; i++ )
+ g_QglTable.m_pfn_qglVertex3fv( path[i] );
+ }
+
+ g_QglTable.m_pfn_qglEnd();*/ // djbob: er, um doesn't really seem to do anyhting
+ }
+
+ // -mars
+
+ g_QglTable.m_pfn_qglPopMatrix();
+
+ g_QglTable.m_pfn_qglPopAttrib();
+}
+
+void DBobView::Draw3D()
+{
+ if(!path)
+ return;
+
+ g_QglTable.m_pfn_qglPushAttrib(GL_ALL_ATTRIB_BITS);
+
+ g_QglTable.m_pfn_qglDisable(GL_BLEND);
+ g_QglTable.m_pfn_qglEnable(GL_LINE_SMOOTH);
+
+ g_QglTable.m_pfn_qglLineWidth(1.0f);
+ g_QglTable.m_pfn_qglColor4f(1.0f, 0.0f, 0.0f, 1.0f);
+
+ g_QglTable.m_pfn_qglBegin(GL_LINE_STRIP);
+
+ for(int i = 0; i < nPathCount; i++)
+ g_QglTable.m_pfn_qglVertex3fv(path[i]);
+
+ g_QglTable.m_pfn_qglEnd();
+
+ if(m_bShowExtra)
+ {
+ // +mars
+ // ahhh -- a nice C&P job :)
+ // for the bounding box stuff
+ g_QglTable.m_pfn_qglColor4f(0.25f, 0.75f, 0.75f, 1.0f);
+
+ g_QglTable.m_pfn_qglTranslatef( 16.0f, 16.0f, 28.0f );
+
+ g_QglTable.m_pfn_qglBegin( GL_LINE_STRIP );
+
+ int i;
+ for ( i = 0; i < nPathCount; i++ )
+ g_QglTable.m_pfn_qglVertex3fv( path[i] );
+
+ g_QglTable.m_pfn_qglEnd();
+
+ // ---------------
+
+ g_QglTable.m_pfn_qglTranslatef( -16.0f, -16.0f, -28.0f ); // back to where we were
+ g_QglTable.m_pfn_qglTranslatef( -16.0f, 16.0f, 28.0f ); // move to new postion
+
+ g_QglTable.m_pfn_qglBegin( GL_LINE_STRIP );
+
+ for ( i = 0; i < nPathCount; i++ )
+ g_QglTable.m_pfn_qglVertex3fv( path[i] );
+
+ g_QglTable.m_pfn_qglEnd();
+
+ // --------------
+
+ g_QglTable.m_pfn_qglTranslatef( 16.0f, -16.0f, -28.0f ); // back to where we were
+ g_QglTable.m_pfn_qglTranslatef( 16.0f, -16.0f, -28.0f ); // new pos
+
+ g_QglTable.m_pfn_qglBegin( GL_LINE_STRIP );
+
+ for ( i = 0; i < nPathCount; i++ )
+ g_QglTable.m_pfn_qglVertex3fv( path[i] );
+
+ g_QglTable.m_pfn_qglEnd();
+
+ // ----------------
+
+ g_QglTable.m_pfn_qglTranslatef( -16.0f, 16.0f, 28.0f ); // back to where we were
+ g_QglTable.m_pfn_qglTranslatef( -16.0f, -16.0f, -28.0f ); // new pos
+
+ g_QglTable.m_pfn_qglBegin( GL_LINE_STRIP );
+
+ for ( i = 0; i < nPathCount; i++ )
+ g_QglTable.m_pfn_qglVertex3fv( path[i] );
+
+ g_QglTable.m_pfn_qglEnd();
+ }
+ // -mars
+
+ g_QglTable.m_pfn_qglPopAttrib();
+}
+
+void DBobView::Register()
+{
+ g_QglTable.m_pfnHookGL2DWindow( this );
+ g_QglTable.m_pfnHookGL3DWindow( this );
+ m_bHooked = TRUE;
+}
+
+void DBobView::UnRegister()
+{
+ g_QglTable.m_pfnUnHookGL2DWindow( this );
+ g_QglTable.m_pfnUnHookGL3DWindow( this );
+ m_bHooked = FALSE;
+}
+
+void DBobView::SetPath(vec3_t *pPath)
+{
+ if(path)
+ delete[] path;
+
+ path = pPath;
+}
+
+#define LOCAL_GRAVITY -800.0f
+
+bool DBobView::CalculateTrajectory(vec3_t start, vec3_t apex, float multiplier, int points, float varGravity)
+{
+ if(apex[2] <= start[2])
+ {
+ SetPath(NULL);
+ return FALSE;
+ }
+ // ----think q3a actually would allow these
+ //scrub that, coz the plugin wont :]
+
+ vec3_t dist, speed;
+ VectorSubtract(apex, start, dist);
+
+ vec_t speed_z = (float)sqrt(-2*LOCAL_GRAVITY*dist[2]);
+ float flight_time = -speed_z/LOCAL_GRAVITY;
+
+
+ VectorScale(dist, 1/flight_time, speed);
+ speed[2] = speed_z;
+
+// Sys_Printf("Speed: (%.4f %.4f %.4f)\n", speed[0], speed[1], speed[2]);
+
+ vec3_t* pPath = new vec3_t[points];
+
+ float interval = multiplier*flight_time/points;
+ for(int i = 0; i < points; i++)
+ {
+ float ltime = interval*i;
+
+ VectorScale(speed, ltime, pPath[i]);
+ VectorAdd(pPath[i], start, pPath[i]);
+
+ // could do this all with vectors
+ // vGrav = {0, 0, -800.0f}
+ // VectorScale(vGrav, 0.5f*ltime*ltime, vAdd);
+ // VectorScale(speed, ltime, pPath[i]);
+ // _VectorAdd(pPath[i], start, pPath[i])
+ // _VectorAdd(pPath[i], vAdd, pPath[i])
+
+ pPath[i][2] = start[2] + (speed_z*ltime) + (varGravity*0.5f*ltime*ltime);
+ }
+
+ SetPath(pPath);
+ return TRUE;
+}
+
+void DBobView::Begin(const char* trigger, const char *target, float multiplier, int points, float varGravity, bool bNoUpdate, bool bShowExtra)
+{
+ strcpy(entTrigger, trigger);
+ strcpy(entTarget, target);
+
+ fMultiplier = multiplier;
+ fVarGravity = varGravity;
+ nPathCount = points;
+ m_bShowExtra = bShowExtra;
+
+ Register();
+
+ if(UpdatePath())
+ {
+ if(!bNoUpdate)
+ {
+ eyes = new DListener;
+ eyes->parent = this;
+ eyes->Register();
+ }
+ }
+ else
+ {
+ Sys_ERROR("Initialization Failure in DBobView::Begin");
+ delete this;
+ }
+}
+
+bool DBobView::UpdatePath()
+{
+ vec3_t start, apex;
+
+ if(GetEntityCentre(entTrigger, start))
+ {
+ if(GetEntityCentre(entTarget, apex))
+ {
+ CalculateTrajectory(start, apex, fMultiplier, nPathCount, fVarGravity);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
-/*\r
-BobToolz plugin for GtkRadiant\r
-Copyright (C) 2001 Gordon Biggans\r
-\r
-This library is free software; you can redistribute it and/or\r
-modify it under the terms of the GNU Lesser General Public\r
-License as published by the Free Software Foundation; either\r
-version 2.1 of the License, or (at your option) any later version.\r
-\r
-This library is distributed in the hope that it will be useful,\r
-but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
-Lesser General Public License for more details.\r
-\r
-You should have received a copy of the GNU Lesser General Public\r
-License along with this library; if not, write to the Free Software\r
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
-*/\r
-\r
-// DBrush.cpp: implementation of the DBrush class.\r
-//\r
-//////////////////////////////////////////////////////////////////////\r
-\r
-#include "StdAfx.h"\r
-\r
-#ifdef _WIN32\r
-#pragma warning(disable : 4786)\r
-#endif\r
-\r
-#include "DBrush.h"\r
-#include "DWinding.h"\r
-#include "dialogs-gtk.h"\r
-\r
-#include "misc.h"\r
-\r
-//////////////////////////////////////////////////////////////////////\r
-// Construction/Destruction\r
-//////////////////////////////////////////////////////////////////////\r
-\r
-DBrush::DBrush(int ID)\r
-{\r
- m_nBrushID = ID;\r
- bBoundsBuilt = FALSE;\r
- QER_brush = NULL;\r
-}\r
-\r
-DBrush::~DBrush()\r
-{\r
- ClearFaces();\r
- ClearPoints();\r
-}\r
-\r
-//////////////////////////////////////////////////////////////////////\r
-// Implementation\r
-//////////////////////////////////////////////////////////////////////\r
-\r
-DPlane* DBrush::AddFace(vec3_t va, vec3_t vb, vec3_t vc, _QERFaceData* texData)\r
-{\r
-#ifdef _DEBUG\r
-// Sys_Printf("(%f %f %f) (%f %f %f) (%f %f %f)\n", va[0], va[1], va[2], vb[0], vb[1], vb[2], vc[0], vc[1], vc[2]);\r
-#endif\r
- bBoundsBuilt = FALSE;\r
- DPlane* newFace = new DPlane(va, vb, vc, texData);\r
- faceList.push_back(newFace);\r
- \r
- return newFace;\r
-}\r
-\r
-int DBrush::BuildPoints()\r
-{\r
- ClearPoints();\r
- \r
- if(faceList.size() <= 3) // if less than 3 faces, there can be no points\r
- return 0; // with only 3 faces u can't have a bounded soild\r
-\r
- for(list<DPlane *>::const_iterator p1=faceList.begin(); p1!=faceList.end(); p1++)\r
- {\r
- list<DPlane *>::const_iterator p2=p1;\r
- for(p2++; p2!=faceList.end(); p2++)\r
- {\r
- list<DPlane *>::const_iterator p3=p2;\r
- for(p3++; p3!=faceList.end(); p3++)\r
- {\r
- vec3_t pnt;\r
- if((*p1)->PlaneIntersection(*p2, *p3, pnt))\r
- {\r
- int pos = PointPosition(pnt);\r
-\r
- if(pos == POINT_IN_BRUSH)\r
- { // ???? shouldn't happen here\r
- Sys_Printf("ERROR:: Build Brush Points: Point IN brush!!!\n");\r
- }\r
- else if(pos == POINT_ON_BRUSH)\r
- { // normal point\r
- if(!HasPoint(pnt))\r
- AddPoint(pnt);\r
-/* else\r
- Sys_Printf("Duplicate Point Found, pyramids ahoy!!!!!\n");*/\r
- // point lies on more that 3 planes\r
- }\r
- \r
- // otherwise point is removed due to another plane..\r
-\r
- // Sys_Printf("(%f, %f, %f)\n", pnt[0], pnt[1], pnt[2]); \r
- } \r
- }\r
- }\r
- }\r
-\r
-#ifdef _DEBUG\r
-// Sys_Printf("%i points on brush\n", pointList.size());\r
-#endif\r
-\r
- return pointList.size();\r
-}\r
-\r
-void DBrush::LoadFromBrush_t(brush_t* brush, bool textured)\r
-{\r
- ClearFaces();\r
- ClearPoints();\r
-\r
- for(int i = g_FuncTable.m_pfnGetFaceCount(brush)-1; i >= 0 ; i--)\r
- { // running backwards so i dont have to use the count function each time (OPT)\r
- _QERFaceData* faceData = g_FuncTable.m_pfnGetFaceData(brush, i);\r
-\r
- if(faceData == NULL)\r
- DoMessageBox("Null pointer returned", "WARNING!", MB_OK);\r
-\r
- if(textured)\r
- AddFace(faceData->m_v1, faceData->m_v2, faceData->m_v3, faceData);\r
- else\r
- AddFace(faceData->m_v1, faceData->m_v2, faceData->m_v3, NULL);\r
- }\r
-\r
- QER_brush = brush;\r
-}\r
-\r
-int DBrush::PointPosition(vec3_t pnt)\r
-{\r
- int state = POINT_IN_BRUSH; // if nothing happens point is inside brush\r
-\r
- for(list<DPlane *>::const_iterator chkPlane=faceList.begin(); chkPlane!=faceList.end(); chkPlane++)\r
- {\r
- float dist = (*chkPlane)->DistanceToPoint(pnt);\r
-\r
- if(dist > MAX_ROUND_ERROR)\r
- return POINT_OUT_BRUSH; // if point is in front of plane, it CANT be in the brush\r
- else if(fabs(dist) < MAX_ROUND_ERROR)\r
- state = POINT_ON_BRUSH; // if point is ON plane point is either ON the brush \r
- // or outside it, it can no longer be in it\r
- }\r
-\r
- return state;\r
-}\r
-\r
-void DBrush::ClearPoints()\r
-{\r
- for(list<DPoint *>::const_iterator deadPoint=pointList.begin(); deadPoint!=pointList.end(); deadPoint++) {\r
- delete *deadPoint;\r
- }\r
- pointList.clear();\r
-}\r
-\r
-void DBrush::ClearFaces()\r
-{\r
- bBoundsBuilt = FALSE;\r
- for(list<DPlane *>::const_iterator deadPlane=faceList.begin(); deadPlane!=faceList.end(); deadPlane++)\r
- {\r
- delete *deadPlane;\r
- }\r
- faceList.clear();\r
-}\r
-\r
-void DBrush::AddPoint(vec3_t pnt)\r
-{\r
- DPoint* newPoint = new DPoint;\r
- VectorCopy(pnt, newPoint->_pnt);\r
- pointList.push_back(newPoint);\r
-}\r
-\r
-bool DBrush::HasPoint(vec3_t pnt)\r
-{\r
- for(list<DPoint *>::const_iterator chkPoint=pointList.begin(); chkPoint!=pointList.end(); chkPoint++)\r
- {\r
- if(**chkPoint == pnt)\r
- return TRUE;\r
- }\r
-\r
- return FALSE;\r
-}\r
-\r
-int DBrush::RemoveRedundantPlanes()\r
-{\r
- int cnt = 0;\r
- list<DPlane *>::iterator chkPlane;\r
-\r
- // find duplicate planes\r
- list<DPlane *>::iterator p1=faceList.begin();\r
-\r
- while( p1!=faceList.end() )\r
- {\r
- list<DPlane *>::iterator p2 = p1;\r
-\r
- for(p2++; p2!=faceList.end(); p2++)\r
- {\r
- if(**p1 == **p2)\r
- {\r
- if(!strcmp((*p1)->texInfo.m_TextureName, "textures/common/caulk"))\r
- {\r
- delete *p1;\r
- p1 = faceList.erase(p1); // duplicate plane\r
- }\r
- else\r
- {\r
- delete *p2;\r
- p2 = faceList.erase(p2); // duplicate plane\r
- }\r
-\r
- cnt++;\r
- break;\r
- }\r
- }\r
-\r
- if( p2 == faceList.end() )\r
- p1++;\r
- }\r
- \r
- //+djbob kill planes with bad normal, they are more of a nuisance than losing a brush\r
- chkPlane=faceList.begin();\r
- while( chkPlane!=faceList.end() )\r
- {\r
- if(VectorLength((*chkPlane)->normal) == 0) // plane has bad normal\r
- {\r
- delete *chkPlane;\r
- chkPlane = faceList.erase(chkPlane);\r
- cnt++;\r
- } else {\r
- chkPlane++;\r
- }\r
- }\r
- //-djbob\r
- \r
- if(pointList.size() == 0) // if points may not have been built, build them\r
-/* if(BuildPoints() == 0) // just let the planes die if they are all bad\r
- return cnt;*/\r
- BuildPoints();\r
-\r
- chkPlane=faceList.begin();\r
- while(chkPlane != faceList.end())\r
- {\r
- if((*chkPlane)->IsRedundant(pointList)) // checks that plane "0wnz" :), 3 or more points\r
- {\r
- delete *chkPlane;\r
- chkPlane = faceList.erase(chkPlane);\r
- cnt++;\r
- } \r
- else \r
- chkPlane++;\r
- }\r
-\r
- return cnt;\r
-}\r
-\r
-bool DBrush::GetBounds(vec3_t min, vec3_t max)\r
-{\r
- BuildBounds();\r
-\r
- if(!bBoundsBuilt)\r
- return FALSE;\r
-\r
- VectorCopy(bbox_min, min);\r
- VectorCopy(bbox_max, max);\r
-\r
- return TRUE;\r
-}\r
-\r
-bool DBrush::BBoxCollision(DBrush* chkBrush)\r
-{\r
- vec3_t min1, min2;\r
- vec3_t max1, max2;\r
-\r
- GetBounds(min1, max1);\r
- chkBrush->GetBounds(min2, max2);\r
-\r
- if(min1[0] >= max2[0])\r
- return FALSE;\r
- if(min1[1] >= max2[1])\r
- return FALSE;\r
- if(min1[2] >= max2[2])\r
- return FALSE;\r
-\r
- if(max1[0] <= min2[0])\r
- return FALSE;\r
- if(max1[1] <= min2[1])\r
- return FALSE;\r
- if(max1[2] <= min2[2])\r
- return FALSE;\r
-\r
- return TRUE;\r
-}\r
-\r
-DPlane* DBrush::HasPlane(DPlane* chkPlane)\r
-{\r
- for(list<DPlane *>::const_iterator brushPlane=faceList.begin(); brushPlane!=faceList.end(); brushPlane++)\r
- {\r
- if(**brushPlane == *chkPlane)\r
- return *brushPlane;\r
- }\r
- return NULL;\r
-}\r
-\r
-bool DBrush::IsCutByPlane(DPlane *cuttingPlane)\r
-{\r
- bool isInFront;\r
-\r
- if(pointList.size() == 0)\r
- if(BuildPoints() == 0)\r
- return FALSE;\r
-\r
- list<DPoint *>::const_iterator chkPnt = pointList.begin();\r
-\r
- if(chkPnt == pointList.end())\r
- return FALSE;\r
-\r
- float dist = cuttingPlane->DistanceToPoint((*chkPnt)->_pnt);\r
-\r
- if(dist > MAX_ROUND_ERROR)\r
- isInFront = FALSE;\r
- else if(dist < MAX_ROUND_ERROR)\r
- isInFront = TRUE;\r
- else\r
- return TRUE;\r
-\r
- for(chkPnt++=pointList.begin(); chkPnt!=pointList.end(); chkPnt++)\r
- {\r
- dist = cuttingPlane->DistanceToPoint((*chkPnt)->_pnt);\r
-\r
- if(dist > MAX_ROUND_ERROR)\r
- {\r
- if(isInFront)\r
- return TRUE;\r
- }\r
- else if(dist < MAX_ROUND_ERROR)\r
- {\r
- if(!isInFront)\r
- return TRUE;\r
- }\r
- else\r
- return TRUE;\r
- }\r
-\r
- return FALSE;\r
-}\r
-\r
-brush_t* DBrush::BuildInRadiant(bool allowDestruction, int* changeCnt, entity_t* entity)\r
-{\r
- if(allowDestruction)\r
- {\r
- bool kill = TRUE;\r
- \r
- for(list<DPlane *>::const_iterator chkPlane=faceList.begin(); chkPlane!=faceList.end(); chkPlane++)\r
- {\r
- if((*chkPlane)->m_bChkOk)\r
- {\r
- kill = FALSE;\r
- break;\r
- }\r
- }\r
- if(kill)\r
- return NULL;\r
- }\r
-\r
- //+djbob: fixed bug when brush had no faces "phantom brush" in radiant.\r
- if(faceList.size() < 4)\r
- {\r
- Sys_Printf("Possible Phantom Brush Found, will not rebuild\n");\r
- return NULL;\r
- }\r
- //-djbob\r
-\r
- QER_brush = (brush_t*)g_FuncTable.m_pfnCreateBrushHandle();\r
-\r
- for(list<DPlane *>::const_iterator buildPlane=faceList.begin(); buildPlane!=faceList.end(); buildPlane++) {\r
- if((*buildPlane)->AddToBrush_t(QER_brush) && changeCnt) {\r
- (*changeCnt)++;\r
- }\r
- }\r
-\r
- if(entity) {\r
- g_FuncTable.m_pfnCommitBrushHandleToEntity(QER_brush, entity);\r
- g_BrushTable.m_pfnBrush_Build(QER_brush);\r
- g_BrushTable.m_pfnBrush_AddToList(QER_brush, g_AppDataTable.m_pfnSelectedBrushes());\r
- } else {\r
- g_FuncTable.m_pfnCommitBrushHandle(QER_brush);\r
- }\r
-\r
- return QER_brush;\r
-}\r
-\r
-void DBrush::CutByPlane(DPlane *cutPlane, DBrush **newBrush1, DBrush **newBrush2)\r
-{\r
- if(!IsCutByPlane(cutPlane))\r
- {\r
- *newBrush1 = NULL;\r
- *newBrush2 = NULL;\r
- return;\r
- }\r
-\r
- DBrush* b1 = new DBrush;\r
- DBrush* b2 = new DBrush;\r
- \r
- for(list<DPlane *>::const_iterator parsePlane=faceList.begin(); parsePlane!=faceList.end(); parsePlane++)\r
- {\r
- b1->AddFace((*parsePlane)->points[0], (*parsePlane)->points[1], (*parsePlane)->points[2], NULL);\r
- b2->AddFace((*parsePlane)->points[0], (*parsePlane)->points[1], (*parsePlane)->points[2], NULL);\r
- }\r
-\r
- b1->AddFace(cutPlane->points[0], cutPlane->points[1], cutPlane->points[2], NULL);\r
- b2->AddFace(cutPlane->points[2], cutPlane->points[1], cutPlane->points[0], NULL);\r
-\r
- b1->RemoveRedundantPlanes();\r
- b2->RemoveRedundantPlanes();\r
-\r
- *newBrush1 = b1;\r
- *newBrush2 = b2;\r
-}\r
-\r
-bool DBrush::IntersectsWith(DBrush *chkBrush)\r
-{\r
- if(pointList.size() == 0)\r
- if(BuildPoints() == 0)\r
- return FALSE; // invalid brush!!!!\r
-\r
- if(chkBrush->pointList.size() == 0)\r
- if(chkBrush->BuildPoints() == 0)\r
- return FALSE; // invalid brush!!!!\r
- \r
- if(!BBoxCollision(chkBrush))\r
- return FALSE;\r
-\r
- list<DPlane *>::const_iterator iplPlane;\r
-\r
- for( iplPlane=faceList.begin(); iplPlane!=faceList.end(); iplPlane++)\r
- {\r
-\r
- bool allInFront = TRUE;\r
- for(list<DPoint *>::const_iterator iPoint=chkBrush->pointList.begin(); iPoint!=chkBrush->pointList.end(); iPoint++)\r
- {\r
- if((*iplPlane)->DistanceToPoint((*iPoint)->_pnt) < -MAX_ROUND_ERROR)\r
- {\r
- allInFront = FALSE;\r
- break;\r
- }\r
- }\r
- if(allInFront)\r
- return FALSE;\r
- }\r
-\r
- for( iplPlane=chkBrush->faceList.begin(); iplPlane!=chkBrush->faceList.end(); iplPlane++)\r
- {\r
- bool allInFront = TRUE;\r
- for(list<DPoint *>::const_iterator iPoint=pointList.begin(); iPoint!=pointList.end(); iPoint++)\r
- {\r
- if((*iplPlane)->DistanceToPoint((*iPoint)->_pnt) < -MAX_ROUND_ERROR)\r
- {\r
- allInFront = FALSE;\r
- break;\r
- }\r
- }\r
- if(allInFront)\r
- return FALSE;\r
- }\r
-\r
- return TRUE;\r
-}\r
-\r
-bool DBrush::IntersectsWith(DPlane* p1, DPlane* p2, vec3_t v) {\r
- vec3_t vDown = { 0, 0, -1 };\r
-\r
- list<DPlane *>::const_iterator iplPlane;\r
- for( iplPlane = faceList.begin(); iplPlane != faceList.end(); iplPlane++) {\r
- DPlane* p = (*iplPlane);\r
- \r
- vec_t d = DotProduct( p->normal, vDown );\r
- if( d >= 0 ) {\r
- continue;\r
- }\r
- if(p->PlaneIntersection(p1, p2, v)) {\r
- if(PointPosition( v ) != POINT_OUT_BRUSH) {\r
- return TRUE;\r
- }\r
- }\r
- }\r
-\r
- return FALSE;\r
-}\r
-\r
-void DBrush::BuildBounds()\r
-{\r
- if(!bBoundsBuilt)\r
- {\r
- if(pointList.size() == 0) // if points may not have been built, build them\r
- if(BuildPoints() == 0)\r
- return;\r
- \r
- list<DPoint *>::const_iterator first = pointList.begin();\r
- VectorCopy((*first)->_pnt, bbox_min);\r
- VectorCopy((*first)->_pnt, bbox_max);\r
-\r
- list<DPoint *>::const_iterator point=pointList.begin();\r
- for( point++; point!=pointList.end(); point++)\r
- {\r
- if((*point)->_pnt[0] > bbox_max[0])\r
- bbox_max[0] = (*point)->_pnt[0];\r
- if((*point)->_pnt[1] > bbox_max[1])\r
- bbox_max[1] = (*point)->_pnt[1];\r
- if((*point)->_pnt[2] > bbox_max[2])\r
- bbox_max[2] = (*point)->_pnt[2];\r
-\r
- if((*point)->_pnt[0] < bbox_min[0])\r
- bbox_min[0] = (*point)->_pnt[0];\r
- if((*point)->_pnt[1] < bbox_min[1])\r
- bbox_min[1] = (*point)->_pnt[1];\r
- if((*point)->_pnt[2] < bbox_min[2])\r
- bbox_min[2] = (*point)->_pnt[2];\r
- }\r
-\r
- bBoundsBuilt = TRUE;\r
- }\r
-}\r
-\r
-bool DBrush::BBoxTouch(DBrush *chkBrush)\r
-{\r
- vec3_t min1, min2;\r
- vec3_t max1, max2;\r
-\r
- GetBounds(min1, max1);\r
- chkBrush->GetBounds(min2, max2);\r
-\r
- if((min1[0] - max2[0]) > MAX_ROUND_ERROR)\r
- return FALSE;\r
- if((min1[1] - max2[1]) > MAX_ROUND_ERROR)\r
- return FALSE;\r
- if((min1[2] - max2[2]) > MAX_ROUND_ERROR)\r
- return FALSE;\r
-\r
- if((min2[0] - max1[0]) > MAX_ROUND_ERROR)\r
- return FALSE;\r
- if((min2[1] - max1[1]) > MAX_ROUND_ERROR)\r
- return FALSE;\r
- if((min2[2] - max1[2]) > MAX_ROUND_ERROR)\r
- return FALSE;\r
-\r
- int cnt = 0;\r
-\r
- if((min2[0] - max1[0]) == 0)\r
- cnt++;\r
-\r
- if((min2[1] - max1[1]) == 0)\r
- cnt++;\r
-\r
- if((min2[2] - max1[2]) == 0)\r
- cnt++;\r
-\r
- if((min1[0] - max2[0]) == 0)\r
- cnt++;\r
-\r
- if((min1[1] - max2[1]) == 0)\r
- cnt++;\r
-\r
- if((min1[2] - max2[2]) == 0)\r
- cnt++;\r
-\r
- if(cnt > 1)\r
- return FALSE;\r
-\r
- return TRUE;\r
-}\r
-\r
-void DBrush::ResetChecks(list<Str>* exclusionList)\r
-{\r
- for(list<DPlane *>::const_iterator resetPlane=faceList.begin(); resetPlane!=faceList.end(); resetPlane++)\r
- {\r
- bool set = FALSE;\r
-\r
- if(exclusionList)\r
- {\r
- for(list<Str>::iterator eTexture = exclusionList->begin(); eTexture != exclusionList->end(); eTexture++)\r
- {\r
- if(strstr((*resetPlane)->texInfo.m_TextureName, eTexture->GetBuffer()))\r
- {\r
- set = TRUE;\r
- break;\r
- }\r
- }\r
- }\r
-\r
- (*resetPlane)->m_bChkOk = set;\r
- }\r
-}\r
-\r
-DPlane* DBrush::HasPlaneInverted(DPlane *chkPlane)\r
-{\r
- for(list<DPlane *>::const_iterator brushPlane=faceList.begin(); brushPlane!=faceList.end(); brushPlane++)\r
- {\r
- if(**brushPlane != *chkPlane)\r
- {\r
- if(fabs((*brushPlane)->_d + chkPlane->_d) < 0.1)\r
- return (*brushPlane);\r
- }\r
- }\r
- return NULL;\r
-}\r
-\r
-bool DBrush::HasTexture(const char *textureName)\r
-{\r
- for(list<DPlane *>::const_iterator chkPlane=faceList.begin(); chkPlane!=faceList.end(); chkPlane++)\r
- {\r
- if(strstr((*chkPlane)->texInfo.m_TextureName, textureName))\r
- return TRUE;\r
-\r
- }\r
- return FALSE;\r
-}\r
-\r
-bool DBrush::IsDetail()\r
-{\r
- for(list<DPlane *>::const_iterator chkPlane=faceList.begin(); chkPlane!=faceList.end(); chkPlane++)\r
- {\r
- if((*chkPlane)->texInfo.m_nContents & FACE_DETAIL)\r
- return TRUE;\r
-\r
- }\r
- return FALSE;\r
-}\r
-\r
-void DBrush::BuildFromWinding(DWinding *w)\r
-{\r
- if(w->numpoints < 3)\r
- {\r
- Sys_ERROR("Winding has invalid number of points");\r
- return;\r
- }\r
-\r
- DPlane* wPlane = w->WindingPlane();\r
-\r
- DWinding* w2;\r
- w2 = w->CopyWinding();\r
- int i;\r
- for(i = 0; i < w2->numpoints; i++)\r
- VectorAdd(w2->p[i], wPlane->normal, w2->p[i]);\r
-\r
- AddFace(w2->p[0], w2->p[1], w2->p[2], NULL);\r
- AddFace(w->p[2], w->p[1], w->p[0], NULL);\r
-\r
- for(i = 0; i < w->numpoints-1; i++)\r
- AddFace(w2->p[i], w->p[i], w->p[i+1], NULL);\r
- AddFace(w2->p[w->numpoints-1], w->p[w->numpoints-1], w->p[0], NULL);\r
-\r
- delete wPlane;\r
- delete w2;\r
-}\r
-\r
-void DBrush::SaveToFile(FILE *pFile)\r
-{\r
- fprintf(pFile, "{\n");\r
-\r
- for(list<DPlane *>::const_iterator pp=faceList.begin(); pp!=faceList.end(); pp++)\r
- {\r
- char buffer[512];\r
-\r
- sprintf(buffer, "( %.0f %.0f %.0f ) ( %.0f %.0f %.0f ) ( %.0f %.0f %.0f ) %s %.0f %.0f %f %f %.0f 0 0 0\n",\r
- (*pp)->points[0][0], (*pp)->points[0][1], (*pp)->points[0][2], \r
- (*pp)->points[1][0], (*pp)->points[1][1], (*pp)->points[1][2], \r
- (*pp)->points[2][0], (*pp)->points[2][1], (*pp)->points[2][2], \r
- (*pp)->texInfo.m_TextureName,\r
- (*pp)->texInfo.m_fShift[0], (*pp)->texInfo.m_fShift[1], \r
- (*pp)->texInfo.m_fScale[0], (*pp)->texInfo.m_fScale[0], \r
- (*pp)->texInfo.m_fRotate);\r
-\r
- fprintf(pFile, buffer);\r
- }\r
-\r
- fprintf(pFile, "}\n");\r
-}\r
-\r
-void DBrush::Rotate(vec3_t vOrigin, vec3_t vRotation)\r
-{\r
- for(list<DPlane *>::const_iterator rotPlane=faceList.begin(); rotPlane!=faceList.end(); rotPlane++)\r
- {\r
- for(int i = 0; i < 3; i++)\r
- VectorRotate((*rotPlane)->points[i], vRotation, vOrigin);\r
-\r
- (*rotPlane)->Rebuild();\r
- }\r
-}\r
-\r
-void DBrush::RotateAboutCentre(vec3_t vRotation)\r
-{\r
- vec3_t min, max, centre;\r
- GetBounds(min, max);\r
- VectorAdd(min, max, centre);\r
- VectorScale(centre, 0.5f, centre);\r
-\r
- Rotate(centre, vRotation);\r
-}\r
-\r
-bool DBrush::ResetTextures(const char* textureName, float fScale[2], float fShift[2], int rotation, const char* newTextureName, \r
- int bResetTextureName, int bResetScale[2], int bResetShift[2], int bResetRotation)\r
-{\r
- if(textureName)\r
- {\r
- bool changed = FALSE;\r
- for(list<DPlane *>::const_iterator resetPlane=faceList.begin(); resetPlane!=faceList.end(); resetPlane++)\r
- {\r
- if(!strcmp((*resetPlane)->texInfo.m_TextureName, textureName))\r
- {\r
- if(bResetTextureName)\r
- strcpy((*resetPlane)->texInfo.m_TextureName, newTextureName);\r
-\r
- if(bResetScale[0])\r
- (*resetPlane)->texInfo.m_fScale[0] = fScale[0];\r
- if(bResetScale[1])\r
- (*resetPlane)->texInfo.m_fScale[1] = fScale[1];\r
-\r
- if(bResetShift[0])\r
- (*resetPlane)->texInfo.m_fShift[0] = fShift[0];\r
- if(bResetShift[1])\r
- (*resetPlane)->texInfo.m_fShift[1] = fShift[1];\r
-\r
- if(bResetRotation)\r
- (*resetPlane)->texInfo.m_fRotate = (float)rotation;\r
-\r
- changed = TRUE;\r
- }\r
- }\r
- return changed; // no point rebuilding unless we need to, only slows things down\r
- }\r
- else\r
- {\r
- for(list<DPlane *>::const_iterator resetPlane=faceList.begin(); resetPlane!=faceList.end(); resetPlane++)\r
- {\r
- if(bResetTextureName)\r
- strcpy((*resetPlane)->texInfo.m_TextureName, newTextureName);\r
-\r
- if(bResetScale[0])\r
- (*resetPlane)->texInfo.m_fScale[0] = fScale[0];\r
- if(bResetScale[1])\r
- (*resetPlane)->texInfo.m_fScale[1] = fScale[1];\r
-\r
- if(bResetShift[0])\r
- (*resetPlane)->texInfo.m_fShift[0] = fShift[0];\r
- if(bResetShift[1])\r
- (*resetPlane)->texInfo.m_fShift[1] = fShift[1];\r
-\r
- if(bResetRotation)\r
- (*resetPlane)->texInfo.m_fRotate = (float)rotation;\r
- }\r
- return TRUE;\r
- }\r
-}\r
-\r
-bool DBrush::operator ==(DBrush* other)\r
-{\r
- list<DPlane *>::const_iterator chkPlane;\r
- \r
- for(chkPlane=faceList.begin(); chkPlane!=faceList.end(); chkPlane++)\r
- {\r
- if(!other->HasPlane((*chkPlane)))\r
- return FALSE;\r
- }\r
-\r
- for(chkPlane=faceList.begin(); chkPlane!=faceList.end(); chkPlane++)\r
- {\r
- if(!HasPlane((*chkPlane)))\r
- return FALSE;\r
- }\r
-\r
- return TRUE;\r
-}\r
-\r
-DPlane* DBrush::AddFace(vec3_t va, vec3_t vb, vec3_t vc, const char *textureName, bool bDetail)\r
-{\r
- bBoundsBuilt = FALSE;\r
- DPlane* newFace = new DPlane(va, vb, vc, textureName, bDetail);\r
- faceList.push_back(newFace);\r
- \r
- return newFace;\r
-}\r
-\r
-DPlane* DBrush::FindPlaneWithClosestNormal( vec_t* normal ) {\r
- vec_t bestDot = -2;\r
- DPlane* bestDotPlane = NULL;\r
- list<DPlane *>::const_iterator chkPlane;\r
- for( chkPlane = faceList.begin(); chkPlane != faceList.end(); chkPlane++ ) {\r
- DPlane* pPlane = (*chkPlane);\r
-\r
- vec_t dot = DotProduct( pPlane->normal, normal );\r
- if( dot > bestDot ) {\r
- bestDot = dot;\r
- bestDotPlane = pPlane;\r
- }\r
- }\r
-\r
- return bestDotPlane;\r
-}\r
-\r
-int DBrush::FindPointsForPlane( DPlane* plane, DPoint** pnts, int maxpnts ) {\r
- int numpnts = 0;\r
-\r
- if(!maxpnts) {\r
- return 0;\r
- }\r
-\r
- BuildPoints();\r
-\r
- for( list<DPoint *>::const_iterator points = pointList.begin(); points != pointList.end(); points++ ) {\r
- DPoint* point = (*points);\r
-\r
- if( fabs(plane->DistanceToPoint( point->_pnt )) < MAX_ROUND_ERROR ) {\r
- pnts[numpnts] = point;\r
- numpnts++;\r
-\r
- if(numpnts >= maxpnts) {\r
- return numpnts;\r
- }\r
-\r
- }\r
- }\r
-\r
- return numpnts;\r
-}\r
-\r
-void DBrush::RemovePlane( DPlane* plane ) {\r
- bBoundsBuilt = FALSE;\r
- for( list<DPlane *>::const_iterator deadPlane = faceList.begin(); deadPlane != faceList.end(); deadPlane++ ) { \r
- if(*deadPlane == plane) {\r
- delete *deadPlane;\r
- faceList.remove( plane );\r
- }\r
- }\r
-}\r
-\r
-void DBrush::RemoveFromRadiant( void ) {\r
- if(QER_brush) {\r
- g_FuncTable.m_pfnDeleteBrushHandle(QER_brush);\r
- }\r
-}\r
+/*
+BobToolz plugin for GtkRadiant
+Copyright (C) 2001 Gordon Biggans
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+// DBrush.cpp: implementation of the DBrush class.
+//
+//////////////////////////////////////////////////////////////////////
+
+#include "StdAfx.h"
+
+#ifdef _WIN32
+#pragma warning(disable : 4786)
+#endif
+
+#include "DBrush.h"
+#include "DWinding.h"
+#include "dialogs-gtk.h"
+
+#include "misc.h"
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+DBrush::DBrush(int ID)
+{
+ m_nBrushID = ID;
+ bBoundsBuilt = FALSE;
+ QER_brush = NULL;
+}
+
+DBrush::~DBrush()
+{
+ ClearFaces();
+ ClearPoints();
+}
+
+//////////////////////////////////////////////////////////////////////
+// Implementation
+//////////////////////////////////////////////////////////////////////
+
+DPlane* DBrush::AddFace(vec3_t va, vec3_t vb, vec3_t vc, _QERFaceData* texData)
+{
+#ifdef _DEBUG
+// Sys_Printf("(%f %f %f) (%f %f %f) (%f %f %f)\n", va[0], va[1], va[2], vb[0], vb[1], vb[2], vc[0], vc[1], vc[2]);
+#endif
+ bBoundsBuilt = FALSE;
+ DPlane* newFace = new DPlane(va, vb, vc, texData);
+ faceList.push_back(newFace);
+
+ return newFace;
+}
+
+int DBrush::BuildPoints()
+{
+ ClearPoints();
+
+ if(faceList.size() <= 3) // if less than 3 faces, there can be no points
+ return 0; // with only 3 faces u can't have a bounded soild
+
+ for(list<DPlane *>::const_iterator p1=faceList.begin(); p1!=faceList.end(); p1++)
+ {
+ list<DPlane *>::const_iterator p2=p1;
+ for(p2++; p2!=faceList.end(); p2++)
+ {
+ list<DPlane *>::const_iterator p3=p2;
+ for(p3++; p3!=faceList.end(); p3++)
+ {
+ vec3_t pnt;
+ if((*p1)->PlaneIntersection(*p2, *p3, pnt))
+ {
+ int pos = PointPosition(pnt);
+
+ if(pos == POINT_IN_BRUSH)
+ { // ???? shouldn't happen here
+ Sys_Printf("ERROR:: Build Brush Points: Point IN brush!!!\n");
+ }
+ else if(pos == POINT_ON_BRUSH)
+ { // normal point
+ if(!HasPoint(pnt))
+ AddPoint(pnt);
+/* else
+ Sys_Printf("Duplicate Point Found, pyramids ahoy!!!!!\n");*/
+ // point lies on more that 3 planes
+ }
+
+ // otherwise point is removed due to another plane..
+
+ // Sys_Printf("(%f, %f, %f)\n", pnt[0], pnt[1], pnt[2]);
+ }
+ }
+ }
+ }
+
+#ifdef _DEBUG
+// Sys_Printf("%i points on brush\n", pointList.size());
+#endif
+
+ return pointList.size();
+}
+
+void DBrush::LoadFromBrush_t(brush_t* brush, bool textured)
+{
+ ClearFaces();
+ ClearPoints();
+
+ for(int i = g_FuncTable.m_pfnGetFaceCount(brush)-1; i >= 0 ; i--)
+ { // running backwards so i dont have to use the count function each time (OPT)
+ _QERFaceData* faceData = g_FuncTable.m_pfnGetFaceData(brush, i);
+
+ if(faceData == NULL)
+ DoMessageBox("Null pointer returned", "WARNING!", MB_OK);
+
+ if(textured)
+ AddFace(faceData->m_v1, faceData->m_v2, faceData->m_v3, faceData);
+ else
+ AddFace(faceData->m_v1, faceData->m_v2, faceData->m_v3, NULL);
+ }
+
+ QER_brush = brush;
+}
+
+int DBrush::PointPosition(vec3_t pnt)
+{
+ int state = POINT_IN_BRUSH; // if nothing happens point is inside brush
+
+ for(list<DPlane *>::const_iterator chkPlane=faceList.begin(); chkPlane!=faceList.end(); chkPlane++)
+ {
+ float dist = (*chkPlane)->DistanceToPoint(pnt);
+
+ if(dist > MAX_ROUND_ERROR)
+ return POINT_OUT_BRUSH; // if point is in front of plane, it CANT be in the brush
+ else if(fabs(dist) < MAX_ROUND_ERROR)
+ state = POINT_ON_BRUSH; // if point is ON plane point is either ON the brush
+ // or outside it, it can no longer be in it
+ }
+
+ return state;
+}
+
+void DBrush::ClearPoints()
+{
+ for(list<DPoint *>::const_iterator deadPoint=pointList.begin(); deadPoint!=pointList.end(); deadPoint++) {
+ delete *deadPoint;
+ }
+ pointList.clear();
+}
+
+void DBrush::ClearFaces()
+{
+ bBoundsBuilt = FALSE;
+ for(list<DPlane *>::const_iterator deadPlane=faceList.begin(); deadPlane!=faceList.end(); deadPlane++)
+ {
+ delete *deadPlane;
+ }
+ faceList.clear();
+}
+
+void DBrush::AddPoint(vec3_t pnt)
+{
+ DPoint* newPoint = new DPoint;
+ VectorCopy(pnt, newPoint->_pnt);
+ pointList.push_back(newPoint);
+}
+
+bool DBrush::HasPoint(vec3_t pnt)
+{
+ for(list<DPoint *>::const_iterator chkPoint=pointList.begin(); chkPoint!=pointList.end(); chkPoint++)
+ {
+ if(**chkPoint == pnt)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+int DBrush::RemoveRedundantPlanes()
+{
+ int cnt = 0;
+ list<DPlane *>::iterator chkPlane;
+
+ // find duplicate planes
+ list<DPlane *>::iterator p1=faceList.begin();
+
+ while( p1!=faceList.end() )
+ {
+ list<DPlane *>::iterator p2 = p1;
+
+ for(p2++; p2!=faceList.end(); p2++)
+ {
+ if(**p1 == **p2)
+ {
+ if(!strcmp((*p1)->texInfo.m_TextureName, "textures/common/caulk"))
+ {
+ delete *p1;
+ p1 = faceList.erase(p1); // duplicate plane
+ }
+ else
+ {
+ delete *p2;
+ p2 = faceList.erase(p2); // duplicate plane
+ }
+
+ cnt++;
+ break;
+ }
+ }
+
+ if( p2 == faceList.end() )
+ p1++;
+ }
+
+ //+djbob kill planes with bad normal, they are more of a nuisance than losing a brush
+ chkPlane=faceList.begin();
+ while( chkPlane!=faceList.end() )
+ {
+ if(VectorLength((*chkPlane)->normal) == 0) // plane has bad normal
+ {
+ delete *chkPlane;
+ chkPlane = faceList.erase(chkPlane);
+ cnt++;
+ } else {
+ chkPlane++;
+ }
+ }
+ //-djbob
+
+ if(pointList.size() == 0) // if points may not have been built, build them
+/* if(BuildPoints() == 0) // just let the planes die if they are all bad
+ return cnt;*/
+ BuildPoints();
+
+ chkPlane=faceList.begin();
+ while(chkPlane != faceList.end())
+ {
+ if((*chkPlane)->IsRedundant(pointList)) // checks that plane "0wnz" :), 3 or more points
+ {
+ delete *chkPlane;
+ chkPlane = faceList.erase(chkPlane);
+ cnt++;
+ }
+ else
+ chkPlane++;
+ }
+
+ return cnt;
+}
+
+bool DBrush::GetBounds(vec3_t min, vec3_t max)
+{
+ BuildBounds();
+
+ if(!bBoundsBuilt)
+ return FALSE;
+
+ VectorCopy(bbox_min, min);
+ VectorCopy(bbox_max, max);
+
+ return TRUE;
+}
+
+bool DBrush::BBoxCollision(DBrush* chkBrush)
+{
+ vec3_t min1, min2;
+ vec3_t max1, max2;
+
+ GetBounds(min1, max1);
+ chkBrush->GetBounds(min2, max2);
+
+ if(min1[0] >= max2[0])
+ return FALSE;
+ if(min1[1] >= max2[1])
+ return FALSE;
+ if(min1[2] >= max2[2])
+ return FALSE;
+
+ if(max1[0] <= min2[0])
+ return FALSE;
+ if(max1[1] <= min2[1])
+ return FALSE;
+ if(max1[2] <= min2[2])
+ return FALSE;
+
+ return TRUE;
+}
+
+DPlane* DBrush::HasPlane(DPlane* chkPlane)
+{
+ for(list<DPlane *>::const_iterator brushPlane=faceList.begin(); brushPlane!=faceList.end(); brushPlane++)
+ {
+ if(**brushPlane == *chkPlane)
+ return *brushPlane;
+ }
+ return NULL;
+}
+
+bool DBrush::IsCutByPlane(DPlane *cuttingPlane)
+{
+ bool isInFront;
+
+ if(pointList.size() == 0)
+ if(BuildPoints() == 0)
+ return FALSE;
+
+ list<DPoint *>::const_iterator chkPnt = pointList.begin();
+
+ if(chkPnt == pointList.end())
+ return FALSE;
+
+ float dist = cuttingPlane->DistanceToPoint((*chkPnt)->_pnt);
+
+ if(dist > MAX_ROUND_ERROR)
+ isInFront = FALSE;
+ else if(dist < MAX_ROUND_ERROR)
+ isInFront = TRUE;
+ else
+ return TRUE;
+
+ for(chkPnt++=pointList.begin(); chkPnt!=pointList.end(); chkPnt++)
+ {
+ dist = cuttingPlane->DistanceToPoint((*chkPnt)->_pnt);
+
+ if(dist > MAX_ROUND_ERROR)
+ {
+ if(isInFront)
+ return TRUE;
+ }
+ else if(dist < MAX_ROUND_ERROR)
+ {
+ if(!isInFront)
+ return TRUE;
+ }
+ else
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+brush_t* DBrush::BuildInRadiant(bool allowDestruction, int* changeCnt, entity_t* entity)
+{
+ if(allowDestruction)
+ {
+ bool kill = TRUE;
+
+ for(list<DPlane *>::const_iterator chkPlane=faceList.begin(); chkPlane!=faceList.end(); chkPlane++)
+ {
+ if((*chkPlane)->m_bChkOk)
+ {
+ kill = FALSE;
+ break;
+ }
+ }
+ if(kill)
+ return NULL;
+ }
+
+ //+djbob: fixed bug when brush had no faces "phantom brush" in radiant.
+ if(faceList.size() < 4)
+ {
+ Sys_Printf("Possible Phantom Brush Found, will not rebuild\n");
+ return NULL;
+ }
+ //-djbob
+
+ QER_brush = (brush_t*)g_FuncTable.m_pfnCreateBrushHandle();
+
+ for(list<DPlane *>::const_iterator buildPlane=faceList.begin(); buildPlane!=faceList.end(); buildPlane++) {
+ if((*buildPlane)->AddToBrush_t(QER_brush) && changeCnt) {
+ (*changeCnt)++;
+ }
+ }
+
+ if(entity) {
+ g_FuncTable.m_pfnCommitBrushHandleToEntity(QER_brush, entity);
+ g_BrushTable.m_pfnBrush_Build(QER_brush);
+ g_BrushTable.m_pfnBrush_AddToList(QER_brush, g_AppDataTable.m_pfnSelectedBrushes());
+ } else {
+ g_FuncTable.m_pfnCommitBrushHandle(QER_brush);
+ }
+
+ return QER_brush;
+}
+
+void DBrush::CutByPlane(DPlane *cutPlane, DBrush **newBrush1, DBrush **newBrush2)
+{
+ if(!IsCutByPlane(cutPlane))
+ {
+ *newBrush1 = NULL;
+ *newBrush2 = NULL;
+ return;
+ }
+
+ DBrush* b1 = new DBrush;
+ DBrush* b2 = new DBrush;
+
+ for(list<DPlane *>::const_iterator parsePlane=faceList.begin(); parsePlane!=faceList.end(); parsePlane++)
+ {
+ b1->AddFace((*parsePlane)->points[0], (*parsePlane)->points[1], (*parsePlane)->points[2], NULL);
+ b2->AddFace((*parsePlane)->points[0], (*parsePlane)->points[1], (*parsePlane)->points[2], NULL);
+ }
+
+ b1->AddFace(cutPlane->points[0], cutPlane->points[1], cutPlane->points[2], NULL);
+ b2->AddFace(cutPlane->points[2], cutPlane->points[1], cutPlane->points[0], NULL);
+
+ b1->RemoveRedundantPlanes();
+ b2->RemoveRedundantPlanes();
+
+ *newBrush1 = b1;
+ *newBrush2 = b2;
+}
+
+bool DBrush::IntersectsWith(DBrush *chkBrush)
+{
+ if(pointList.size() == 0)
+ if(BuildPoints() == 0)
+ return FALSE; // invalid brush!!!!
+
+ if(chkBrush->pointList.size() == 0)
+ if(chkBrush->BuildPoints() == 0)
+ return FALSE; // invalid brush!!!!
+
+ if(!BBoxCollision(chkBrush))
+ return FALSE;
+
+ list<DPlane *>::const_iterator iplPlane;
+
+ for( iplPlane=faceList.begin(); iplPlane!=faceList.end(); iplPlane++)
+ {
+
+ bool allInFront = TRUE;
+ for(list<DPoint *>::const_iterator iPoint=chkBrush->pointList.begin(); iPoint!=chkBrush->pointList.end(); iPoint++)
+ {
+ if((*iplPlane)->DistanceToPoint((*iPoint)->_pnt) < -MAX_ROUND_ERROR)
+ {
+ allInFront = FALSE;
+ break;
+ }
+ }
+ if(allInFront)
+ return FALSE;
+ }
+
+ for( iplPlane=chkBrush->faceList.begin(); iplPlane!=chkBrush->faceList.end(); iplPlane++)
+ {
+ bool allInFront = TRUE;
+ for(list<DPoint *>::const_iterator iPoint=pointList.begin(); iPoint!=pointList.end(); iPoint++)
+ {
+ if((*iplPlane)->DistanceToPoint((*iPoint)->_pnt) < -MAX_ROUND_ERROR)
+ {
+ allInFront = FALSE;
+ break;
+ }
+ }
+ if(allInFront)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+bool DBrush::IntersectsWith(DPlane* p1, DPlane* p2, vec3_t v) {
+ vec3_t vDown = { 0, 0, -1 };
+
+ list<DPlane *>::const_iterator iplPlane;
+ for( iplPlane = faceList.begin(); iplPlane != faceList.end(); iplPlane++) {
+ DPlane* p = (*iplPlane);
+
+ vec_t d = DotProduct( p->normal, vDown );
+ if( d >= 0 ) {
+ continue;
+ }
+ if(p->PlaneIntersection(p1, p2, v)) {
+ if(PointPosition( v ) != POINT_OUT_BRUSH) {
+ return TRUE;
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+void DBrush::BuildBounds()
+{
+ if(!bBoundsBuilt)
+ {
+ if(pointList.size() == 0) // if points may not have been built, build them
+ if(BuildPoints() == 0)
+ return;
+
+ list<DPoint *>::const_iterator first = pointList.begin();
+ VectorCopy((*first)->_pnt, bbox_min);
+ VectorCopy((*first)->_pnt, bbox_max);
+
+ list<DPoint *>::const_iterator point=pointList.begin();
+ for( point++; point!=pointList.end(); point++)
+ {
+ if((*point)->_pnt[0] > bbox_max[0])
+ bbox_max[0] = (*point)->_pnt[0];
+ if((*point)->_pnt[1] > bbox_max[1])
+ bbox_max[1] = (*point)->_pnt[1];
+ if((*point)->_pnt[2] > bbox_max[2])
+ bbox_max[2] = (*point)->_pnt[2];
+
+ if((*point)->_pnt[0] < bbox_min[0])
+ bbox_min[0] = (*point)->_pnt[0];
+ if((*point)->_pnt[1] < bbox_min[1])
+ bbox_min[1] = (*point)->_pnt[1];
+ if((*point)->_pnt[2] < bbox_min[2])
+ bbox_min[2] = (*point)->_pnt[2];
+ }
+
+ bBoundsBuilt = TRUE;
+ }
+}
+
+bool DBrush::BBoxTouch(DBrush *chkBrush)
+{
+ vec3_t min1, min2;
+ vec3_t max1, max2;
+
+ GetBounds(min1, max1);
+ chkBrush->GetBounds(min2, max2);
+
+ if((min1[0] - max2[0]) > MAX_ROUND_ERROR)
+ return FALSE;
+ if((min1[1] - max2[1]) > MAX_ROUND_ERROR)
+ return FALSE;
+ if((min1[2] - max2[2]) > MAX_ROUND_ERROR)
+ return FALSE;
+
+ if((min2[0] - max1[0]) > MAX_ROUND_ERROR)
+ return FALSE;
+ if((min2[1] - max1[1]) > MAX_ROUND_ERROR)
+ return FALSE;
+ if((min2[2] - max1[2]) > MAX_ROUND_ERROR)
+ return FALSE;
+
+ int cnt = 0;
+
+ if((min2[0] - max1[0]) == 0)
+ cnt++;
+
+ if((min2[1] - max1[1]) == 0)
+ cnt++;
+
+ if((min2[2] - max1[2]) == 0)
+ cnt++;
+
+ if((min1[0] - max2[0]) == 0)
+ cnt++;
+
+ if((min1[1] - max2[1]) == 0)
+ cnt++;
+
+ if((min1[2] - max2[2]) == 0)
+ cnt++;
+
+ if(cnt > 1)
+ return FALSE;
+
+ return TRUE;
+}
+
+void DBrush::ResetChecks(list<Str>* exclusionList)
+{
+ for(list<DPlane *>::const_iterator resetPlane=faceList.begin(); resetPlane!=faceList.end(); resetPlane++)
+ {
+ bool set = FALSE;
+
+ if(exclusionList)
+ {
+ for(list<Str>::iterator eTexture = exclusionList->begin(); eTexture != exclusionList->end(); eTexture++)
+ {
+ if(strstr((*resetPlane)->texInfo.m_TextureName, eTexture->GetBuffer()))
+ {
+ set = TRUE;
+ break;
+ }
+ }
+ }
+
+ (*resetPlane)->m_bChkOk = set;
+ }
+}
+
+DPlane* DBrush::HasPlaneInverted(DPlane *chkPlane)
+{
+ for(list<DPlane *>::const_iterator brushPlane=faceList.begin(); brushPlane!=faceList.end(); brushPlane++)
+ {
+ if(**brushPlane != *chkPlane)
+ {
+ if(fabs((*brushPlane)->_d + chkPlane->_d) < 0.1)
+ return (*brushPlane);
+ }
+ }
+ return NULL;
+}
+
+bool DBrush::HasTexture(const char *textureName)
+{
+ for(list<DPlane *>::const_iterator chkPlane=faceList.begin(); chkPlane!=faceList.end(); chkPlane++)
+ {
+ if(strstr((*chkPlane)->texInfo.m_TextureName, textureName))
+ return TRUE;
+
+ }
+ return FALSE;
+}
+
+bool DBrush::IsDetail()
+{
+ for(list<DPlane *>::const_iterator chkPlane=faceList.begin(); chkPlane!=faceList.end(); chkPlane++)
+ {
+ if((*chkPlane)->texInfo.m_nContents & FACE_DETAIL)
+ return TRUE;
+
+ }
+ return FALSE;
+}
+
+void DBrush::BuildFromWinding(DWinding *w)
+{
+ if(w->numpoints < 3)
+ {
+ Sys_ERROR("Winding has invalid number of points");
+ return;
+ }
+
+ DPlane* wPlane = w->WindingPlane();
+
+ DWinding* w2;
+ w2 = w->CopyWinding();
+ int i;
+ for(i = 0; i < w2->numpoints; i++)
+ VectorAdd(w2->p[i], wPlane->normal, w2->p[i]);
+
+ AddFace(w2->p[0], w2->p[1], w2->p[2], NULL);
+ AddFace(w->p[2], w->p[1], w->p[0], NULL);
+
+ for(i = 0; i < w->numpoints-1; i++)
+ AddFace(w2->p[i], w->p[i], w->p[i+1], NULL);
+ AddFace(w2->p[w->numpoints-1], w->p[w->numpoints-1], w->p[0], NULL);
+
+ delete wPlane;
+ delete w2;
+}
+
+void DBrush::SaveToFile(FILE *pFile)
+{
+ fprintf(pFile, "{\n");
+
+ for(list<DPlane *>::const_iterator pp=faceList.begin(); pp!=faceList.end(); pp++)
+ {
+ char buffer[512];
+
+ sprintf(buffer, "( %.0f %.0f %.0f ) ( %.0f %.0f %.0f ) ( %.0f %.0f %.0f ) %s %.0f %.0f %f %f %.0f 0 0 0\n",
+ (*pp)->points[0][0], (*pp)->points[0][1], (*pp)->points[0][2],
+ (*pp)->points[1][0], (*pp)->points[1][1], (*pp)->points[1][2],
+ (*pp)->points[2][0], (*pp)->points[2][1], (*pp)->points[2][2],
+ (*pp)->texInfo.m_TextureName,
+ (*pp)->texInfo.m_fShift[0], (*pp)->texInfo.m_fShift[1],
+ (*pp)->texInfo.m_fScale[0], (*pp)->texInfo.m_fScale[0],
+ (*pp)->texInfo.m_fRotate);
+
+ fprintf(pFile, buffer);
+ }
+
+ fprintf(pFile, "}\n");
+}
+
+void DBrush::Rotate(vec3_t vOrigin, vec3_t vRotation)
+{
+ for(list<DPlane *>::const_iterator rotPlane=faceList.begin(); rotPlane!=faceList.end(); rotPlane++)
+ {
+ for(int i = 0; i < 3; i++)
+ VectorRotate((*rotPlane)->points[i], vRotation, vOrigin);
+
+ (*rotPlane)->Rebuild();
+ }
+}
+
+void DBrush::RotateAboutCentre(vec3_t vRotation)
+{
+ vec3_t min, max, centre;
+ GetBounds(min, max);
+ VectorAdd(min, max, centre);
+ VectorScale(centre, 0.5f, centre);
+
+ Rotate(centre, vRotation);
+}
+
+bool DBrush::ResetTextures(const char* textureName, float fScale[2], float fShift[2], int rotation, const char* newTextureName,
+ int bResetTextureName, int bResetScale[2], int bResetShift[2], int bResetRotation)
+{
+ if(textureName)
+ {
+ bool changed = FALSE;
+ for(list<DPlane *>::const_iterator resetPlane=faceList.begin(); resetPlane!=faceList.end(); resetPlane++)
+ {
+ if(!strcmp((*resetPlane)->texInfo.m_TextureName, textureName))
+ {
+ if(bResetTextureName)
+ strcpy((*resetPlane)->texInfo.m_TextureName, newTextureName);
+
+ if(bResetScale[0])
+ (*resetPlane)->texInfo.m_fScale[0] = fScale[0];
+ if(bResetScale[1])
+ (*resetPlane)->texInfo.m_fScale[1] = fScale[1];
+
+ if(bResetShift[0])
+ (*resetPlane)->texInfo.m_fShift[0] = fShift[0];
+ if(bResetShift[1])
+ (*resetPlane)->texInfo.m_fShift[1] = fShift[1];
+
+ if(bResetRotation)
+ (*resetPlane)->texInfo.m_fRotate = (float)rotation;
+
+ changed = TRUE;
+ }
+ }
+ return changed; // no point rebuilding unless we need to, only slows things down
+ }
+ else
+ {
+ for(list<DPlane *>::const_iterator resetPlane=faceList.begin(); resetPlane!=faceList.end(); resetPlane++)
+ {
+ if(bResetTextureName)
+ strcpy((*resetPlane)->texInfo.m_TextureName, newTextureName);
+
+ if(bResetScale[0])
+ (*resetPlane)->texInfo.m_fScale[0] = fScale[0];
+ if(bResetScale[1])
+ (*resetPlane)->texInfo.m_fScale[1] = fScale[1];
+
+ if(bResetShift[0])
+ (*resetPlane)->texInfo.m_fShift[0] = fShift[0];
+ if(bResetShift[1])
+ (*resetPlane)->texInfo.m_fShift[1] = fShift[1];
+
+ if(bResetRotation)
+ (*resetPlane)->texInfo.m_fRotate = (float)rotation;
+ }
+ return TRUE;
+ }
+}
+
+bool DBrush::operator ==(DBrush* other)
+{
+ list<DPlane *>::const_iterator chkPlane;
+
+ for(chkPlane=faceList.begin(); chkPlane!=faceList.end(); chkPlane++)
+ {
+ if(!other->HasPlane((*chkPlane)))
+ return FALSE;
+ }
+
+ for(chkPlane=faceList.begin(); chkPlane!=faceList.end(); chkPlane++)
+ {
+ if(!HasPlane((*chkPlane)))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+DPlane* DBrush::AddFace(vec3_t va, vec3_t vb, vec3_t vc, const char *textureName, bool bDetail)
+{
+ bBoundsBuilt = FALSE;
+ DPlane* newFace = new DPlane(va, vb, vc, textureName, bDetail);
+ faceList.push_back(newFace);
+
+ return newFace;
+}
+
+DPlane* DBrush::FindPlaneWithClosestNormal( vec_t* normal ) {
+ vec_t bestDot = -2;
+ DPlane* bestDotPlane = NULL;
+ list<DPlane *>::const_iterator chkPlane;
+ for( chkPlane = faceList.begin(); chkPlane != faceList.end(); chkPlane++ ) {
+ DPlane* pPlane = (*chkPlane);
+
+ vec_t dot = DotProduct( pPlane->normal, normal );
+ if( dot > bestDot ) {
+ bestDot = dot;
+ bestDotPlane = pPlane;
+ }
+ }
+
+ return bestDotPlane;
+}
+
+int DBrush::FindPointsForPlane( DPlane* plane, DPoint** pnts, int maxpnts ) {
+ int numpnts = 0;
+
+ if(!maxpnts) {
+ return 0;
+ }
+
+ BuildPoints();
+
+ for( list<DPoint *>::const_iterator points = pointList.begin(); points != pointList.end(); points++ ) {
+ DPoint* point = (*points);
+
+ if( fabs(plane->DistanceToPoint( point->_pnt )) < MAX_ROUND_ERROR ) {
+ pnts[numpnts] = point;
+ numpnts++;
+
+ if(numpnts >= maxpnts) {
+ return numpnts;
+ }
+
+ }
+ }
+
+ return numpnts;
+}
+
+void DBrush::RemovePlane( DPlane* plane ) {
+ bBoundsBuilt = FALSE;
+ for( list<DPlane *>::const_iterator deadPlane = faceList.begin(); deadPlane != faceList.end(); deadPlane++ ) {
+ if(*deadPlane == plane) {
+ delete *deadPlane;
+ faceList.remove( plane );
+ }
+ }
+}
+
+void DBrush::RemoveFromRadiant( void ) {
+ if(QER_brush) {
+ g_FuncTable.m_pfnDeleteBrushHandle(QER_brush);
+ }
+}
-/*\r
-BobToolz plugin for GtkRadiant\r
-Copyright (C) 2001 Gordon Biggans\r
-\r
-This library is free software; you can redistribute it and/or\r
-modify it under the terms of the GNU Lesser General Public\r
-License as published by the Free Software Foundation; either\r
-version 2.1 of the License, or (at your option) any later version.\r
-\r
-This library is distributed in the hope that it will be useful,\r
-but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
-Lesser General Public License for more details.\r
-\r
-You should have received a copy of the GNU Lesser General Public\r
-License along with this library; if not, write to the Free Software\r
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
-*/\r
-\r
-// DEPair.cpp: implementation of the DEPair class.\r
-//\r
-//////////////////////////////////////////////////////////////////////\r
-\r
-#include "StdAfx.h"\r
-#include "DEPair.h"\r
-\r
-//////////////////////////////////////////////////////////////////////\r
-// Construction/Destruction\r
-//////////////////////////////////////////////////////////////////////\r
-\r
-DEPair::DEPair()\r
-{\r
-\r
-}\r
-\r
-DEPair::~DEPair()\r
-{\r
-\r
-}\r
-\r
-//////////////////////////////////////////////////////////////////////\r
-// Implementation\r
-//////////////////////////////////////////////////////////////////////\r
-\r
-void DEPair::Build(char *pKey, char *pValue)\r
-{\r
- key = pKey;\r
- value = pValue;\r
-}\r
+/*
+BobToolz plugin for GtkRadiant
+Copyright (C) 2001 Gordon Biggans
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+// DEPair.cpp: implementation of the DEPair class.
+//
+//////////////////////////////////////////////////////////////////////
+
+#include "StdAfx.h"
+#include "DEPair.h"
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+DEPair::DEPair()
+{
+
+}
+
+DEPair::~DEPair()
+{
+
+}
+
+//////////////////////////////////////////////////////////////////////
+// Implementation
+//////////////////////////////////////////////////////////////////////
+
+void DEPair::Build(char *pKey, char *pValue)
+{
+ key = pKey;
+ value = pValue;
+}
-/*\r
-BobToolz plugin for GtkRadiant\r
-Copyright (C) 2001 Gordon Biggans\r
-\r
-This library is free software; you can redistribute it and/or\r
-modify it under the terms of the GNU Lesser General Public\r
-License as published by the Free Software Foundation; either\r
-version 2.1 of the License, or (at your option) any later version.\r
-\r
-This library is distributed in the hope that it will be useful,\r
-but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
-Lesser General Public License for more details.\r
-\r
-You should have received a copy of the GNU Lesser General Public\r
-License along with this library; if not, write to the Free Software\r
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
-*/\r
-\r
-// DEntity.cpp: implementation of the DEntity class.\r
-//\r
-//////////////////////////////////////////////////////////////////////\r
-\r
-#include "StdAfx.h"\r
-\r
-#ifdef _WIN32\r
-#pragma warning(disable : 4786)\r
-#endif\r
-\r
-#include "DEntity.h"\r
-\r
-#include "dialogs-gtk.h"\r
-#include "misc.h"\r
-#include "CPortals.h"\r
-\r
-const char* brushEntityList[] = {\r
- "worldspawn",\r
- "trigger_always",\r
- "trigger_hurt",\r
- "trigger_multiple",\r
- "trigger_push",\r
- "trigger_teleport",\r
- "func_bobbing",\r
- "func_button",\r
- "func_door",\r
- "func_group",\r
- "func_pendulum",\r
- "func_plat",\r
- "func_rotating",\r
- "func_static",\r
- "func_timer",\r
- "func_train",\r
- 0\r
-};\r
-\r
-//////////////////////////////////////////////////////////////////////\r
-// Construction/Destruction\r
-//////////////////////////////////////////////////////////////////////\r
-\r
-DEntity::DEntity(char *classname, int ID)\r
-{\r
- SetClassname(classname);\r
- m_nID = ID;\r
- QER_Entity = NULL;\r
-}\r
-\r
-DEntity::~DEntity()\r
-{\r
- ClearPatches();\r
- ClearBrushes();\r
- ClearEPairs();\r
-}\r
-\r
-//////////////////////////////////////////////////////////////////////\r
-// Implementation\r
-//////////////////////////////////////////////////////////////////////\r
-\r
-void DEntity::ClearBrushes()\r
-{\r
- for(list<DBrush *>::const_iterator deadBrush=brushList.begin(); deadBrush!=brushList.end(); deadBrush++)\r
- {\r
- delete *deadBrush;\r
- }\r
- brushList.clear();\r
-}\r
-\r
-void DEntity::ClearPatches()\r
-{\r
- for(list<DPatch *>::const_iterator deadPatch=patchList.begin(); deadPatch!=patchList.end(); deadPatch++)\r
- {\r
- delete *deadPatch;\r
- }\r
- patchList.clear();\r
-}\r
-\r
-DPatch* DEntity::NewPatch()\r
-{\r
- DPatch* newPatch = new DPatch;\r
-\r
- patchList.push_back(newPatch);\r
-\r
- return newPatch;\r
-}\r
-\r
-DBrush* DEntity::NewBrush(int ID)\r
-{\r
- DBrush* newBrush = new DBrush(ID);\r
-\r
- brushList.push_back(newBrush);\r
-\r
- return newBrush;\r
-}\r
-\r
-char* getNextBracket(char* s)\r
-{\r
- char* p = s;\r
- while(*p)\r
- {\r
- p++;\r
- if(*p == '(')\r
- break;\r
- }\r
-\r
- return p;\r
-}\r
-\r
-bool DEntity::LoadFromPrt(char *filename)\r
-{\r
- CPortals portals;\r
- strcpy(portals.fn, filename);\r
- portals.Load();\r
-\r
- if(portals.node_count == 0)\r
- return FALSE;\r
-\r
- ClearBrushes();\r
- ClearEPairs();\r
- \r
- bool build = false;\r
- for(unsigned int i = 0; i < portals.node_count; i++)\r
- {\r
- build = false;\r
- DBrush* brush = NewBrush();\r
-\r
- for(unsigned int j = 0; j < portals.node[i].portal_count; j++)\r
- {\r
- for(unsigned int k = 0; k < portals.node[i].portal[j].point_count-2; k++) \r
- {\r
- vec3_t v1, v2, normal, n;\r
- VectorSubtract(portals.node[i].portal[j].point[k+2].p, portals.node[i].portal[j].point[k+1].p, v1);\r
- VectorSubtract(portals.node[i].portal[j].point[k].p, portals.node[i].portal[j].point[k+1].p, v2);\r
- CrossProduct(v1, v2, n);\r
- VectorNormalize(n, v2);\r
-\r
- if(k == 0) \r
- {\r
- VectorCopy(v2, normal);\r
- }\r
- else\r
- {\r
- VectorSubtract(v2, normal, v1);\r
- if(VectorLength(v1) > 0.01)\r
- {\r
- build = true;\r
- break;\r
- }\r
- }\r
- }\r
-\r
- if(!build)\r
- brush->AddFace(portals.node[i].portal[j].point[2].p, portals.node[i].portal[j].point[1].p, portals.node[i].portal[j].point[0].p, "textures/common/caulk", FALSE);\r
- else\r
- brush->AddFace(portals.node[i].portal[j].point[0].p, portals.node[i].portal[j].point[1].p, portals.node[i].portal[j].point[2].p, "textures/common/caulk", FALSE);\r
- }\r
- if(build)\r
- brush->BuildInRadiant(FALSE, NULL);\r
- }\r
-\r
- return TRUE;\r
-}\r
-\r
-DPlane* DEntity::AddFaceToBrush(vec3_t va, vec3_t vb, vec3_t vc, _QERFaceData* faceData, int ID)\r
-{\r
- DBrush* buildBrush = GetBrushForID(ID);\r
- return buildBrush->AddFace(va, vb, vc, faceData);\r
- // slow, dont use much\r
-}\r
-\r
-DBrush* DEntity::GetBrushForID(int ID)\r
-{\r
- DBrush* buildBrush = NULL;\r
-\r
- for(list<DBrush *>::const_iterator chkBrush=brushList.begin(); chkBrush!=brushList.end(); chkBrush++)\r
- {\r
- if((*chkBrush)->m_nBrushID == ID)\r
- {\r
- buildBrush = (*chkBrush);\r
- break;\r
- }\r
- }\r
-\r
- if(!buildBrush)\r
- buildBrush = NewBrush(ID);\r
-\r
- return buildBrush;\r
-}\r
-\r
-void DEntity::LoadSelectedBrushes()\r
-{\r
- ClearBrushes();\r
- ClearEPairs();\r
-\r
- int count = g_FuncTable.m_pfnAllocateSelectedBrushHandles();\r
-\r
- for(int i = 0; i < count; i++) {\r
- brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(i);\r
-\r
- if(brush->pPatch)\r
- continue;\r
-\r
- DBrush* loadBrush = NewBrush(i);\r
- loadBrush->LoadFromBrush_t(brush, TRUE);\r
- }\r
-\r
- g_FuncTable.m_pfnReleaseSelectedBrushHandles();\r
-}\r
-\r
-void DEntity::LoadSelectedPatches()\r
-{\r
- ClearPatches();\r
- ClearEPairs();\r
-\r
- int count = g_FuncTable.m_pfnAllocateSelectedPatchHandles();\r
-\r
- for(int i = 0; i < count; i++)\r
- {\r
- //$ FIXME: m_pfnGetPatchHandle\r
- patchMesh_t *pmesh = (patchMesh_t*)g_FuncTable.m_pfnGetPatchData(i);\r
-\r
- DPatch* loadPatch = NewPatch();\r
- loadPatch->LoadFromBrush_t(pmesh->pSymbiot);\r
- }\r
-\r
- g_FuncTable.m_pfnReleasePatchHandles();\r
-}\r
-\r
-bool* DEntity::BuildIntersectList()\r
-{\r
- int max = GetIDMax();\r
- if(max == 0)\r
- return NULL;\r
-\r
- bool* pbIntList = new bool[max];\r
- memset(pbIntList, 0, sizeof(bool)*(max));\r
-\r
- for(list<DBrush *>::const_iterator pB1=brushList.begin(); pB1!=brushList.end(); pB1++)\r
- {\r
- list<DBrush *>::const_iterator pB2=pB1;\r
- for(pB2++; pB2!=brushList.end(); pB2++)\r
- {\r
- if((*pB1)->IntersectsWith((*pB2)))\r
- {\r
- pbIntList[(*pB1)->m_nBrushID] = TRUE;\r
- pbIntList[(*pB2)->m_nBrushID] = TRUE;\r
- }\r
- }\r
- }\r
-\r
- return pbIntList;\r
-}\r
-\r
-bool* DEntity::BuildDuplicateList()\r
-{\r
- int max = GetIDMax();\r
- if(max == 0)\r
- return NULL;\r
-\r
- bool* pbDupList = new bool[max];\r
- memset(pbDupList, 0, sizeof(bool)*(max));\r
-\r
- for(list<DBrush *>::const_iterator pB1=brushList.begin(); pB1!=brushList.end(); pB1++)\r
- {\r
- list<DBrush *>::const_iterator pB2=pB1;\r
- for(pB2++; pB2!=brushList.end(); pB2++)\r
- {\r
- if(**pB1 == *pB2)\r
- {\r
- pbDupList[(*pB1)->m_nBrushID] = TRUE;\r
- pbDupList[(*pB2)->m_nBrushID] = TRUE;\r
- }\r
- }\r
- }\r
-\r
- return pbDupList;\r
-}\r
-\r
-void DEntity::SelectBrushes(bool *selectList)\r
-{\r
- if(selectList == NULL)\r
- return;\r
-\r
- g_FuncTable.m_pfnDeselectAllBrushes();\r
-\r
- g_FuncTable.m_pfnAllocateActiveBrushHandles();\r
-\r
- for(std::list<DBrush *>::const_iterator pBrush=brushList.begin(); pBrush!=brushList.end(); pBrush++)\r
- {\r
- if(selectList[(*pBrush)->m_nBrushID])\r
- g_FuncTable.m_pfnSelectBrush((*pBrush)->QER_brush);\r
- }\r
- g_FuncTable.m_pfnReleaseActiveBrushHandles();\r
-}\r
-\r
-bool DEntity::LoadFromEntity(int id, bool bLoadPatches) {\r
- return LoadFromEntity((entity_t*)g_FuncTable.m_pfnGetEntityHandle(id), bLoadPatches);\r
-}\r
-\r
-bool DEntity::LoadFromEntity(entity_t* ent, bool bLoadPatches) {\r
- ClearPatches();\r
- ClearBrushes();\r
- ClearEPairs();\r
-\r
- QER_Entity = ent;\r
-\r
- epair_t* epl = *g_EntityTable.m_pfnGetEntityKeyValList(QER_Entity);\r
- LoadEPairList(epl);\r
-\r
- bool keep = FALSE;\r
- int i;\r
- for(i = 0; brushEntityList[i]; i++)\r
- {\r
- if(!stricmp(brushEntityList[i], m_Classname))\r
- {\r
- keep = TRUE;\r
- break;\r
- }\r
- }\r
-\r
- if(!keep)\r
- return FALSE;\r
-\r
- int count = g_FuncTable.m_pfnAllocateEntityBrushHandles(QER_Entity);\r
-\r
- for(i = 0; i < count; i++)\r
- {\r
-\r
- brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetEntityBrushHandle(i);\r
-\r
- if(brush == NULL) {\r
- DoMessageBox("GTKRadiant returned a NULL pointer, NOT a good sign", "WARNING!!!", MB_OK);\r
- continue;\r
- }\r
-\r
- if(brush->pPatch)\r
- {\r
- if(bLoadPatches)\r
- {\r
- DPatch* loadPatch = NewPatch();\r
- loadPatch->LoadFromBrush_t(brush);\r
- }\r
- }\r
- else\r
- {\r
- DBrush* loadBrush = NewBrush(i);\r
- loadBrush->LoadFromBrush_t(brush, TRUE);\r
- }\r
- }\r
-\r
- g_FuncTable.m_pfnReleaseEntityBrushHandles();\r
-\r
- return TRUE;\r
-}\r
-\r
-void DEntity::RemoveNonCheckBrushes(list<Str>* exclusionList, bool useDetail)\r
-{\r
- list<DBrush *>::iterator chkBrush=brushList.begin();\r
-\r
- while( chkBrush!=brushList.end() )\r
- {\r
- if(!useDetail)\r
- {\r
- if((*chkBrush)->IsDetail())\r
- {\r
- delete *chkBrush;\r
- chkBrush = brushList.erase(chkBrush);\r
- continue;\r
- }\r
- }\r
-\r
- list<Str>::iterator eTexture;\r
-\r
- for( eTexture=exclusionList->begin(); eTexture!=exclusionList->end(); eTexture++ )\r
- {\r
- if((*chkBrush)->HasTexture((*eTexture).GetBuffer()))\r
- {\r
- delete *chkBrush;\r
- chkBrush = brushList.erase(chkBrush);\r
- break;\r
- }\r
- }\r
-\r
- if( eTexture == exclusionList->end() )\r
- chkBrush++;\r
- }\r
-}\r
-\r
-void DEntity::ResetChecks(list<Str>* exclusionList)\r
-{\r
- for(list<DBrush *>::const_iterator resetBrush=brushList.begin(); resetBrush!=brushList.end(); resetBrush++)\r
- {\r
- (*resetBrush)->ResetChecks(exclusionList);\r
- }\r
-}\r
-\r
-int DEntity::FixBrushes(bool rebuild)\r
-{\r
- g_FuncTable.m_pfnAllocateActiveBrushHandles();\r
-\r
- int cnt = 0;\r
-\r
- for(list<DBrush *>::const_iterator fixBrush=brushList.begin(); fixBrush!=brushList.end(); fixBrush++)\r
- {\r
- int count = (*fixBrush)->RemoveRedundantPlanes();\r
- if(count)\r
- {\r
- cnt += count;\r
- if(rebuild)\r
- {\r
- g_FuncTable.m_pfnDeleteBrushHandle((*fixBrush)->QER_brush);\r
-\r
- (*fixBrush)->BuildInRadiant(FALSE, NULL);\r
- }\r
- }\r
- }\r
-\r
- g_FuncTable.m_pfnReleaseActiveBrushHandles();\r
-\r
- return cnt;\r
-}\r
-\r
-void DEntity::BuildInRadiant(bool allowDestruction)\r
-{\r
- bool makeEntity = strcmp(m_Classname, "worldspawn") ? true : false;\r
-\r
- if(makeEntity)\r
- {\r
- entity_t* pE = (entity_t*)g_FuncTable.m_pfnCreateEntityHandle();\r
-\r
- epair_t* pEpS = GetNextChainItem(NULL, "classname", m_Classname);\r
-\r
- epair_t* pEp = pEpS;\r
-\r
- for(list<DEPair* >::const_iterator buildEPair=epairList.begin(); buildEPair!=epairList.end(); buildEPair++)\r
- {\r
- pEp = GetNextChainItem(pEp, (*buildEPair)->key, (*buildEPair)->value);\r
- }\r
-\r
- g_EntityTable.m_pfnSetEntityKeyValList(pE, pEpS);\r
-\r
- g_FuncTable.m_pfnCommitEntityHandleToMap(pE);\r
-\r
- for(list<DBrush *>::const_iterator buildBrush=brushList.begin(); buildBrush!=brushList.end(); buildBrush++)\r
- (*buildBrush)->BuildInRadiant(allowDestruction, NULL, pE);\r
-\r
- for(list<DPatch *>::const_iterator buildPatch=patchList.begin(); buildPatch!=patchList.end(); buildPatch++)\r
- (*buildPatch)->BuildInRadiant(pE);\r
-\r
- QER_Entity = pE;\r
- }\r
- else\r
- {\r
- for(list<DBrush *>::const_iterator buildBrush=brushList.begin(); buildBrush!=brushList.end(); buildBrush++)\r
- (*buildBrush)->BuildInRadiant(allowDestruction, NULL);\r
-\r
- for(list<DPatch *>::const_iterator buildPatch=patchList.begin(); buildPatch!=patchList.end(); buildPatch++)\r
- (*buildPatch)->BuildInRadiant();\r
- }\r
-}\r
-\r
-\r
-\r
-int DEntity::GetIDMax( void ) {\r
- int max = -1;\r
- for(list<DBrush *>::const_iterator cntBrush=brushList.begin(); cntBrush!=brushList.end(); cntBrush++) {\r
- if((*cntBrush)->m_nBrushID > max)\r
- max = (*cntBrush)->m_nBrushID;\r
- }\r
- return max+1;\r
-}\r
-\r
-void DEntity::SetClassname( char *classname ) {\r
- m_Classname = classname;\r
-}\r
-\r
-void DEntity::SaveToFile(FILE *pFile)\r
-{\r
- fprintf(pFile, "{\n");\r
-\r
- fprintf(pFile, "\"classname\" \"%s\"\n", (const char *)m_Classname);\r
-\r
- for(list<DEPair *>::const_iterator ep=epairList.begin(); ep!=epairList.end(); ep++)\r
- {\r
- fprintf(pFile, "\"%s\" \"%s\"\n", (const char *)(*ep)->key, (const char *)(*ep)->value);\r
- }\r
-\r
- for(list<DBrush *>::const_iterator bp=brushList.begin(); bp!=brushList.end(); bp++)\r
- {\r
- (*bp)->SaveToFile(pFile);\r
- }\r
-\r
- fprintf(pFile, "}\n");\r
-}\r
-\r
-void DEntity::ClearEPairs()\r
-{\r
- for(list<DEPair *>::const_iterator deadEPair=epairList.begin(); deadEPair!=epairList.end(); deadEPair++)\r
- {\r
- delete (*deadEPair);\r
- }\r
- epairList.clear();\r
-}\r
-\r
-void DEntity::AddEPair(char *key, char *value) { \r
- DEPair* newEPair; \r
- newEPair = FindEPairByKey( key );\r
- if(!newEPair) {\r
- newEPair = new DEPair;\r
- newEPair->Build(key, value);\r
- epairList.push_back(newEPair);\r
- } else {\r
- newEPair->Build(key, value);\r
- }\r
-}\r
-\r
-void DEntity::LoadEPairList(epair_t *epl)\r
-{\r
- epair_t* ep = epl;\r
- while(ep)\r
- {\r
- if(!strcmp(ep->key, "classname"))\r
- SetClassname(ep->value);\r
- else \r
- AddEPair(ep->key, ep->value);\r
-\r
- ep = ep->next;\r
- }\r
-}\r
-\r
-bool DEntity::ResetTextures(const char* textureName, float fScale[2], float fShift[2], int rotation, const char* newTextureName, \r
- int bResetTextureName, int bResetScale[2], int bResetShift[2], int bResetRotation, bool rebuild)\r
-{\r
- g_FuncTable.m_pfnDeselectAllBrushes();\r
-\r
- g_FuncTable.m_pfnAllocateActiveBrushHandles();\r
-\r
- bool reset = FALSE;\r
-\r
- for(list<DBrush *>::const_iterator resetBrush=brushList.begin(); resetBrush!=brushList.end(); resetBrush++)\r
- {\r
- bool tmp = (*resetBrush)->ResetTextures(textureName, fScale, fShift, rotation, newTextureName, \r
- bResetTextureName, bResetScale, bResetShift, bResetRotation);\r
-\r
- if(tmp)\r
- {\r
- reset = TRUE;\r
-\r
- if(rebuild)\r
- {\r
- entity_t *pE = (*resetBrush)->QER_brush->owner; \r
- g_FuncTable.m_pfnDeleteBrushHandle((*resetBrush)->QER_brush);\r
- (*resetBrush)->BuildInRadiant(FALSE, NULL, pE->entityId == 0 ? NULL : pE);\r
-\r
- if( pE->entityId == 0 ? NULL : pE )\r
- {\r
- }\r
- }\r
- }\r
- }\r
-\r
- if(bResetTextureName)\r
- {\r
- for(list<DPatch *>::const_iterator resetPatch=patchList.begin(); resetPatch!=patchList.end(); resetPatch++)\r
- {\r
- bool tmp = (*resetPatch)->ResetTextures(textureName, newTextureName);\r
-\r
- if(tmp)\r
- {\r
- reset = TRUE;\r
-\r
- if(rebuild)\r
- {\r
- entity_t *pE = (*resetPatch)->QER_brush->owner; \r
- g_FuncTable.m_pfnDeleteBrushHandle((*resetPatch)->QER_brush);\r
- (*resetPatch)->BuildInRadiant(pE->entityId == 0 ? NULL : pE);\r
- }\r
- }\r
- }\r
- }\r
-\r
- g_FuncTable.m_pfnReleaseActiveBrushHandles();\r
-\r
- return reset;\r
-}\r
-\r
-DEPair* DEntity::FindEPairByKey(const char* keyname)\r
-{\r
- for(list<DEPair *>::const_iterator ep=epairList.begin(); ep!=epairList.end(); ep++)\r
- {\r
- char* c = (*ep)->key;\r
- if(!strcmp(c, keyname))\r
- return *ep;\r
- }\r
- return NULL;\r
-}\r
-\r
-void DEntity::RemoveFromRadiant()\r
-{\r
- g_EntityTable.m_pfnEntity_Free( (entity_t*)QER_Entity );\r
-\r
- QER_Entity = NULL;\r
-}\r
-\r
-void DEntity::SpawnString(const char* key, const char* defaultstring, const char** out)\r
-{\r
- DEPair* pEP = FindEPairByKey(key);\r
- if(pEP) {\r
- *out = pEP->value;\r
- } else {\r
- *out = defaultstring;\r
- }\r
-}\r
-\r
-void DEntity::SpawnInt(const char* key, const char* defaultstring, int* out)\r
-{\r
- DEPair* pEP = FindEPairByKey(key);\r
- if(pEP) {\r
- *out = atoi(pEP->value);\r
- } else {\r
- *out = atoi(defaultstring);\r
- }\r
-}\r
-\r
-void DEntity::SpawnFloat(const char* key, const char* defaultstring, float* out)\r
-{\r
- DEPair* pEP = FindEPairByKey(key);\r
- if(pEP) {\r
- *out = static_cast< float >( atof( pEP->value ) );\r
- } else {\r
- *out = static_cast< float >( atof(defaultstring) );\r
- }\r
-}\r
-\r
-void DEntity::SpawnVector(const char* key, const char* defaultstring, vec_t* out)\r
-{\r
- DEPair* pEP = FindEPairByKey(key);\r
- if(pEP) {\r
- sscanf(pEP->value, "%f %f %f", &out[0], &out[1], &out[2]);\r
- } else {\r
- sscanf(defaultstring, "%f %f %f", &out[0], &out[1], &out[2]);\r
- }\r
-}\r
-\r
-int DEntity::GetBrushCount( void ) {\r
- return brushList.size();\r
-}\r
-\r
-DBrush* DEntity::FindBrushByPointer( brush_t* brush ) {\r
- for(list<DBrush *>::const_iterator listBrush = brushList.begin(); listBrush != brushList.end(); listBrush++) {\r
- DBrush* pBrush = (*listBrush);\r
- if(pBrush->QER_brush == brush) {\r
- return pBrush;\r
- }\r
- }\r
- return NULL;\r
-}\r
+/*
+BobToolz plugin for GtkRadiant
+Copyright (C) 2001 Gordon Biggans
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+// DEntity.cpp: implementation of the DEntity class.
+//
+//////////////////////////////////////////////////////////////////////
+
+#include "StdAfx.h"
+
+#ifdef _WIN32
+#pragma warning(disable : 4786)
+#endif
+
+#include "DEntity.h"
+
+#include "dialogs-gtk.h"
+#include "misc.h"
+#include "CPortals.h"
+
+const char* brushEntityList[] = {
+ "worldspawn",
+ "trigger_always",
+ "trigger_hurt",
+ "trigger_multiple",
+ "trigger_push",
+ "trigger_teleport",
+ "func_bobbing",
+ "func_button",
+ "func_door",
+ "func_group",
+ "func_pendulum",
+ "func_plat",
+ "func_rotating",
+ "func_static",
+ "func_timer",
+ "func_train",
+ 0
+};
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+DEntity::DEntity(char *classname, int ID)
+{
+ SetClassname(classname);
+ m_nID = ID;
+ QER_Entity = NULL;
+}
+
+DEntity::~DEntity()
+{
+ ClearPatches();
+ ClearBrushes();
+ ClearEPairs();
+}
+
+//////////////////////////////////////////////////////////////////////
+// Implementation
+//////////////////////////////////////////////////////////////////////
+
+void DEntity::ClearBrushes()
+{
+ for(list<DBrush *>::const_iterator deadBrush=brushList.begin(); deadBrush!=brushList.end(); deadBrush++)
+ {
+ delete *deadBrush;
+ }
+ brushList.clear();
+}
+
+void DEntity::ClearPatches()
+{
+ for(list<DPatch *>::const_iterator deadPatch=patchList.begin(); deadPatch!=patchList.end(); deadPatch++)
+ {
+ delete *deadPatch;
+ }
+ patchList.clear();
+}
+
+DPatch* DEntity::NewPatch()
+{
+ DPatch* newPatch = new DPatch;
+
+ patchList.push_back(newPatch);
+
+ return newPatch;
+}
+
+DBrush* DEntity::NewBrush(int ID)
+{
+ DBrush* newBrush = new DBrush(ID);
+
+ brushList.push_back(newBrush);
+
+ return newBrush;
+}
+
+char* getNextBracket(char* s)
+{
+ char* p = s;
+ while(*p)
+ {
+ p++;
+ if(*p == '(')
+ break;
+ }
+
+ return p;
+}
+
+bool DEntity::LoadFromPrt(char *filename)
+{
+ CPortals portals;
+ strcpy(portals.fn, filename);
+ portals.Load();
+
+ if(portals.node_count == 0)
+ return FALSE;
+
+ ClearBrushes();
+ ClearEPairs();
+
+ bool build = false;
+ for(unsigned int i = 0; i < portals.node_count; i++)
+ {
+ build = false;
+ DBrush* brush = NewBrush();
+
+ for(unsigned int j = 0; j < portals.node[i].portal_count; j++)
+ {
+ for(unsigned int k = 0; k < portals.node[i].portal[j].point_count-2; k++)
+ {
+ vec3_t v1, v2, normal, n;
+ VectorSubtract(portals.node[i].portal[j].point[k+2].p, portals.node[i].portal[j].point[k+1].p, v1);
+ VectorSubtract(portals.node[i].portal[j].point[k].p, portals.node[i].portal[j].point[k+1].p, v2);
+ CrossProduct(v1, v2, n);
+ VectorNormalize(n, v2);
+
+ if(k == 0)
+ {
+ VectorCopy(v2, normal);
+ }
+ else
+ {
+ VectorSubtract(v2, normal, v1);
+ if(VectorLength(v1) > 0.01)
+ {
+ build = true;
+ break;
+ }
+ }
+ }
+
+ if(!build)
+ brush->AddFace(portals.node[i].portal[j].point[2].p, portals.node[i].portal[j].point[1].p, portals.node[i].portal[j].point[0].p, "textures/common/caulk", FALSE);
+ else
+ brush->AddFace(portals.node[i].portal[j].point[0].p, portals.node[i].portal[j].point[1].p, portals.node[i].portal[j].point[2].p, "textures/common/caulk", FALSE);
+ }
+ if(build)
+ brush->BuildInRadiant(FALSE, NULL);
+ }
+
+ return TRUE;
+}
+
+DPlane* DEntity::AddFaceToBrush(vec3_t va, vec3_t vb, vec3_t vc, _QERFaceData* faceData, int ID)
+{
+ DBrush* buildBrush = GetBrushForID(ID);
+ return buildBrush->AddFace(va, vb, vc, faceData);
+ // slow, dont use much
+}
+
+DBrush* DEntity::GetBrushForID(int ID)
+{
+ DBrush* buildBrush = NULL;
+
+ for(list<DBrush *>::const_iterator chkBrush=brushList.begin(); chkBrush!=brushList.end(); chkBrush++)
+ {
+ if((*chkBrush)->m_nBrushID == ID)
+ {
+ buildBrush = (*chkBrush);
+ break;
+ }
+ }
+
+ if(!buildBrush)
+ buildBrush = NewBrush(ID);
+
+ return buildBrush;
+}
+
+void DEntity::LoadSelectedBrushes()
+{
+ ClearBrushes();
+ ClearEPairs();
+
+ int count = g_FuncTable.m_pfnAllocateSelectedBrushHandles();
+
+ for(int i = 0; i < count; i++) {
+ brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(i);
+
+ if(brush->pPatch)
+ continue;
+
+ DBrush* loadBrush = NewBrush(i);
+ loadBrush->LoadFromBrush_t(brush, TRUE);
+ }
+
+ g_FuncTable.m_pfnReleaseSelectedBrushHandles();
+}
+
+void DEntity::LoadSelectedPatches()
+{
+ ClearPatches();
+ ClearEPairs();
+
+ int count = g_FuncTable.m_pfnAllocateSelectedPatchHandles();
+
+ for(int i = 0; i < count; i++)
+ {
+ //$ FIXME: m_pfnGetPatchHandle
+ patchMesh_t *pmesh = (patchMesh_t*)g_FuncTable.m_pfnGetPatchData(i);
+
+ DPatch* loadPatch = NewPatch();
+ loadPatch->LoadFromBrush_t(pmesh->pSymbiot);
+ }
+
+ g_FuncTable.m_pfnReleasePatchHandles();
+}
+
+bool* DEntity::BuildIntersectList()
+{
+ int max = GetIDMax();
+ if(max == 0)
+ return NULL;
+
+ bool* pbIntList = new bool[max];
+ memset(pbIntList, 0, sizeof(bool)*(max));
+
+ for(list<DBrush *>::const_iterator pB1=brushList.begin(); pB1!=brushList.end(); pB1++)
+ {
+ list<DBrush *>::const_iterator pB2=pB1;
+ for(pB2++; pB2!=brushList.end(); pB2++)
+ {
+ if((*pB1)->IntersectsWith((*pB2)))
+ {
+ pbIntList[(*pB1)->m_nBrushID] = TRUE;
+ pbIntList[(*pB2)->m_nBrushID] = TRUE;
+ }
+ }
+ }
+
+ return pbIntList;
+}
+
+bool* DEntity::BuildDuplicateList()
+{
+ int max = GetIDMax();
+ if(max == 0)
+ return NULL;
+
+ bool* pbDupList = new bool[max];
+ memset(pbDupList, 0, sizeof(bool)*(max));
+
+ for(list<DBrush *>::const_iterator pB1=brushList.begin(); pB1!=brushList.end(); pB1++)
+ {
+ list<DBrush *>::const_iterator pB2=pB1;
+ for(pB2++; pB2!=brushList.end(); pB2++)
+ {
+ if(**pB1 == *pB2)
+ {
+ pbDupList[(*pB1)->m_nBrushID] = TRUE;
+ pbDupList[(*pB2)->m_nBrushID] = TRUE;
+ }
+ }
+ }
+
+ return pbDupList;
+}
+
+void DEntity::SelectBrushes(bool *selectList)
+{
+ if(selectList == NULL)
+ return;
+
+ g_FuncTable.m_pfnDeselectAllBrushes();
+
+ g_FuncTable.m_pfnAllocateActiveBrushHandles();
+
+ for(std::list<DBrush *>::const_iterator pBrush=brushList.begin(); pBrush!=brushList.end(); pBrush++)
+ {
+ if(selectList[(*pBrush)->m_nBrushID])
+ g_FuncTable.m_pfnSelectBrush((*pBrush)->QER_brush);
+ }
+ g_FuncTable.m_pfnReleaseActiveBrushHandles();
+}
+
+bool DEntity::LoadFromEntity(int id, bool bLoadPatches) {
+ return LoadFromEntity((entity_t*)g_FuncTable.m_pfnGetEntityHandle(id), bLoadPatches);
+}
+
+bool DEntity::LoadFromEntity(entity_t* ent, bool bLoadPatches) {
+ ClearPatches();
+ ClearBrushes();
+ ClearEPairs();
+
+ QER_Entity = ent;
+
+ epair_t* epl = *g_EntityTable.m_pfnGetEntityKeyValList(QER_Entity);
+ LoadEPairList(epl);
+
+ bool keep = FALSE;
+ int i;
+ for(i = 0; brushEntityList[i]; i++)
+ {
+ if(!stricmp(brushEntityList[i], m_Classname))
+ {
+ keep = TRUE;
+ break;
+ }
+ }
+
+ if(!keep)
+ return FALSE;
+
+ int count = g_FuncTable.m_pfnAllocateEntityBrushHandles(QER_Entity);
+
+ for(i = 0; i < count; i++)
+ {
+
+ brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetEntityBrushHandle(i);
+
+ if(brush == NULL) {
+ DoMessageBox("GTKRadiant returned a NULL pointer, NOT a good sign", "WARNING!!!", MB_OK);
+ continue;
+ }
+
+ if(brush->pPatch)
+ {
+ if(bLoadPatches)
+ {
+ DPatch* loadPatch = NewPatch();
+ loadPatch->LoadFromBrush_t(brush);
+ }
+ }
+ else
+ {
+ DBrush* loadBrush = NewBrush(i);
+ loadBrush->LoadFromBrush_t(brush, TRUE);
+ }
+ }
+
+ g_FuncTable.m_pfnReleaseEntityBrushHandles();
+
+ return TRUE;
+}
+
+void DEntity::RemoveNonCheckBrushes(list<Str>* exclusionList, bool useDetail)
+{
+ list<DBrush *>::iterator chkBrush=brushList.begin();
+
+ while( chkBrush!=brushList.end() )
+ {
+ if(!useDetail)
+ {
+ if((*chkBrush)->IsDetail())
+ {
+ delete *chkBrush;
+ chkBrush = brushList.erase(chkBrush);
+ continue;
+ }
+ }
+
+ list<Str>::iterator eTexture;
+
+ for( eTexture=exclusionList->begin(); eTexture!=exclusionList->end(); eTexture++ )
+ {
+ if((*chkBrush)->HasTexture((*eTexture).GetBuffer()))
+ {
+ delete *chkBrush;
+ chkBrush = brushList.erase(chkBrush);
+ break;
+ }
+ }
+
+ if( eTexture == exclusionList->end() )
+ chkBrush++;
+ }
+}
+
+void DEntity::ResetChecks(list<Str>* exclusionList)
+{
+ for(list<DBrush *>::const_iterator resetBrush=brushList.begin(); resetBrush!=brushList.end(); resetBrush++)
+ {
+ (*resetBrush)->ResetChecks(exclusionList);
+ }
+}
+
+int DEntity::FixBrushes(bool rebuild)
+{
+ g_FuncTable.m_pfnAllocateActiveBrushHandles();
+
+ int cnt = 0;
+
+ for(list<DBrush *>::const_iterator fixBrush=brushList.begin(); fixBrush!=brushList.end(); fixBrush++)
+ {
+ int count = (*fixBrush)->RemoveRedundantPlanes();
+ if(count)
+ {
+ cnt += count;
+ if(rebuild)
+ {
+ g_FuncTable.m_pfnDeleteBrushHandle((*fixBrush)->QER_brush);
+
+ (*fixBrush)->BuildInRadiant(FALSE, NULL);
+ }
+ }
+ }
+
+ g_FuncTable.m_pfnReleaseActiveBrushHandles();
+
+ return cnt;
+}
+
+void DEntity::BuildInRadiant(bool allowDestruction)
+{
+ bool makeEntity = strcmp(m_Classname, "worldspawn") ? true : false;
+
+ if(makeEntity)
+ {
+ entity_t* pE = (entity_t*)g_FuncTable.m_pfnCreateEntityHandle();
+
+ epair_t* pEpS = GetNextChainItem(NULL, "classname", m_Classname);
+
+ epair_t* pEp = pEpS;
+
+ for(list<DEPair* >::const_iterator buildEPair=epairList.begin(); buildEPair!=epairList.end(); buildEPair++)
+ {
+ pEp = GetNextChainItem(pEp, (*buildEPair)->key, (*buildEPair)->value);
+ }
+
+ g_EntityTable.m_pfnSetEntityKeyValList(pE, pEpS);
+
+ g_FuncTable.m_pfnCommitEntityHandleToMap(pE);
+
+ for(list<DBrush *>::const_iterator buildBrush=brushList.begin(); buildBrush!=brushList.end(); buildBrush++)
+ (*buildBrush)->BuildInRadiant(allowDestruction, NULL, pE);
+
+ for(list<DPatch *>::const_iterator buildPatch=patchList.begin(); buildPatch!=patchList.end(); buildPatch++)
+ (*buildPatch)->BuildInRadiant(pE);
+
+ QER_Entity = pE;
+ }
+ else
+ {
+ for(list<DBrush *>::const_iterator buildBrush=brushList.begin(); buildBrush!=brushList.end(); buildBrush++)
+ (*buildBrush)->BuildInRadiant(allowDestruction, NULL);
+
+ for(list<DPatch *>::const_iterator buildPatch=patchList.begin(); buildPatch!=patchList.end(); buildPatch++)
+ (*buildPatch)->BuildInRadiant();
+ }
+}
+
+
+
+int DEntity::GetIDMax( void ) {
+ int max = -1;
+ for(list<DBrush *>::const_iterator cntBrush=brushList.begin(); cntBrush!=brushList.end(); cntBrush++) {
+ if((*cntBrush)->m_nBrushID > max)
+ max = (*cntBrush)->m_nBrushID;
+ }
+ return max+1;
+}
+
+void DEntity::SetClassname( char *classname ) {
+ m_Classname = classname;
+}
+
+void DEntity::SaveToFile(FILE *pFile)
+{
+ fprintf(pFile, "{\n");
+
+ fprintf(pFile, "\"classname\" \"%s\"\n", (const char *)m_Classname);
+
+ for(list<DEPair *>::const_iterator ep=epairList.begin(); ep!=epairList.end(); ep++)
+ {
+ fprintf(pFile, "\"%s\" \"%s\"\n", (const char *)(*ep)->key, (const char *)(*ep)->value);
+ }
+
+ for(list<DBrush *>::const_iterator bp=brushList.begin(); bp!=brushList.end(); bp++)
+ {
+ (*bp)->SaveToFile(pFile);
+ }
+
+ fprintf(pFile, "}\n");
+}
+
+void DEntity::ClearEPairs()
+{
+ for(list<DEPair *>::const_iterator deadEPair=epairList.begin(); deadEPair!=epairList.end(); deadEPair++)
+ {
+ delete (*deadEPair);
+ }
+ epairList.clear();
+}
+
+void DEntity::AddEPair(char *key, char *value) {
+ DEPair* newEPair;
+ newEPair = FindEPairByKey( key );
+ if(!newEPair) {
+ newEPair = new DEPair;
+ newEPair->Build(key, value);
+ epairList.push_back(newEPair);
+ } else {
+ newEPair->Build(key, value);
+ }
+}
+
+void DEntity::LoadEPairList(epair_t *epl)
+{
+ epair_t* ep = epl;
+ while(ep)
+ {
+ if(!strcmp(ep->key, "classname"))
+ SetClassname(ep->value);
+ else
+ AddEPair(ep->key, ep->value);
+
+ ep = ep->next;
+ }
+}
+
+bool DEntity::ResetTextures(const char* textureName, float fScale[2], float fShift[2], int rotation, const char* newTextureName,
+ int bResetTextureName, int bResetScale[2], int bResetShift[2], int bResetRotation, bool rebuild)
+{
+ g_FuncTable.m_pfnDeselectAllBrushes();
+
+ g_FuncTable.m_pfnAllocateActiveBrushHandles();
+
+ bool reset = FALSE;
+
+ for(list<DBrush *>::const_iterator resetBrush=brushList.begin(); resetBrush!=brushList.end(); resetBrush++)
+ {
+ bool tmp = (*resetBrush)->ResetTextures(textureName, fScale, fShift, rotation, newTextureName,
+ bResetTextureName, bResetScale, bResetShift, bResetRotation);
+
+ if(tmp)
+ {
+ reset = TRUE;
+
+ if(rebuild)
+ {
+ entity_t *pE = (*resetBrush)->QER_brush->owner;
+ g_FuncTable.m_pfnDeleteBrushHandle((*resetBrush)->QER_brush);
+ (*resetBrush)->BuildInRadiant(FALSE, NULL, pE->entityId == 0 ? NULL : pE);
+
+ if( pE->entityId == 0 ? NULL : pE )
+ {
+ }
+ }
+ }
+ }
+
+ if(bResetTextureName)
+ {
+ for(list<DPatch *>::const_iterator resetPatch=patchList.begin(); resetPatch!=patchList.end(); resetPatch++)
+ {
+ bool tmp = (*resetPatch)->ResetTextures(textureName, newTextureName);
+
+ if(tmp)
+ {
+ reset = TRUE;
+
+ if(rebuild)
+ {
+ entity_t *pE = (*resetPatch)->QER_brush->owner;
+ g_FuncTable.m_pfnDeleteBrushHandle((*resetPatch)->QER_brush);
+ (*resetPatch)->BuildInRadiant(pE->entityId == 0 ? NULL : pE);
+ }
+ }
+ }
+ }
+
+ g_FuncTable.m_pfnReleaseActiveBrushHandles();
+
+ return reset;
+}
+
+DEPair* DEntity::FindEPairByKey(const char* keyname)
+{
+ for(list<DEPair *>::const_iterator ep=epairList.begin(); ep!=epairList.end(); ep++)
+ {
+ char* c = (*ep)->key;
+ if(!strcmp(c, keyname))
+ return *ep;
+ }
+ return NULL;
+}
+
+void DEntity::RemoveFromRadiant()
+{
+ g_EntityTable.m_pfnEntity_Free( (entity_t*)QER_Entity );
+
+ QER_Entity = NULL;
+}
+
+void DEntity::SpawnString(const char* key, const char* defaultstring, const char** out)
+{
+ DEPair* pEP = FindEPairByKey(key);
+ if(pEP) {
+ *out = pEP->value;
+ } else {
+ *out = defaultstring;
+ }
+}
+
+void DEntity::SpawnInt(const char* key, const char* defaultstring, int* out)
+{
+ DEPair* pEP = FindEPairByKey(key);
+ if(pEP) {
+ *out = atoi(pEP->value);
+ } else {
+ *out = atoi(defaultstring);
+ }
+}
+
+void DEntity::SpawnFloat(const char* key, const char* defaultstring, float* out)
+{
+ DEPair* pEP = FindEPairByKey(key);
+ if(pEP) {
+ *out = static_cast< float >( atof( pEP->value ) );
+ } else {
+ *out = static_cast< float >( atof(defaultstring) );
+ }
+}
+
+void DEntity::SpawnVector(const char* key, const char* defaultstring, vec_t* out)
+{
+ DEPair* pEP = FindEPairByKey(key);
+ if(pEP) {
+ sscanf(pEP->value, "%f %f %f", &out[0], &out[1], &out[2]);
+ } else {
+ sscanf(defaultstring, "%f %f %f", &out[0], &out[1], &out[2]);
+ }
+}
+
+int DEntity::GetBrushCount( void ) {
+ return brushList.size();
+}
+
+DBrush* DEntity::FindBrushByPointer( brush_t* brush ) {
+ for(list<DBrush *>::const_iterator listBrush = brushList.begin(); listBrush != brushList.end(); listBrush++) {
+ DBrush* pBrush = (*listBrush);
+ if(pBrush->QER_brush == brush) {
+ return pBrush;
+ }
+ }
+ return NULL;
+}
-/*\r
-BobToolz plugin for GtkRadiant\r
-Copyright (C) 2001 Gordon Biggans\r
-\r
-This library is free software; you can redistribute it and/or\r
-modify it under the terms of the GNU Lesser General Public\r
-License as published by the Free Software Foundation; either\r
-version 2.1 of the License, or (at your option) any later version.\r
-\r
-This library is distributed in the hope that it will be useful,\r
-but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
-Lesser General Public License for more details.\r
-\r
-You should have received a copy of the GNU Lesser General Public\r
-License along with this library; if not, write to the Free Software\r
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
-*/\r
-\r
-// DListener.cpp: implementation of the DListener class.\r
-//\r
-//////////////////////////////////////////////////////////////////////\r
-\r
-#include "StdAfx.h"\r
-#include "DListener.h"\r
-\r
-//////////////////////////////////////////////////////////////////////\r
-// Construction/Destruction\r
-//////////////////////////////////////////////////////////////////////\r
-\r
-DListener::DListener()\r
-{\r
- refCount = 1;\r
- m_bHooked = FALSE;\r
-}\r
-\r
-DListener::~DListener()\r
-{\r
- UnRegister();\r
-}\r
-\r
-void DListener::Register()\r
-{\r
- g_MessageTable.m_pfnHookWindow( this );\r
- m_bHooked = TRUE;\r
-}\r
-\r
-void DListener::UnRegister()\r
-{\r
- if(m_bHooked)\r
- {\r
- g_MessageTable.m_pfnUnHookWindow( this );\r
- m_bHooked = FALSE;\r
- }\r
-}\r
-\r
-bool DListener::OnMouseMove(guint32 nFlags, gdouble x, gdouble y)\r
-{\r
- if(!parent->UpdatePath())\r
- delete parent;\r
-\r
- return FALSE;\r
-}\r
-\r
-bool DListener::OnLButtonDown(guint32 nFlags, gdouble x, gdouble y)\r
-{\r
- return FALSE;\r
-}\r
-\r
-bool DListener::OnLButtonUp(guint32 nFlags, gdouble x, gdouble y)\r
-{\r
- return FALSE;\r
-}\r
-\r
-bool DListener::OnRButtonDown(guint32 nFlags, gdouble x, gdouble y)\r
-{\r
- return FALSE;\r
-}\r
-\r
-bool DListener::OnRButtonUp(guint32 nFlags, gdouble x, gdouble y)\r
-{\r
- return FALSE;\r
-}\r
-\r
-bool DListener::OnMButtonDown(guint32 nFlags, gdouble x, gdouble y)\r
-{\r
- return FALSE;\r
-}\r
-\r
-bool DListener::OnMButtonUp(guint32 nFlags, gdouble x, gdouble y)\r
-{\r
- return FALSE;\r
-}\r
+/*
+BobToolz plugin for GtkRadiant
+Copyright (C) 2001 Gordon Biggans
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+// DListener.cpp: implementation of the DListener class.
+//
+//////////////////////////////////////////////////////////////////////
+
+#include "StdAfx.h"
+#include "DListener.h"
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+DListener::DListener()
+{
+ refCount = 1;
+ m_bHooked = FALSE;
+}
+
+DListener::~DListener()
+{
+ UnRegister();
+}
+
+void DListener::Register()
+{
+ g_MessageTable.m_pfnHookWindow( this );
+ m_bHooked = TRUE;
+}
+
+void DListener::UnRegister()
+{
+ if(m_bHooked)
+ {
+ g_MessageTable.m_pfnUnHookWindow( this );
+ m_bHooked = FALSE;
+ }
+}
+
+bool DListener::OnMouseMove(guint32 nFlags, gdouble x, gdouble y)
+{
+ if(!parent->UpdatePath())
+ delete parent;
+
+ return FALSE;
+}
+
+bool DListener::OnLButtonDown(guint32 nFlags, gdouble x, gdouble y)
+{
+ return FALSE;
+}
+
+bool DListener::OnLButtonUp(guint32 nFlags, gdouble x, gdouble y)
+{
+ return FALSE;
+}
+
+bool DListener::OnRButtonDown(guint32 nFlags, gdouble x, gdouble y)
+{
+ return FALSE;
+}
+
+bool DListener::OnRButtonUp(guint32 nFlags, gdouble x, gdouble y)
+{
+ return FALSE;
+}
+
+bool DListener::OnMButtonDown(guint32 nFlags, gdouble x, gdouble y)
+{
+ return FALSE;
+}
+
+bool DListener::OnMButtonUp(guint32 nFlags, gdouble x, gdouble y)
+{
+ return FALSE;
+}
-/*\r
-BobToolz plugin for GtkRadiant\r
-Copyright (C) 2001 Gordon Biggans\r
-\r
-This library is free software; you can redistribute it and/or\r
-modify it under the terms of the GNU Lesser General Public\r
-License as published by the Free Software Foundation; either\r
-version 2.1 of the License, or (at your option) any later version.\r
-\r
-This library is distributed in the hope that it will be useful,\r
-but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
-Lesser General Public License for more details.\r
-\r
-You should have received a copy of the GNU Lesser General Public\r
-License along with this library; if not, write to the Free Software\r
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
-*/\r
-\r
-// DMap.cpp: implementation of the DMap class.\r
-//\r
-//////////////////////////////////////////////////////////////////////\r
-\r
-#include "StdAfx.h"\r
-#include "DMap.h"\r
-\r
-\r
-//////////////////////////////////////////////////////////////////////\r
-// Construction/Destruction\r
-//////////////////////////////////////////////////////////////////////\r
-\r
-DMap::DMap()\r
-{\r
- m_nNextEntity = 1;\r
- AddEntity("worldspawn", 0);\r
-}\r
-\r
-DMap::~DMap()\r
-{\r
- ClearEntities();\r
-}\r
-\r
-DEntity* DMap::AddEntity(char *classname, int ID)\r
-{\r
- DEntity* newEntity;\r
- if(ID == -1)\r
- newEntity = new DEntity(classname, m_nNextEntity++);\r
- else\r
- newEntity = new DEntity(classname, ID);\r
-\r
- entityList.push_back(newEntity);\r
- \r
- return newEntity;\r
-}\r
-\r
-void DMap::ClearEntities()\r
-{\r
- m_nNextEntity = 1;\r
-\r
- for(list<DEntity *>::const_iterator deadEntity=entityList.begin(); deadEntity!=entityList.end(); deadEntity++)\r
- delete *deadEntity;\r
-\r
- entityList.clear();\r
-}\r
-\r
-DEntity* DMap::GetEntityForID(int ID)\r
-{\r
- DEntity* findEntity = NULL;\r
-\r
- for(list<DEntity *>::const_iterator chkEntity=entityList.begin(); chkEntity!=entityList.end(); chkEntity++)\r
- {\r
- if((*chkEntity)->m_nID == ID)\r
- {\r
- findEntity = (*chkEntity);\r
- break;\r
- }\r
- }\r
-\r
- if(!findEntity)\r
- findEntity = AddEntity("worldspawn", ID);\r
-\r
- return findEntity;\r
-}\r
-\r
-\r
-DEntity* DMap::GetWorldSpawn()\r
-{\r
- return GetEntityForID(0);\r
-}\r
-\r
-void DMap::BuildInRadiant(bool bAllowDestruction)\r
-{\r
- for(list<DEntity *>::const_iterator buildEntity=entityList.begin(); buildEntity!=entityList.end(); buildEntity++)\r
- (*buildEntity)->BuildInRadiant(bAllowDestruction);\r
-}\r
-\r
-void DMap::LoadAll(bool bLoadPatches)\r
-{\r
- ClearEntities();\r
-\r
- g_FuncTable.m_pfnDeselectAllBrushes();\r
-\r
- int count = g_FuncTable.m_pfnGetEntityCount();\r
-\r
- for(int i = 0; i < count; i++)\r
- {\r
- DEntity* loadEntity;\r
-\r
- if(i == 0)\r
- loadEntity = GetWorldSpawn();\r
- else\r
- loadEntity = AddEntity("", m_nNextEntity++);\r
-\r
- if(!loadEntity->LoadFromEntity(i, bLoadPatches))\r
- {\r
- delete loadEntity;\r
- entityList.pop_back();\r
- }\r
- }\r
-}\r
-\r
-int DMap::FixBrushes(bool rebuild)\r
-{\r
- int count = 0;\r
- for(list<DEntity *>::const_iterator fixEntity=entityList.begin(); fixEntity!=entityList.end(); fixEntity++)\r
- {\r
- int cnt;\r
-\r
- if(!stricmp("worldspawn", (*fixEntity)->m_Classname))\r
- cnt = (*fixEntity)->FixBrushes(rebuild);\r
- else\r
- {\r
- cnt = (*fixEntity)->FixBrushes(FALSE);\r
- \r
- if(cnt && rebuild)\r
- RebuildEntity(*fixEntity);\r
- }\r
-\r
- count += cnt;\r
- }\r
-\r
- return count;\r
-}\r
-\r
-void DMap::ResetTextures( const char* textureName, float fScale[2], float fShift[2], int rotation, const char* newTextureName, \r
- int bResetTextureName, int bResetScale[2], int bResetShift[2], int bResetRotation)\r
-{\r
- for(list<DEntity *>::const_iterator texEntity=entityList.begin(); texEntity!=entityList.end(); texEntity++)\r
- {\r
- if(!stricmp("worldspawn", (*texEntity)->m_Classname))\r
- (*texEntity)->ResetTextures(textureName, fScale, fShift, rotation, newTextureName, \r
- bResetTextureName, bResetScale, bResetShift, bResetRotation, TRUE);\r
- else\r
- {\r
- if((*texEntity)->ResetTextures( textureName, fScale, fShift, rotation, newTextureName, \r
- bResetTextureName, bResetScale, bResetShift, bResetRotation, FALSE))\r
- RebuildEntity(*texEntity);\r
- }\r
- } \r
-}\r
-\r
-void DMap::RebuildEntity(DEntity *ent)\r
-{\r
- ent->RemoveFromRadiant();\r
- ent->BuildInRadiant(FALSE);\r
-}\r
+/*
+BobToolz plugin for GtkRadiant
+Copyright (C) 2001 Gordon Biggans
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+// DMap.cpp: implementation of the DMap class.
+//
+//////////////////////////////////////////////////////////////////////
+
+#include "StdAfx.h"
+#include "DMap.h"
+
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+DMap::DMap()
+{
+ m_nNextEntity = 1;
+ AddEntity("worldspawn", 0);
+}
+
+DMap::~DMap()
+{
+ ClearEntities();
+}
+
+DEntity* DMap::AddEntity(char *classname, int ID)
+{
+ DEntity* newEntity;
+ if(ID == -1)
+ newEntity = new DEntity(classname, m_nNextEntity++);
+ else
+ newEntity = new DEntity(classname, ID);
+
+ entityList.push_back(newEntity);
+
+ return newEntity;
+}
+
+void DMap::ClearEntities()
+{
+ m_nNextEntity = 1;
+
+ for(list<DEntity *>::const_iterator deadEntity=entityList.begin(); deadEntity!=entityList.end(); deadEntity++)
+ delete *deadEntity;
+
+ entityList.clear();
+}
+
+DEntity* DMap::GetEntityForID(int ID)
+{
+ DEntity* findEntity = NULL;
+
+ for(list<DEntity *>::const_iterator chkEntity=entityList.begin(); chkEntity!=entityList.end(); chkEntity++)
+ {
+ if((*chkEntity)->m_nID == ID)
+ {
+ findEntity = (*chkEntity);
+ break;
+ }
+ }
+
+ if(!findEntity)
+ findEntity = AddEntity("worldspawn", ID);
+
+ return findEntity;
+}
+
+
+DEntity* DMap::GetWorldSpawn()
+{
+ return GetEntityForID(0);
+}
+
+void DMap::BuildInRadiant(bool bAllowDestruction)
+{
+ for(list<DEntity *>::const_iterator buildEntity=entityList.begin(); buildEntity!=entityList.end(); buildEntity++)
+ (*buildEntity)->BuildInRadiant(bAllowDestruction);
+}
+
+void DMap::LoadAll(bool bLoadPatches)
+{
+ ClearEntities();
+
+ g_FuncTable.m_pfnDeselectAllBrushes();
+
+ int count = g_FuncTable.m_pfnGetEntityCount();
+
+ for(int i = 0; i < count; i++)
+ {
+ DEntity* loadEntity;
+
+ if(i == 0)
+ loadEntity = GetWorldSpawn();
+ else
+ loadEntity = AddEntity("", m_nNextEntity++);
+
+ if(!loadEntity->LoadFromEntity(i, bLoadPatches))
+ {
+ delete loadEntity;
+ entityList.pop_back();
+ }
+ }
+}
+
+int DMap::FixBrushes(bool rebuild)
+{
+ int count = 0;
+ for(list<DEntity *>::const_iterator fixEntity=entityList.begin(); fixEntity!=entityList.end(); fixEntity++)
+ {
+ int cnt;
+
+ if(!stricmp("worldspawn", (*fixEntity)->m_Classname))
+ cnt = (*fixEntity)->FixBrushes(rebuild);
+ else
+ {
+ cnt = (*fixEntity)->FixBrushes(FALSE);
+
+ if(cnt && rebuild)
+ RebuildEntity(*fixEntity);
+ }
+
+ count += cnt;
+ }
+
+ return count;
+}
+
+void DMap::ResetTextures( const char* textureName, float fScale[2], float fShift[2], int rotation, const char* newTextureName,
+ int bResetTextureName, int bResetScale[2], int bResetShift[2], int bResetRotation)
+{
+ for(list<DEntity *>::const_iterator texEntity=entityList.begin(); texEntity!=entityList.end(); texEntity++)
+ {
+ if(!stricmp("worldspawn", (*texEntity)->m_Classname))
+ (*texEntity)->ResetTextures(textureName, fScale, fShift, rotation, newTextureName,
+ bResetTextureName, bResetScale, bResetShift, bResetRotation, TRUE);
+ else
+ {
+ if((*texEntity)->ResetTextures( textureName, fScale, fShift, rotation, newTextureName,
+ bResetTextureName, bResetScale, bResetShift, bResetRotation, FALSE))
+ RebuildEntity(*texEntity);
+ }
+ }
+}
+
+void DMap::RebuildEntity(DEntity *ent)
+{
+ ent->RemoveFromRadiant();
+ ent->BuildInRadiant(FALSE);
+}
-/*\r
-BobToolz plugin for GtkRadiant\r
-Copyright (C) 2001 Gordon Biggans\r
-\r
-This library is free software; you can redistribute it and/or\r
-modify it under the terms of the GNU Lesser General Public\r
-License as published by the Free Software Foundation; either\r
-version 2.1 of the License, or (at your option) any later version.\r
-\r
-This library is distributed in the hope that it will be useful,\r
-but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
-Lesser General Public License for more details.\r
-\r
-You should have received a copy of the GNU Lesser General Public\r
-License along with this library; if not, write to the Free Software\r
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
-*/\r
-\r
-// DPatch.cpp: implementation of the DPatch class.\r
-//\r
-//////////////////////////////////////////////////////////////////////\r
-\r
-#include "StdAfx.h"\r
-#include "DPatch.h"\r
-#include "misc.h"\r
-#include "./dialogs/dialogs-gtk.h"\r
-\r
-//////////////////////////////////////////////////////////////////////\r
-// Construction/Destruction\r
-//////////////////////////////////////////////////////////////////////\r
-\r
-// Added patch merging, wahey!\r
-\r
-//\r
-// problem is, you cant put patches into entities as yet :(\r
-//\r
-\r
-DPatch::DPatch()\r
-{\r
- width = MIN_PATCH_WIDTH;\r
- height = MIN_PATCH_HEIGHT;\r
- QER_patch = NULL;\r
- QER_brush = NULL;\r
-}\r
-\r
-DPatch::~DPatch()\r
-{\r
-\r
-}\r
-\r
-void DPatch::SetTexture(const char *textureName)\r
-{\r
- strcpy(texture, textureName);\r
-}\r
-\r
-void CopyDrawVert(const drawVert_t* in, drawVert_t* out)\r
-{\r
- out->lightmap[0] = in->lightmap[0];\r
- out->lightmap[1] = in->lightmap[1];\r
- out->st[0] = in->st[0];\r
- out->st[1] = in->st[1];\r
- VectorCopy(in->normal, out->normal);\r
- VectorCopy(in->xyz, out->xyz);\r
-}\r
-\r
-void DPatch::BuildInRadiant(void* entity)\r
-{\r
- int nIndex = g_FuncTable.m_pfnCreatePatchHandle();\r
- //$ FIXME: m_pfnGetPatchHandle\r
- patchMesh_t* pm = g_FuncTable.m_pfnGetPatchData(nIndex);\r
-\r
- pm->height = height;\r
- pm->width = width;\r
-\r
- for(int x = 0; x < width; x++)\r
- for(int y = 0; y < height; y++)\r
- CopyDrawVert(&points[x][y], &pm->ctrl[x][y]);\r
-\r
- QER_patch = pm;\r
-\r
-/* if(entity)\r
- {\r
-// strcpy(pm->d_texture->name, texture);\r
-\r
- brush_t* brush = (brush_t*)g_FuncTable.m_pfnCreateBrushHandle();\r
- brush->patchBrush = TRUE;\r
- brush->pPatch = pm; \r
-\r
- pm->pSymbiot = brush;\r
- pm->bSelected = false;\r
- pm->bOverlay = false; // bleh, f*cks up, just have to wait for a proper function\r
- pm->bDirty = true; // or get my own patch out....\r
- pm->nListID = -1;\r
-\r
- g_FuncTable.m_pfnCommitBrushHandleToEntity(brush, entity);\r
- }\r
- else*/ // patch to entity just plain dont work atm\r
-\r
- if(entity)\r
- g_FuncTable.m_pfnCommitPatchHandleToEntity(nIndex, pm, texture, entity);\r
- else\r
- g_FuncTable.m_pfnCommitPatchHandleToMap(nIndex, pm, texture);\r
-\r
- QER_brush = pm->pSymbiot;\r
-}\r
-\r
-void DPatch::LoadFromBrush_t(brush_t* brush)\r
-{\r
- QER_brush = brush;\r
- QER_patch = brush->pPatch;\r
-\r
- SetTexture(QER_patch->pShader->getName());\r
-\r
- for(int x = 0; x < QER_patch->width; x++)\r
- for(int y = 0; y < QER_patch->height; y++)\r
- CopyDrawVert(&QER_patch->ctrl[x][y], &points[x][y]);\r
-\r
- width = QER_patch->width;\r
- height = QER_patch->height;\r
-}\r
-\r
-void DPatch::RemoveFromRadiant()\r
-{\r
- if(QER_brush)\r
- g_FuncTable.m_pfnDeleteBrushHandle(QER_brush);\r
-}\r
-\r
-bool DPatch::ResetTextures(const char *oldTextureName, const char *newTextureName)\r
-{\r
- if( !oldTextureName || !strcmp(texture, oldTextureName))\r
- {\r
- strcpy(texture, newTextureName);\r
- return TRUE;\r
- }\r
-\r
- return FALSE;\r
-}\r
-\r
-void Build1dArray(vec3_t* array, drawVert_t points[MAX_PATCH_WIDTH][MAX_PATCH_HEIGHT], \r
- int startX, int startY, int number, bool horizontal, bool inverse)\r
-{\r
- int x = startX, y = startY, i, step;\r
-\r
- if(inverse)\r
- step = -1;\r
- else\r
- step = 1;\r
-\r
- for(i = 0; i < number; i++)\r
- {\r
- VectorCopy(points[x][y].xyz, array[i]);\r
-\r
- if(horizontal)\r
- x+=step;\r
- else\r
- y+=step;\r
- }\r
-}\r
-\r
-void Print1dArray(vec3_t* array, int size)\r
-{\r
- for(int i = 0; i < size; i++)\r
- Sys_Printf("(%.0f %.0f %.0f)\t", array[i][0], array[i][1], array[i][2]);\r
- Sys_Printf("\n");\r
-}\r
-\r
-bool Compare1dArrays(vec3_t* a1, vec3_t* a2, int size)\r
-{\r
- int i;\r
- bool equal = true;\r
-\r
- for(i = 0; i < size; i++)\r
- {\r
- if(!VectorCompare(a1[i], a2[size-i-1]))\r
- {\r
- equal = false;\r
- break;\r
- }\r
- }\r
- return equal;\r
-}\r
-\r
-patch_merge_t DPatch::IsMergable(DPatch *other)\r
-{\r
- int i, j;\r
- vec3_t p1Array[4][MAX_PATCH_HEIGHT];\r
- vec3_t p2Array[4][MAX_PATCH_HEIGHT];\r
-\r
- int p1ArraySizes[4];\r
- int p2ArraySizes[4];\r
-\r
- patch_merge_t merge_info;\r
-\r
- Build1dArray(p1Array[0], this->points, 0, 0, this->width, true, false);\r
- Build1dArray(p1Array[1], this->points, this->width-1, 0, this->height, false, false);\r
- Build1dArray(p1Array[2], this->points, this->width-1, this->height-1, this->width, true, true);\r
- Build1dArray(p1Array[3], this->points, 0, this->height-1, this->height, false, true);\r
-\r
- Build1dArray(p2Array[0], other->points, 0, 0, other->width, true, false);\r
- Build1dArray(p2Array[1], other->points, other->width-1, 0, other->height, false, false);\r
- Build1dArray(p2Array[2], other->points, other->width-1, other->height-1, other->width, true, true);\r
- Build1dArray(p2Array[3], other->points, 0, other->height-1, other->height, false, true);\r
-\r
- p1ArraySizes[0] = this->width;\r
- p1ArraySizes[1] = this->height;\r
- p1ArraySizes[2] = this->width;\r
- p1ArraySizes[3] = this->height;\r
-\r
- p2ArraySizes[0] = other->width;\r
- p2ArraySizes[1] = other->height;\r
- p2ArraySizes[2] = other->width;\r
- p2ArraySizes[3] = other->height;\r
-\r
- for(i = 0; i < 4; i++)\r
- {\r
- for(j = 0; j < 4; j++)\r
- {\r
- if(p1ArraySizes[i] == p2ArraySizes[j])\r
- {\r
- if(Compare1dArrays(p1Array[i], p2Array[j], p1ArraySizes[i]))\r
- {\r
- merge_info.pos1 = i;\r
- merge_info.pos2 = j;\r
- merge_info.mergable = true;\r
- return merge_info;\r
- }\r
- }\r
- }\r
- }\r
- \r
- merge_info.mergable = false;\r
- return merge_info;\r
-}\r
-\r
-DPatch* DPatch::MergePatches(patch_merge_t merge_info, DPatch *p1, DPatch *p2)\r
-{\r
- while(merge_info.pos1 != 2)\r
- {\r
- p1->Transpose();\r
- merge_info.pos1--;\r
- if(merge_info.pos1 < 0)\r
- merge_info.pos1 += 4;\r
- }\r
-\r
- while(merge_info.pos2 != 0)\r
- {\r
- p2->Transpose();\r
- merge_info.pos2--;\r
- if(merge_info.pos2 < 0)\r
- merge_info.pos2 += 3;\r
- }\r
-\r
- int newHeight = p1->height + p2->height - 1;\r
- if(newHeight > MAX_PATCH_HEIGHT)\r
- return NULL;\r
-\r
- DPatch* newPatch = new DPatch();\r
-\r
- newPatch->height = newHeight;\r
- newPatch->width = p1->width;\r
- newPatch->SetTexture(p1->texture);\r
-\r
- int y = 0;\r
- int i;\r
- for(i = 0; i < p1->height; i++, y++)\r
- for(int x = 0; x < p1->width; x++)\r
- memcpy(&newPatch->points[x][y], &p1->points[x][i], sizeof(drawVert_t));\r
-\r
- for(i = 1; i < p2->height; i++, y++)\r
- for(int x = 0; x < p2->width; x++)\r
- memcpy(&newPatch->points[x][y], &p2->points[x][i], sizeof(drawVert_t));\r
-\r
-// newPatch->Invert();\r
-\r
- return newPatch;\r
-}\r
-\r
-void DPatch::Invert()\r
-{\r
- drawVert_t vertTemp;\r
- int i, j;\r
-\r
- for(i = 0 ; i < width ; i++ ) \r
- {\r
- for(j = 0; j < height / 2; j++)\r
- {\r
- memcpy(&vertTemp, &points[i][height - 1- j], sizeof (drawVert_t));\r
- memcpy(&points[i][height - 1 - j], &points[i][j], sizeof(drawVert_t));\r
- memcpy(&points[i][j], &vertTemp, sizeof(drawVert_t));\r
- }\r
- }\r
-}\r
-\r
-void DPatch::Transpose()\r
-{\r
- int i, j, w;\r
- drawVert_t dv;\r
-\r
- if ( width > height ) \r
- {\r
- for ( i = 0 ; i < height ; i++ ) \r
- {\r
- for ( j = i + 1 ; j < width ; j++ ) \r
- {\r
- if ( j < height ) \r
- {\r
- // swap the value\r
- memcpy(&dv, &points[j][i], sizeof(drawVert_t));\r
- memcpy(&points[j][i], &points[i][j], sizeof(drawVert_t));\r
- memcpy(&points[i][j], &dv, sizeof(drawVert_t));\r
- } \r
- else \r
- {\r
- // just copy\r
- memcpy(&points[i][j], &points[j][i], sizeof(drawVert_t));\r
- }\r
- }\r
- }\r
- } \r
- else \r
- {\r
- for ( i = 0 ; i < width ; i++ ) \r
- {\r
- for ( j = i + 1 ; j < height ; j++ ) \r
- {\r
- if ( j < width ) \r
- {\r
- // swap the value\r
- &nbs